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
);
132 if (retval
== PAM_SUCCESS
)
134 retval
=pam_setcred(*pamh
, PAM_ESTABLISH_CRED
);
135 if (retval
!= PAM_SUCCESS
)
137 DPRINTF("pam_setcred failed, result %d", retval
);
143 if (retval
== PAM_SUCCESS
)
145 retval
=pam_acct_mgmt(*pamh
, 0);
146 if (retval
!= PAM_SUCCESS
)
148 DPRINTF("pam_acct_mgmt failed, result %d", retval
);
151 if (retval
== PAM_SUCCESS
)
153 DPRINTF("dopam successful");
158 struct callback_info
{
159 int (*callback_func
)(struct authinfo
*, void *);
163 static int callback_pam(struct authinfo
*a
, void *argptr
)
165 struct callback_info
*ci
=(struct callback_info
*)argptr
;
166 pam_handle_t
*pamh
=NULL
;
175 a
->clearpasswd
=pam_password
;
176 s
=strdup(a
->sysusername
);
185 ** OK, in order to transparently support PAM sessions inside this
186 ** authentication module, what we need to do is to fork(), and let
187 ** the child run in its parent place. Once the child process exits,
188 ** the parent calls pam_end_session, and clears the PAM library.
190 ** This means that upon return from auth_pam(), your process ID
191 ** might've changed!!!
193 ** However, if the authentication fails, we can simply exit, without
194 ** running as a child process.
196 ** Additionally, the PAM library might allocate some resources that
197 ** authenticated clients should not access. Therefore, we fork
198 ** *before* we try to authenticate. If the authentication succeeds,
199 ** the child process will run in the parent's place. The child
200 ** process waits until the parent tells it whether the authentication
201 ** worked. If it worked, the child keeps running. If not, the child
202 ** exits, which the parent waits for.
204 ** The authentication status is communicated to the child process via
207 if (pipe(pipefd
) < 0)
214 if ((p
=fork()) == -1)
225 if (retval
== PAM_SUCCESS
)
226 if (write(pipefd
[1], "", 1) < 0)
227 ; /* ignore gcc warning */
234 while (wait(&waitstat
) != p
)
236 if (read(pipefd
[0], buf
, 1) > 0)
242 rc
=(*ci
->callback_func
)(a
, ci
->callback_arg
);
257 if (retval
== PAM_SUCCESS
)
258 retval
=pam_open_session(pamh
, 0);
260 if (retval
!= PAM_SUCCESS
)
262 if (pam_end(pamh
, retval
) != PAM_SUCCESS
)
263 perror("Unable to release PAM tokens");
265 /* Wait for child to terminate */
267 close(pipefd
[1]); /* Tell the child to shut down */
268 while (wait(&waitstat
) != p
)
273 /* Tell child process to run in authenticated state */
275 write(pipefd
[1], "", 1);
278 /* Wait for child process to finish */
280 while (wait(&waitstat
) != p
)
283 retval
=pam_close_session(pamh
, 0);
284 if (retval
!= PAM_SUCCESS
)
285 perror("pam_close_session");
287 if (pam_end(pamh
, retval
) != PAM_SUCCESS
)
288 perror("Unable to release PAM tokens");
290 if (WIFEXITED(waitstat
))
291 exit(WEXITSTATUS(waitstat
));
297 extern int auth_pam_pre(const char *userid
, const char *service
,
298 int (*callback
)(struct authinfo
*, void *),
301 int auth_pam(const char *service
, const char *type
, char *authdata
,
302 int (*callback_func
)(struct authinfo
*, void *),
305 struct callback_info ci
;
307 if (strcmp(type
, AUTHTYPE_LOGIN
))
309 DPRINTF("authpam only handles authtype=" AUTHTYPE_LOGIN
);
314 if ((pam_username
=strtok(authdata
, "\n")) == 0 ||
315 (pam_password
=strtok(0, "\n")) == 0)
317 DPRINTF("incomplete username or missing password");
324 ci
.callback_func
=callback_func
;
325 ci
.callback_arg
=callback_arg
;
326 return auth_pam_pre(pam_username
, service
, &callback_pam
, &ci
);
329 static void auth_pam_cleanup()
333 static struct authstaticinfo authpam_info
={
343 struct authstaticinfo
*courier_authpam_init()
345 return &authpam_info
;