2 ** Copyright 1998 - 2012 Double Precision, Inc. See COPYING for
3 ** distribution information.
7 #include "courier_auth_config.h"
19 #include "courierauthstaticlist.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>
31 static const char *pam_username
, *pam_password
, *pam_service
;
33 extern void auth_pwd_enumerate( void(*cb_func
)(const char *name
,
42 static int pam_conv(int num_msg
, const struct pam_message
**msg
,
43 struct pam_response
**resp
, void *appdata_ptr
)
46 struct pam_response
*repl
= NULL
;
48 repl
= malloc(sizeof(struct pam_response
) * num_msg
);
49 if (!repl
) return PAM_CONV_ERR
;
51 for (i
=0; i
<num_msg
; i
++)
52 switch (msg
[i
]->msg_style
) {
53 case PAM_PROMPT_ECHO_ON
:
54 repl
[i
].resp_retcode
= PAM_SUCCESS
;
55 repl
[i
].resp
= strdup(pam_username
);
62 case PAM_PROMPT_ECHO_OFF
:
63 repl
[i
].resp_retcode
= PAM_SUCCESS
;
64 repl
[i
].resp
= strdup(pam_password
);
73 if (write(2, msg
[i
]->msg
, strlen(msg
[i
]->msg
)) < 0 ||
74 write(2, "\n", 1) < 0)
75 ; /* ignore gcc warning */
77 repl
[i
].resp_retcode
= PAM_SUCCESS
;
89 static struct pam_conv conv
= {
94 static int dopam(pam_handle_t
**pamh
, int *started
)
98 DPRINTF("pam_service=%s, pam_username=%s",
99 pam_service
? pam_service
: "<null>",
100 pam_username
? pam_username
: "<null>");
104 retval
=pam_start(pam_service
, pam_username
, &conv
, pamh
);
105 if (retval
!= PAM_SUCCESS
)
107 DPRINTF("pam_start failed, result %d [Hint: bad PAM configuration?]", retval
);
112 if (retval
== PAM_SUCCESS
)
114 retval
=pam_set_item(*pamh
, PAM_AUTHTOK
, pam_password
);
115 if (retval
!= PAM_SUCCESS
)
117 DPRINTF("pam_set_item failed, result %d", retval
);
122 if (retval
== PAM_SUCCESS
)
124 retval
=pam_authenticate(*pamh
, 0);
125 if (retval
!= PAM_SUCCESS
)
127 DPRINTF("pam_authenticate failed, result %d", retval
);
134 if (retval
== PAM_SUCCESS
)
136 retval
=pam_setcred(*pamh
, PAM_ESTABLISH_CRED
);
137 if (retval
!= PAM_SUCCESS
)
139 DPRINTF("pam_setcred failed, result %d", retval
);
145 if (retval
== PAM_SUCCESS
)
147 retval
=pam_acct_mgmt(*pamh
, 0);
148 if (retval
!= PAM_SUCCESS
)
150 DPRINTF("pam_acct_mgmt failed, result %d", retval
);
153 if (retval
== PAM_SUCCESS
)
155 DPRINTF("dopam successful");
160 struct callback_info
{
161 int (*callback_func
)(struct authinfo
*, void *);
165 static int callback_pam(struct authinfo
*a
, void *argptr
)
167 struct callback_info
*ci
=(struct callback_info
*)argptr
;
168 pam_handle_t
*pamh
=NULL
;
177 a
->clearpasswd
=pam_password
;
178 s
=strdup(a
->sysusername
);
187 ** OK, in order to transparently support PAM sessions inside this
188 ** authentication module, what we need to do is to fork(), and let
189 ** the child run in its parent place. Once the child process exits,
190 ** the parent calls pam_end_session, and clears the PAM library.
192 ** This means that upon return from auth_pam(), your process ID
193 ** might've changed!!!
195 ** However, if the authentication fails, we can simply exit, without
196 ** running as a child process.
198 ** Additionally, the PAM library might allocate some resources that
199 ** authenticated clients should not access. Therefore, we fork
200 ** *before* we try to authenticate. If the authentication succeeds,
201 ** the child process will run in the parent's place. The child
202 ** process waits until the parent tells it whether the authentication
203 ** worked. If it worked, the child keeps running. If not, the child
204 ** exits, which the parent waits for.
206 ** The authentication status is communicated to the child process via
209 if (pipe(pipefd
) < 0)
216 if ((p
=fork()) == -1)
228 retval
=dopam(&pamh
, &started
);
229 if (retval
== PAM_SUCCESS
)
230 if (write(pipefd
[1], "", 1) < 0)
231 ; /* ignore gcc warning */
235 pam_end(pamh
, retval
);
241 while (wait(&waitstat
) != p
)
243 if (read(pipefd
[0], buf
, 1) > 0)
249 rc
=(*ci
->callback_func
)(a
, ci
->callback_arg
);
259 extern int auth_pam_pre(const char *userid
, const char *service
,
260 int (*callback
)(struct authinfo
*, void *),
263 int auth_pam(const char *service
, const char *type
, char *authdata
,
264 int (*callback_func
)(struct authinfo
*, void *),
267 struct callback_info ci
;
269 if (strcmp(type
, AUTHTYPE_LOGIN
))
271 DPRINTF("authpam only handles authtype=" AUTHTYPE_LOGIN
);
276 if ((pam_username
=strtok(authdata
, "\n")) == 0 ||
277 (pam_password
=strtok(0, "\n")) == 0)
279 DPRINTF("incomplete username or missing password");
286 ci
.callback_func
=callback_func
;
287 ci
.callback_arg
=callback_arg
;
288 return auth_pam_pre(pam_username
, service
, &callback_pam
, &ci
);
291 static void auth_pam_cleanup()
295 static struct authstaticinfo authpam_info
={
305 struct authstaticinfo
*courier_authpam_init()
307 return &authpam_info
;