authpam.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:7k
源码类别:

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. #if HAVE_CONFIG_H
  6. #include "config.h"
  7. #endif
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <signal.h>
  12. #include <errno.h>
  13. #if HAVE_UNISTD_H
  14. #include <unistd.h>
  15. #endif
  16. #include "auth.h"
  17. #include "authmod.h"
  18. #include "authwait.h"
  19. #if HAVE_SECURITY_PAM_APPL_H
  20. #include <security/pam_appl.h>
  21. #endif
  22. #if HAVE_PAM_PAM_APPL_H
  23. #include <Pam/pam_appl.h>
  24. #endif
  25. static const char rcsid[]="$Id: authpam.c,v 1.9 2000/05/30 02:00:23 mrsam Exp $";
  26. static const char *pam_username, *pam_password, *pam_service;
  27. static int pam_conv(int num_msg, const struct pam_message **msg,
  28.                     struct pam_response **resp, void *appdata_ptr)
  29. {
  30. int i = 0;
  31. struct pam_response *repl = NULL;
  32. repl = malloc(sizeof(struct pam_response) * num_msg);
  33. if (!repl) return PAM_CONV_ERR;
  34. for (i=0; i<num_msg; i++)
  35. switch (msg[i]->msg_style) {
  36. case PAM_PROMPT_ECHO_ON:
  37. repl[i].resp_retcode = PAM_SUCCESS;
  38. repl[i].resp = strdup(pam_username);
  39. if (!repl[i].resp)
  40. {
  41. perror("strdup");
  42. authexit(1);
  43. }
  44. break;
  45. case PAM_PROMPT_ECHO_OFF:
  46. repl[i].resp_retcode = PAM_SUCCESS;
  47. repl[i].resp = strdup(pam_password);
  48. if (!repl[i].resp)
  49. {
  50. perror("strdup");
  51. authexit(1);
  52. }
  53. break;
  54. case PAM_TEXT_INFO:
  55. case PAM_ERROR_MSG:
  56. write(2, msg[i]->msg, strlen(msg[i]->msg));
  57. write(2, "n", 1);
  58. repl[i].resp_retcode = PAM_SUCCESS;
  59. repl[i].resp = NULL;
  60. break;
  61. default:
  62. free (repl);
  63. return PAM_CONV_ERR;
  64. }
  65. *resp=repl;
  66. return PAM_SUCCESS;
  67. }
  68. static struct pam_conv conv = {
  69.           pam_conv,
  70.           NULL
  71.       };
  72. static int dopam(pam_handle_t **pamh)
  73. {
  74. int retval;
  75. retval=pam_start(pam_service, pam_username, &conv, pamh);
  76. if (retval == PAM_SUCCESS)
  77. retval=pam_set_item(*pamh, PAM_AUTHTOK, pam_password);
  78. if (retval == PAM_SUCCESS)
  79. retval=pam_authenticate(*pamh, 0);
  80. #if 0
  81. #if HAVE_PAM_SETCRED
  82. if (retval == PAM_SUCCESS)
  83. retval=pam_setcred(*pamh, PAM_ESTABLISH_CRED);
  84. #endif
  85. if (retval == PAM_SUCCESS)
  86. retval=pam_acct_mgmt(*pamh, 0);
  87. #endif
  88. return (retval);
  89. }
  90. struct callback_info {
  91. char *username;
  92. int issession;
  93. void (*callback_func)(struct authinfo *, void *);
  94. void *callback_arg;
  95. } ;
  96. static int callback_pam(struct authinfo *a, void *argptr)
  97. {
  98. struct callback_info *ci=(struct callback_info *)argptr;
  99. pam_handle_t *pamh=NULL;
  100. int pipefd[2];
  101. int retval;
  102. pid_t p;
  103. int waitstat;
  104. char *s;
  105. s=strdup(a->sysusername);
  106. if (!s)
  107. {
  108. perror("malloc");
  109. return (1);
  110. }
  111. if (!ci->issession && /* Thankfully, no session voodoo needed this time */
  112. ci->callback_func == 0)
  113. {
  114. retval=dopam(&pamh);
  115. if (retval == PAM_SUCCESS)
  116. {
  117. if (pam_end(pamh, retval) != PAM_SUCCESS)
  118. perror("Unable to release PAM tokens");
  119. if (ci->callback_func == 0)
  120. authsuccess(a->homedir,
  121. a->sysusername,
  122. 0,
  123. &a->sysgroupid,
  124. a->address,
  125. a->fullname);
  126. ci->username=s;
  127. putenv("MAILDIR=");
  128. return (0);
  129. }
  130. free(s);
  131. if (pam_end(pamh, retval) != PAM_SUCCESS)
  132. perror("Unable to release PAM tokens");
  133. return (-1);
  134. }
  135. /*
  136. ** OK, in order to transparently support PAM sessions inside this
  137. ** authentication module, what we need to do is to fork(), and let
  138. ** the child run in its parent place.  Once the child process exits,
  139. ** the parent calls pam_end_session, and clears the PAM library.
  140. **
  141. ** This means that upon return from auth_pam(), your process ID
  142. ** might've changed!!!
  143. **
  144. ** However, if the authentication fails, we can simply exit, without
  145. ** running as a child process.
  146. **
  147. ** Additionally, the PAM library might allocate some resources that
  148. ** authenticated clients should not access.  Therefore, we fork
  149. ** *before* we try to authenticate.  If the authentication succeeds,
  150. ** the child process will run in the parent's place.  The child
  151. ** process waits until the parent tells it whether the authentication
  152. ** worked.  If it worked, the child keeps running.  If not, the child
  153. ** exits, which the parent waits for.
  154. **
  155. ** The authentication status is communicated to the child process via
  156. ** a pipe.
  157. */
  158. if (pipe(pipefd) < 0)
  159. {
  160. perror("pipe");
  161. free(s);
  162. return (1);
  163. }
  164. if ((p=fork()) == -1)
  165. {
  166. perror("fork");
  167. free(s);
  168. return (1);
  169. }
  170. if (p == 0)
  171. {
  172. char dummy;
  173. if (ci->callback_func) /* PAM memory leak */
  174. {
  175. close(pipefd[0]);
  176. retval=dopam(&pamh);
  177. if (retval == PAM_SUCCESS)
  178. write(pipefd[1], "", 1);
  179. close(pipefd[1]);
  180. _exit(0);
  181. }
  182. close(pipefd[1]);
  183. if (read(pipefd[0], &dummy, 1) != 1 || dummy)
  184. authexit(1); /* Authentication failed by parent */
  185. close(pipefd[0]);
  186. putenv("MAILDIR=");
  187. authsuccess(a->homedir,
  188. a->sysusername,
  189. 0,
  190. &a->sysgroupid,
  191. a->address,
  192. a->fullname);
  193. ci->username=s;
  194. if (ci->callback_func)
  195. {
  196. a->address=s;
  197. (*ci->callback_func)(a, ci->callback_arg);
  198. }
  199. return (0);
  200. }
  201. if (ci->callback_func)
  202. {
  203. char buf[1];
  204. close(pipefd[1]);
  205. while (wait(&waitstat) != p)
  206. ;
  207. if (read(pipefd[0], buf, 1) > 0)
  208. {
  209. close(pipefd[0]);
  210. a->address=s;
  211. ci->username=s;
  212. (*ci->callback_func)(a, ci->callback_arg);
  213. return (0);
  214. }
  215. close(pipefd[0]);
  216. free(s);
  217. return (-1);
  218. }
  219. free(s);
  220. close(pipefd[0]);
  221. retval=dopam(&pamh);
  222. if (retval == PAM_SUCCESS)
  223. retval=pam_open_session(pamh, 0);
  224. if (retval != PAM_SUCCESS)
  225. {
  226. if (pam_end(pamh, retval) != PAM_SUCCESS)
  227. perror("Unable to release PAM tokens");
  228. /* Wait for child to terminate */
  229. close(pipefd[1]); /* Tell the child to shut down */
  230. while (wait(&waitstat) != p)
  231. ;
  232. return (-1);
  233. }
  234. /* Tell child process to run in authenticated state */
  235. write(pipefd[1], "", 1);
  236. close(pipefd[1]);
  237. /* Wait for child process to finish */
  238. while (wait(&waitstat) != p)
  239. ;
  240. retval=pam_close_session(pamh, 0);
  241. if (retval != PAM_SUCCESS)
  242. perror("pam_close_session");
  243. if (pam_end(pamh, retval) != PAM_SUCCESS)
  244. perror("Unable to release PAM tokens");
  245. if (WIFEXITED(waitstat))
  246. authexit(WEXITSTATUS(waitstat));
  247. authexit(255);
  248. return (1);
  249. }
  250. extern int auth_pam_pre(const char *userid, const char *service,
  251.         int (*callback)(struct authinfo *, void *),
  252.                         void *arg);
  253. char *auth_pam(const char *service, const char *type, char *authdata,
  254. int issession,
  255. void (*callback_func)(struct authinfo *, void *), void *callback_arg)
  256. {
  257. struct callback_info ci;
  258. int rc;
  259. if (strcmp(type, AUTHTYPE_LOGIN) ||
  260. (pam_username=strtok(authdata, "n")) == 0 ||
  261. (pam_password=strtok(0, "n")) == 0)
  262. {
  263. errno=EPERM;
  264. return (0);
  265. }
  266. pam_service=service;
  267. ci.issession=issession;
  268. ci.callback_func=callback_func;
  269. ci.callback_arg=callback_arg;
  270.         rc=auth_pam_pre(pam_username, service, &callback_pam, &ci);
  271. if (rc) return (0);
  272. return (ci.username);
  273. }