Build courier-authlib (0.60.2-0hcoop7).
[hcoop/debian/courier-authlib.git] / authuserdbpwd.c
CommitLineData
d9898ee8 1/*
2** Copyright 2001-2005 Double Precision, Inc. See COPYING for
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 <errno.h>
13#include <signal.h>
14#include <pwd.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include "userdb/userdb.h"
19#include "auth.h"
20#include "authstaticlist.h"
21#include "authwait.h"
22#include "sbindir.h"
23#include "courierauthdebug.h"
24#if HAVE_HMACLIB
25#include "libhmac/hmac.h"
26#endif
27
28static const char rcsid[]="$Id: authuserdbpwd.c,v 1.8 2006/10/28 19:22:52 mrsam Exp $";
29
30
31static int bad(const char *q)
32{
33 const char *p;
34
35 for (p=q; *p; p++)
36 if ((int)(unsigned char)*p < ' ' || *p == '|' || *p == '='
37 || *p == '\'' || *p == '"')
38 return (1);
39 return (0);
40}
41
42
43#if HAVE_HMACLIB
44
45static char *hmacpw(const char *pw, const char *hash)
46{
47 int i;
48
49 for (i=0; hmac_list[i] &&
50 strcmp(hmac_list[i]->hh_name, hash); i++)
51 ;
52 if (hmac_list[i])
53 {
54 struct hmac_hashinfo *hmac=hmac_list[i];
55 unsigned char *p=malloc(hmac->hh_L*2);
56 char *q=malloc(hmac->hh_L*4+1);
57 unsigned i;
58
59 if (!p || !q)
60 {
61 perror("malloc");
62 exit(1);
63 }
64
65 hmac_hashkey(hmac, pw, strlen(pw), p, p+hmac->hh_L);
66 for (i=0; i<hmac->hh_L*2; i++)
67 sprintf(q+i*2, "%02x", (int)p[i]);
68 free(p);
69 return (q);
70 }
71 return (NULL);
72}
73#endif
74
75static int dochangepwd1(const char *, const char *, const char *, const char *,
76 const char *);
77
78static int try_auth_userdb_passwd(const char *hmac_flag,
79 const char *service,
80 const char *uid,
81 const char *opwd_buf,
82 const char *npwd_buf);
83static int makeuserdb();
84
85int auth_userdb_passwd(const char *service,
86 const char *uid,
87 const char *opwd_buf,
88 const char *npwd_buf)
89{
90 int rc;
91 int rc2;
92
93 if (bad(uid) || strchr(uid, '/'))
94 {
95 errno=EPERM;
96 DPRINTF("userdb: %s is not a valid userid.\n",
97 uid);
98 return -1;
99 }
100
101 if (bad(service) ||
102 bad(opwd_buf) ||
103 bad(npwd_buf))
104 {
105 errno=EPERM;
106 DPRINTF("userdb: Invalid service or password string for %s.\n",
107 uid);
108 return (1);
109 }
110
111 rc=try_auth_userdb_passwd(NULL, service, uid, opwd_buf, npwd_buf);
112
113 if (rc > 0)
114 return rc;
115
116#if HAVE_HMACLIB
117
118 {
119 int i;
120
121
122 for (i=0; hmac_list[i]; i++)
123 {
124 const char *n=hmac_list[i]->hh_name;
125
126 char *hmacservice=malloc(strlen(service)+strlen(n)
127 +sizeof("-hmac-"));
128
129 if (hmacservice == NULL)
130 return (1);
131
132 strcat(strcat(strcpy(hmacservice, service),
133 "-hmac-"), n);
134
135 rc2=try_auth_userdb_passwd(n, hmacservice, uid,
136 opwd_buf, npwd_buf);
137
138 if (rc2 > 0)
139 {
140 free(hmacservice);
141 return (1);
142 }
143
144 if (rc2 == 0)
145 rc=0;
146
147 strcat(strcpy(hmacservice, "hmac-"), n);
148
149 rc2=try_auth_userdb_passwd(n, hmacservice, uid,
150 opwd_buf, npwd_buf);
151 free(hmacservice);
152 if (rc2 > 0)
153 return (1);
154
155 if (rc2 == 0)
156 rc=0;
157
158 }
159 }
160#endif
161
162 if (rc == 0)
163 {
164 rc=makeuserdb();
165
166 if (rc)
167 {
168 DPRINTF("makeuserdb: error: %s", strerror(errno));
169 }
170 }
171
172 DPRINTF("authuserdb: return code %d", rc);
173 return rc;
174}
175
176static int try_auth_userdb_passwd(const char *hmac_flag,
177 const char *service,
178 const char *uid,
179 const char *opwd_buf,
180 const char *npwd_buf)
181{
182 char *opwd;
183 char *npwd;
184 int rc;
185
186#if HAVE_HMACLIB
187
188 if (hmac_flag)
189 {
190 DPRINTF("Trying to change password for %s",
191 hmac_flag);
192
193 DPWPRINTF("Old password=%s, new password=%s",
194 opwd_buf, npwd_buf);
195
196 opwd=hmacpw(opwd_buf, hmac_flag);
197 if (!opwd)
198 return 1;
199
200 npwd=hmacpw(npwd_buf, hmac_flag);
201
202 if (!npwd)
203 {
204 free(opwd);
205 return (1);
206 }
207 }
208 else
209#endif
210 {
211 DPRINTF("Trying to change system password for %s",
212 service);
213
214 DPWPRINTF("Old password=%s, new password=%s",
215 opwd_buf, npwd_buf);
216
217 opwd=strdup(opwd_buf);
218 if (!opwd)
219 {
220 return (1);
221 }
222
223 npwd=userdb_mkmd5pw(npwd_buf);
224 if (!npwd || !(npwd=strdup(npwd)))
225 {
226 free(opwd);
227 errno=EPERM;
228 return (1);
229 }
230 }
231
232
233 rc=dochangepwd1(service, uid, opwd, npwd, hmac_flag);
234
235 free(opwd);
236 free(npwd);
237 return (rc);
238}
239
240static int dochangepwd2(const char *service, const char *uid,
241 char *u,
242 const struct userdbs *udb, const char *npwd);
243
244static int dochangepwd1(const char *service, const char *uid,
245 const char *opwd, const char *npwd,
246 const char *hmac_flag)
247{
248 char *udbs;
249 char *services;
250 char *passwords;
251 int rc;
252
253 char *u;
254 struct userdbs *udb;
255
256
257 udbs=userdbshadow(USERDB "shadow.dat", uid);
258
259 if (!udbs)
260 {
261 errno=ENOENT;
262 return (-1);
263 }
264
265 if ((services=malloc(strlen(service)+sizeof("pw"))) == 0)
266 {
267 perror("malloc");
268 free(udbs);
269 errno=EPERM;
270 return (1);
271 }
272
273 strcat(strcpy(services, service), "pw");
274
275 DPRINTF("Checking for password called \"%s\"", services);
276
277 passwords=userdb_gets(udbs, services);
278 free(services);
279
280 if (passwords == 0 && hmac_flag == 0)
281 {
282 DPRINTF("Not found, checking for \"systempw\"");
283 passwords=userdb_gets(udbs, "systempw");
284 service="system";
285 }
286
287 if (!passwords || (hmac_flag ? strcmp(opwd, passwords):
288 authcheckpassword(opwd, passwords)))
289 {
290 if (!passwords)
291 {
292 DPRINTF("Password not found.");
293 }
294 else
295 {
296 DPRINTF("Password didn't match.");
297 }
298
299 if (passwords)
300 free(passwords);
301 free(udbs);
302 errno=EPERM;
303 return (-1);
304 }
305 free(passwords);
306 free(udbs);
307
308 userdb_init(USERDB ".dat");
309 if ( (u=userdb(uid)) == 0 ||
310 (udb=userdb_creates(u)) == 0)
311 {
312 if (u)
313 free(u);
314 errno=EPERM;
315 return (1);
316 }
317
318 rc=dochangepwd2(service, uid, u, udb, npwd);
319
320 userdb_frees(udb);
321 free(u);
322 return (rc);
323}
324
325static int dochangepwd2(const char *services, const char *uid,
326 char *u,
327 const struct userdbs *udb, const char *npwd)
328{
329 char *argv[10];
330 pid_t p, p2;
331 int waitstat;
332
333 argv[0]=SBINDIR "/userdb";
334 argv[1]=malloc(strlen(udb->udb_source ? udb->udb_source:"")
335 +strlen(uid)+1);
336
337 if (!argv[1])
338 {
339 errno=EPERM;
340 return (1);
341 }
342 strcpy(argv[1],udb->udb_source ? udb->udb_source:"");
343 strcat(argv[1],uid);
344 argv[2]="set";
345
346 argv[3]=malloc(strlen(services)+strlen(npwd)+10);
347 if (!argv[3])
348 {
349 free(argv[1]);
350 errno=EPERM;
351 return (1);
352 }
353
354 sprintf(argv[3], "%spw=%s", services, npwd);
355 signal(SIGCHLD, SIG_DFL);
356 argv[4]=0;
357
358 DPRINTF("Executing %s %s %s %s%s",
359 argv[0],
360 argv[1],
361 argv[2],
362 courier_authdebug_login_level >= 2 ? argv[3]:services,
363 courier_authdebug_login_level >= 2 ? "":"pw=******");
364
365 p=fork();
366
367 if (p < 0)
368 {
369 free(argv[3]);
370 free(argv[1]);
371 errno=EPERM;
372 return (1);
373 }
374
375 if (p == 0)
376 {
377 execv(argv[0], argv);
378 perror(argv[0]);
379 exit(1);
380 }
381
382 free(argv[1]);
383 free(argv[3]);
384
385 while ((p2=wait(&waitstat)) != p)
386 {
387 if (p2 < 0 && errno == ECHILD)
388 {
389 perror("wait");
390 errno=EPERM;
391 return (1);
392 }
393 }
394
395 if (!WIFEXITED(waitstat) || WEXITSTATUS(waitstat))
396 {
397 DPRINTF("Command failed: with exit code %d",
398 (int)WEXITSTATUS(waitstat));
399 errno=EPERM;
400 return (1);
401 }
402 DPRINTF("Command succeeded: with exit code %d",
403 (int)WEXITSTATUS(waitstat));
404 return 0;
405}
406
407static int makeuserdb()
408{
409 char *argv[2];
410 pid_t p, p2;
411 int waitstat;
412
413 DPRINTF("Executing makeuserdb");
414 p=fork();
415
416 if (p < 0)
417 {
418 perror("fork");
419 return (1);
420 }
421
422 if (p == 0)
423 {
424 argv[0]= SBINDIR "/makeuserdb";
425 argv[1]=0;
426
427 execv(argv[0], argv);
428 perror(argv[0]);
429 exit(1);
430 }
431
432 while ((p2=wait(&waitstat)) != p)
433 {
434 if (p2 < 0 && errno == ECHILD)
435 {
436 errno=EPERM;
437 return (1);
438 }
439 }
440
441 if (!WIFEXITED(waitstat) || WEXITSTATUS(waitstat))
442 {
443 errno=EPERM;
444 return (1);
445 }
446 return (0);
447}