openafs: Improved calling of get-token script
[hcoop/debian/courier-authlib.git] / authpam.c
CommitLineData
d9898ee8 1/*
b0322a85 2** Copyright 1998 - 2012 Double Precision, Inc. See COPYING for
d9898ee8 3** distribution information.
4*/
5
6#if HAVE_CONFIG_H
7#include "courier_auth_config.h"
8#endif
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <signal.h>
13#include <errno.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include "auth.h"
18#include "authwait.h"
b0322a85 19#include "courierauthstaticlist.h"
d9898ee8 20#include "courierauthdebug.h"
21
22#if HAVE_SECURITY_PAM_APPL_H
23#include <security/pam_appl.h>
24#endif
25
26#if HAVE_PAM_PAM_APPL_H
27#include <Pam/pam_appl.h>
28#endif
29
d9898ee8 30
31static const char *pam_username, *pam_password, *pam_service;
32
33extern void auth_pwd_enumerate( void(*cb_func)(const char *name,
34 uid_t uid,
35 gid_t gid,
36 const char *homedir,
37 const char *maildir,
38 const char *options,
39 void *void_arg),
40 void *void_arg);
41
42static int pam_conv(int num_msg, const struct pam_message **msg,
43 struct pam_response **resp, void *appdata_ptr)
44{
45int i = 0;
46struct pam_response *repl = NULL;
47
48 repl = malloc(sizeof(struct pam_response) * num_msg);
49 if (!repl) return PAM_CONV_ERR;
50
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);
56 if (!repl[i].resp)
57 {
58 perror("strdup");
59 exit(1);
60 }
61 break;
62 case PAM_PROMPT_ECHO_OFF:
63 repl[i].resp_retcode = PAM_SUCCESS;
64 repl[i].resp = strdup(pam_password);
65 if (!repl[i].resp)
66 {
67 perror("strdup");
68 exit(1);
69 }
70 break;
71 case PAM_TEXT_INFO:
72 case PAM_ERROR_MSG:
73 if (write(2, msg[i]->msg, strlen(msg[i]->msg)) < 0 ||
74 write(2, "\n", 1) < 0)
75 ; /* ignore gcc warning */
76
77 repl[i].resp_retcode = PAM_SUCCESS;
78 repl[i].resp = NULL;
79 break;
80 default:
81 free (repl);
82 return PAM_CONV_ERR;
83 }
84
85 *resp=repl;
86 return PAM_SUCCESS;
87}
88
89static struct pam_conv conv = {
90 pam_conv,
91 NULL
92 };
93
b0322a85 94static int dopam(pam_handle_t **pamh, int *started)
d9898ee8 95{
b0322a85 96 int retval;
d9898ee8 97
98 DPRINTF("pam_service=%s, pam_username=%s",
99 pam_service ? pam_service : "<null>",
100 pam_username ? pam_username : "<null>");
101
b0322a85
CE
102 *started=1;
103
d9898ee8 104 retval=pam_start(pam_service, pam_username, &conv, pamh);
105 if (retval != PAM_SUCCESS)
106 {
107 DPRINTF("pam_start failed, result %d [Hint: bad PAM configuration?]", retval);
b0322a85 108 *started=0;
d9898ee8 109 }
110
111#if 0
112 if (retval == PAM_SUCCESS)
113 {
114 retval=pam_set_item(*pamh, PAM_AUTHTOK, pam_password);
115 if (retval != PAM_SUCCESS)
116 {
117 DPRINTF("pam_set_item failed, result %d", retval);
118 }
119 }
120#endif
121
122 if (retval == PAM_SUCCESS)
123 {
124 retval=pam_authenticate(*pamh, 0);
125 if (retval != PAM_SUCCESS)
126 {
127 DPRINTF("pam_authenticate failed, result %d", retval);
128 }
129 }
130
d9898ee8 131
132#if HAVE_PAM_SETCRED
d68dad8a 133 fprintf(stderr, "pam_setcred...\n");
d9898ee8 134 if (retval == PAM_SUCCESS)
135 {
136 retval=pam_setcred(*pamh, PAM_ESTABLISH_CRED);
137 if (retval != PAM_SUCCESS)
138 {
d68dad8a 139 fprintf(stderr, "pam_setcred failed, result %d\n", retval);
d9898ee8 140 }
d68dad8a 141 fprintf(stderr, "pam_setcred done\n");
d9898ee8 142 }
143#endif
d68dad8a 144
d9898ee8 145
146 if (retval == PAM_SUCCESS)
147 {
148 retval=pam_acct_mgmt(*pamh, 0);
149 if (retval != PAM_SUCCESS)
150 {
151 DPRINTF("pam_acct_mgmt failed, result %d", retval);
152 }
153 }
154 if (retval == PAM_SUCCESS)
155 {
156 DPRINTF("dopam successful");
157 }
158 return (retval);
159}
160
161struct callback_info {
162 int (*callback_func)(struct authinfo *, void *);
163 void *callback_arg;
164 } ;
165
166static int callback_pam(struct authinfo *a, void *argptr)
167{
168struct callback_info *ci=(struct callback_info *)argptr;
169pam_handle_t *pamh=NULL;
170int pipefd[2];
171int retval;
172pid_t p;
173int waitstat;
174char *s;
175char buf[1];
176
177
178 a->clearpasswd=pam_password;
179 s=strdup(a->sysusername);
180 if (!s)
181 {
182 perror("malloc");
183 return (1);
184 }
185
186
187/*
188** OK, in order to transparently support PAM sessions inside this
189** authentication module, what we need to do is to fork(), and let
190** the child run in its parent place. Once the child process exits,
191** the parent calls pam_end_session, and clears the PAM library.
192**
193** This means that upon return from auth_pam(), your process ID
194** might've changed!!!
195**
196** However, if the authentication fails, we can simply exit, without
197** running as a child process.
198**
199** Additionally, the PAM library might allocate some resources that
200** authenticated clients should not access. Therefore, we fork
201** *before* we try to authenticate. If the authentication succeeds,
202** the child process will run in the parent's place. The child
203** process waits until the parent tells it whether the authentication
204** worked. If it worked, the child keeps running. If not, the child
205** exits, which the parent waits for.
206**
207** The authentication status is communicated to the child process via
208** a pipe.
209*/
210 if (pipe(pipefd) < 0)
211 {
212 perror("pipe");
213 free(s);
214 return (1);
215 }
216
217 if ((p=fork()) == -1)
218 {
219 perror("fork");
220 free(s);
221 return (1);
222 }
223
224 if (p == 0)
225 {
b0322a85
CE
226 int started;
227
d9898ee8 228 close(pipefd[0]);
b0322a85 229 retval=dopam(&pamh, &started);
d9898ee8 230 if (retval == PAM_SUCCESS)
231 if (write(pipefd[1], "", 1) < 0)
232 ; /* ignore gcc warning */
233 close(pipefd[1]);
b0322a85
CE
234
235 if (started)
236 pam_end(pamh, retval);
d9898ee8 237 _exit(0);
238 }
239
240
241 close(pipefd[1]);
242 while (wait(&waitstat) != p)
243 ;
244 if (read(pipefd[0], buf, 1) > 0)
245 {
246 int rc;
247
248 close(pipefd[0]);
249 a->address=s;
250 rc=(*ci->callback_func)(a, ci->callback_arg);
251 free(s);
252 return rc;
253 }
254 close(pipefd[0]);
255 free(s);
256 errno=EPERM;
257 return (-1);
d9898ee8 258}
259
260extern int auth_pam_pre(const char *userid, const char *service,
261 int (*callback)(struct authinfo *, void *),
262 void *arg);
263
264int auth_pam(const char *service, const char *type, char *authdata,
265 int (*callback_func)(struct authinfo *, void *),
266 void *callback_arg)
267{
268 struct callback_info ci;
269
270 if (strcmp(type, AUTHTYPE_LOGIN))
271 {
272 DPRINTF("authpam only handles authtype=" AUTHTYPE_LOGIN);
273 errno=EPERM;
274 return (-1);
275 }
276
277 if ((pam_username=strtok(authdata, "\n")) == 0 ||
278 (pam_password=strtok(0, "\n")) == 0)
279 {
280 DPRINTF("incomplete username or missing password");
281 errno=EPERM;
282 return (-1);
283 }
284
285 pam_service=service;
286
287 ci.callback_func=callback_func;
288 ci.callback_arg=callback_arg;
289 return auth_pam_pre(pam_username, service, &callback_pam, &ci);
290}
291
292static void auth_pam_cleanup()
293{
294}
295
296static struct authstaticinfo authpam_info={
297 "authpam",
298 auth_pam,
299 auth_pam_pre,
300 auth_pam_cleanup,
301 auth_syspasswd,
302 auth_pam_cleanup,
303 auth_pwd_enumerate};
304
305
306struct authstaticinfo *courier_authpam_init()
307{
308 return &authpam_info;
309}