2 ** Copyright 1998 - 2006 Double Precision, Inc. See COPYING for
3 ** distribution information.
7 #include "courier_auth_config.h"
19 #include "authstaticlist.h"
20 #include "courierauthdebug.h"
22 #if HAVE_SECURITY_PAM_APPL_H
23 #include <security/pam_appl.h>
26 #if HAVE_PAM_PAM_APPL_H
27 #include <Pam/pam_appl.h>
30 static const char rcsid
[]="$Id: authpam.c,v 1.24 2006/10/28 19:22:52 mrsam Exp $";
32 static const char *pam_username
, *pam_password
, *pam_service
;
34 extern void auth_pwd_enumerate( void(*cb_func
)(const char *name
,
43 static int pam_conv(int num_msg
, const struct pam_message
**msg
,
44 struct pam_response
**resp
, void *appdata_ptr
)
47 struct pam_response
*repl
= NULL
;
49 repl
= malloc(sizeof(struct pam_response
) * num_msg
);
50 if (!repl
) return PAM_CONV_ERR
;
52 for (i
=0; i
<num_msg
; i
++)
53 switch (msg
[i
]->msg_style
) {
54 case PAM_PROMPT_ECHO_ON
:
55 repl
[i
].resp_retcode
= PAM_SUCCESS
;
56 repl
[i
].resp
= strdup(pam_username
);
63 case PAM_PROMPT_ECHO_OFF
:
64 repl
[i
].resp_retcode
= PAM_SUCCESS
;
65 repl
[i
].resp
= strdup(pam_password
);
74 if (write(2, msg
[i
]->msg
, strlen(msg
[i
]->msg
)) < 0 ||
75 write(2, "\n", 1) < 0)
76 ; /* ignore gcc warning */
78 repl
[i
].resp_retcode
= PAM_SUCCESS
;
90 static struct pam_conv conv
= {
95 static int dopam(pam_handle_t
**pamh
)
99 DPRINTF("pam_service=%s, pam_username=%s",
100 pam_service
? pam_service
: "<null>",
101 pam_username
? pam_username
: "<null>");
103 retval
=pam_start(pam_service
, pam_username
, &conv
, pamh
);
104 if (retval
!= PAM_SUCCESS
)
106 DPRINTF("pam_start failed, result %d [Hint: bad PAM configuration?]", retval
);
110 if (retval
== PAM_SUCCESS
)
112 retval
=pam_set_item(*pamh
, PAM_AUTHTOK
, pam_password
);
113 if (retval
!= PAM_SUCCESS
)
115 DPRINTF("pam_set_item failed, result %d", retval
);
120 if (retval
== PAM_SUCCESS
)
122 retval
=pam_authenticate(*pamh
, 0);
123 if (retval
!= PAM_SUCCESS
)
125 DPRINTF("pam_authenticate failed, result %d", retval
);
131 fprintf(stderr
, "pam_setcred...\n");
132 if (retval
== PAM_SUCCESS
)
134 retval
=pam_setcred(*pamh
, PAM_ESTABLISH_CRED
);
135 if (retval
!= PAM_SUCCESS
)
137 fprintf(stderr
, "pam_setcred failed, result %d\n", retval
);
139 fprintf(stderr
, "pam_setcred done\n");
144 if (retval
== PAM_SUCCESS
)
146 retval
=pam_acct_mgmt(*pamh
, 0);
147 if (retval
!= PAM_SUCCESS
)
149 DPRINTF("pam_acct_mgmt failed, result %d", retval
);
152 if (retval
== PAM_SUCCESS
)
154 DPRINTF("dopam successful");
159 struct callback_info
{
160 int (*callback_func
)(struct authinfo
*, void *);
164 static int callback_pam(struct authinfo
*a
, void *argptr
)
166 struct callback_info
*ci
=(struct callback_info
*)argptr
;
167 pam_handle_t
*pamh
=NULL
;
176 a
->clearpasswd
=pam_password
;
177 s
=strdup(a
->sysusername
);
186 ** OK, in order to transparently support PAM sessions inside this
187 ** authentication module, what we need to do is to fork(), and let
188 ** the child run in its parent place. Once the child process exits,
189 ** the parent calls pam_end_session, and clears the PAM library.
191 ** This means that upon return from auth_pam(), your process ID
192 ** might've changed!!!
194 ** However, if the authentication fails, we can simply exit, without
195 ** running as a child process.
197 ** Additionally, the PAM library might allocate some resources that
198 ** authenticated clients should not access. Therefore, we fork
199 ** *before* we try to authenticate. If the authentication succeeds,
200 ** the child process will run in the parent's place. The child
201 ** process waits until the parent tells it whether the authentication
202 ** worked. If it worked, the child keeps running. If not, the child
203 ** exits, which the parent waits for.
205 ** The authentication status is communicated to the child process via
208 if (pipe(pipefd
) < 0)
215 if ((p
=fork()) == -1)
226 if (retval
== PAM_SUCCESS
)
227 if (write(pipefd
[1], "", 1) < 0)
228 ; /* ignore gcc warning */
235 while (wait(&waitstat
) != p
)
237 if (read(pipefd
[0], buf
, 1) > 0)
243 rc
=(*ci
->callback_func
)(a
, ci
->callback_arg
);
258 if (retval
== PAM_SUCCESS
)
259 retval
=pam_open_session(pamh
, 0);
261 if (retval
!= PAM_SUCCESS
)
263 if (pam_end(pamh
, retval
) != PAM_SUCCESS
)
264 perror("Unable to release PAM tokens");
266 /* Wait for child to terminate */
268 close(pipefd
[1]); /* Tell the child to shut down */
269 while (wait(&waitstat
) != p
)
274 /* Tell child process to run in authenticated state */
276 write(pipefd
[1], "", 1);
279 /* Wait for child process to finish */
281 while (wait(&waitstat
) != p
)
284 retval
=pam_close_session(pamh
, 0);
285 if (retval
!= PAM_SUCCESS
)
286 perror("pam_close_session");
288 if (pam_end(pamh
, retval
) != PAM_SUCCESS
)
289 perror("Unable to release PAM tokens");
291 if (WIFEXITED(waitstat
))
292 exit(WEXITSTATUS(waitstat
));
298 extern int auth_pam_pre(const char *userid
, const char *service
,
299 int (*callback
)(struct authinfo
*, void *),
302 int auth_pam(const char *service
, const char *type
, char *authdata
,
303 int (*callback_func
)(struct authinfo
*, void *),
306 struct callback_info ci
;
308 if (strcmp(type
, AUTHTYPE_LOGIN
))
310 DPRINTF("authpam only handles authtype=" AUTHTYPE_LOGIN
);
315 if ((pam_username
=strtok(authdata
, "\n")) == 0 ||
316 (pam_password
=strtok(0, "\n")) == 0)
318 DPRINTF("incomplete username or missing password");
325 ci
.callback_func
=callback_func
;
326 ci
.callback_arg
=callback_arg
;
327 return auth_pam_pre(pam_username
, service
, &callback_pam
, &ci
);
330 static void auth_pam_cleanup()
334 static struct authstaticinfo authpam_info
={
344 struct authstaticinfo
*courier_authpam_init()
346 return &authpam_info
;