最近在网上找了不少关于pam的资料,虽然很多,但是都只是动态交互进行验证。因为工作需要,需要进行静态的验证,于是写了如下代码。以下在Mac os X上验证通过。如果把#include <pam/pam_appl.h>,#include <pam/pam_misc.h>,改成#include <security/pam_appl.h>,#include <security/pam_misc.h>应该直接可以在Linux,和Unix等支持Posix标准的环境下运行。
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <grp.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <pam/pam_appl.h>
#include <pam/pam_misc.h>
//#include <pam/pam_misc.h>
int su_conv(int num_msg, const struct pam_message **msgm, //回调函数,非常重要!!!!
struct pam_response **response,void *appdata_ptr);
//static struct pam_conv conv = {misc_conv,NULL};
int main (int argc, const char * argv[])
{
// insert code here...
pam_handle_t *pamh;
const char* mytty,*p;
char *password = "718412";
char *user = "root";
struct pam_conv conv = {su_conv, password};
//其中password就是直接传递给su_conv回调函数void *appdata_ptr 指针
int retval = 100;
printf("uid: %d\n", getuid());
retval = pam_start("su","root",&conv,&pamh);
if(retval = PAM_SUCCESS)
//pam_get_item(pamh,PAM_USER,(const void **)&p);
pam_set_item(pamh,PAM_CONV, getlogin());
mytty = ttyname(STDERR_FILENO);
if (!mytty)
mytty = "tty";
pam_set_item(pamh,PAM_TTY, mytty);
retval = pam_authenticate(pamh,PAM_SILENT);
printf("return code: %d\n", retval);
if(retval != PAM_SUCCESS)
{
printf("invalid password\n");
return -1;
}
retval = pam_end(pamh,PAM_SUCCESS);
printf("uid: %d\n", getuid());
setuid(0);
printf("uid: %d\n", getuid());
printf("the retval is now %d",retval);
return 0;
}
int su_conv(int num_msg, const struct pam_message **msgm,
struct pam_response **response, void *appdata_ptr)
{
char *rec;
struct pam_message *m = (struct pam_message *)*msgm;
struct pam_response *r;
while(num_msg--)
{
switch(m->msg_style)
{
case PAM_PROMPT_ECHO_OFF:
// r->resp = strdup(getpass(m->msg));
r = (struct pam_response *)malloc(sizeof(struct pam_response));
r->resp = (char *)malloc(100);
r->resp_retcode = 0;
strcpy(r->resp, appdata_ptr);
*response = r;
break;
case PAM_PROMPT_ECHO_ON:
//r->resp = (char *)getpass(m->msg);
//fprintf(stdout,"%s",m->msg);
r->resp = malloc(PAM_MAX_RESP_SIZE);
fgets(r->resp,PAM_MAX_RESP_SIZE,stdin);
//gets(rec);
break;
case PAM_ERROR_MSG:
(void)fputs(m->msg,stdout);
break;
case PAM_TEXT_INFO:
fprintf(stdout,"%s\n",m->msg);
break;
default:
break;
}
}
return PAM_SUCCESS;
}