pam_radius_auth.c memory leaks?
Cesare Placanica
ugengia-reg at yahoo.it
Thu Oct 1 16:01:34 CEST 2009
Hi,
I've written a little test application for pam_radius_auth.
Although in the following article:
http://developers.sun.com/solaris/articles/user_auth_solaris3.html
is written that *pam service modules are in charge of freeing pam_response messages*, I suspect that this is not happening.
Here is my test application and the memory debug using libumem:
gerace:1> ldd check_user
libpam.so.1 => /usr/dt/lib/libpam.so.1
libumem.so.1 => /lib/libumem.so.1
libc.so.1 => /lib/libc.so.1
libcmd.so.1 => /lib/libcmd.so.1
libm.so.2 => /lib/libm.so.2
/platform/SUNW,A70/lib/libc_psr.so.1
gerace:2> uname -a
SunOS gerace 5.10 Generic_118833-03 sun4u sparc SUNW,A70
gerace:3>
gerace:3> cat check_user.c
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include "dprint.h"
/* pam conversation function */
extern int check_conv(int num_msg, struct pam_message **msg, struct pam_response **resp, void *app_data);
int main(int argc, char *argv[])
{
struct pam_conv conv = { check_conv, NULL };
pam_handle_t *ph;
int error;
if (argc == 1)
{
printf("pam_radius_auth testing utility\n\n");
printf("Usage: %s user [trace_flag (0|1)]\n", argv[0]);
exit(0);
}
if (argc == 3)
{
if (0 == strncmp(argv[2], "1", 2))
{
trace_flag = 1;
}
}
if ((error = pam_start("ctms", argv[1], &conv, &ph)) != PAM_SUCCESS)
{
fprintf(stderr, "Call to pam_start failed: %s\n", pam_strerror(ph, error));
exit(1);
}
for (;;)
{
error = pam_authenticate(ph, 0);
if (error == PAM_SUCCESS)
{
printf("Password match.\n");
break;
}
else
{
if (error == PAM_AUTHINFO_UNAVAIL)
{
printf("Server down\n");
break;
}
else
{
printf("Password don't match.\n");
}
}
}
pam_end(ph, 0);
return (0);
}
gerace:4>
gerace:4> cat check_user_conv.c
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include "dprint.h"
int check_conv(int num_msg, struct pam_message **msg, struct pam_response **resp, void *app_data)
{
struct pam_message *m = *msg;
struct pam_response *r;
int i;
char *ct_passwd = NULL;
char *ct_pin = NULL;
DPRINT("DEBUG: entering conversation function\n");
if ((num_msg <= 0) || (num_msg >= PAM_MAX_NUM_MSG))
{
fprintf(stderr, "Invalid number of messages\n");
*resp = NULL;
return (PAM_CONV_ERR);
}
if ((*resp = r = calloc(num_msg, sizeof(struct pam_response))) == NULL)
return (PAM_BUF_ERR);
for (i = 0; i < num_msg; i++)
{
switch (m->msg_style)
{
case PAM_PROMPT_ECHO_OFF:
if (m->msg)
{
DPRINT("DEBUG: PAM_PROMPT_ECHO_OFF server says %s\n", m->msg);
}
else
{
DPRINT("DEBUG: PAM_PROMPT_ECHO_OFF\n");
}
ct_passwd = getpassphrase("Enter password: ");
r->resp = strdup(ct_passwd);
m++;
r++;
break;
case PAM_PROMPT_ECHO_ON:
DPRINT("DEBUG: PAM_PROMPT_ECHO_ON\n");
if (m->msg)
{
ct_pin = getpassphrase(m->msg);
r->resp = strdup(ct_pin);
}
else
{
r->resp = NULL;
}
m++;
r++;
break;
case PAM_ERROR_MSG:
DPRINT("DEBUG: PAM_ERROR_MSG\n");
if (m->msg)
fprintf(stderr, "%s\n", m->msg);
m++;
r++;
break;
case PAM_TEXT_INFO:
DPRINT("DEBUG: PAM_TEXT_INFO\n");
if (m->msg)
printf("%s\n", m->msg);
m++;
r++;
break;
}
}
return (PAM_SUCCESS);
}
gerace:6>
gerace:6>
gerace:6> setenv LD_PRELOAD libumem.so.1
gerace:7> setenv UMEM_DEBUG default
gerace:8> sudo mdb ./check_user
> ::sysbp _exit
> ::run SuperUser
Enter password:
Password match.
mdb: stop on entry to _exit
mdb: target stopped at:
libc.so.1`exit+0x14: ta 8
mdb: You've got symbols!
Loading modules: [ ld.so.1 libumem.so.1 libc.so.1 ]
> ::load libumem
> ::findleaks
CACHE LEAKED BUFCTL CALLER
00033b88 1 0003d518 libc.so.1`_nss_XbyY_buf_alloc+8
0002d188 1 00072000 libpam.so.1`run_stack+0xc8
----------------------------------------------------------------------
Total 2 buffers, 1216 bytes
>
> 0003d518::bufctl_audit
ADDR BUFADDR TIMESTAMP THREAD
CACHE LASTLOG CONTENTS
3d518 41480 13e5187aea2a 1
33b88 0 0
libumem.so.1`umem_cache_alloc+0x210
libumem.so.1`umem_alloc+0x60
libumem.so.1`malloc+0x28
libc.so.1`_nss_XbyY_buf_alloc+8
0xff1aa688
0xff1a6af4
0xff1a6750
0xff1a2e88
0xff1d0ce8
libpam.so.1`run_stack+0xc8
libpam.so.1`pam_authenticate+0x30
main+0x13c
_start+0x5c
> 00072000::bufctl_audit
ADDR BUFADDR TIMESTAMP THREAD
CACHE LASTLOG CONTENTS
72000 75f80 13e5187ace6e 1
2d188 0 0
libumem.so.1`umem_cache_alloc+0x210
libumem.so.1`umem_alloc+0x60
libumem.so.1`malloc+0x28
libumem.so.1`calloc+0x58
0xff1a6acc
0xff1a6750
0xff1a2e88
0xff1d0ce8
libpam.so.1`run_stack+0xc8
libpam.so.1`pam_authenticate+0x30
main+0x13c
_start+0x5c
> ::quit
I suspect that the first leak is due the strdup function in the conversation function (check_conv), because memory allocation is in libc.
The second leak is the calloc in check_conv function.
There is a guideline to handle this memory issues for pam_response messages?
Regards,
Cesare
More information about the Freeradius-Users
mailing list