/ [pam-modules] / trunk / pam_ldaphome / pam_ldaphome.c
To checkout: svn checkout http://svn.gnu.org.ua/sources/pam-modules/trunk/pam_ldaphome/pam_ldaphome.c
Puszcza

Contents of /trunk/pam_ldaphome/pam_ldaphome.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 118 - (show annotations)
Sun May 13 09:48:57 2012 UTC (9 years, 5 months ago) by gray
File MIME type: text/plain
File size: 17988 byte(s)
Revamp build system. Add pam_ldaphome module.

* configure.ac: Test for ldap.
(AC_OUTPUT): Create pam_ldaphome/Makefile.
* acinclude.m4 (PM_ENABLE): Declare PAM_COND_<item>
conditional in addition to BUILD_PAM_<item> substitution
variable.
* Makefile.am (SUBDIRS): Include most modules via
conditionally defined Makefile variables.

* lib/graypam.h (gray_env): New struct.
(gray_env_get,gray_env_free,gray_env_read)
(gray_boolean_true_p): New protos.
* lib/env.c: New file.
* lib/Makefile.am (libgraypam_la_SOURCES): Add env.c

* pam_fshadow/Makefile.am: Remove BUILD_PAM_FSHADOW
substitution.
* pam_regex/Makefile.am: Remove BUILD_PAM_REGEX
substitution.
* pam_sql/pam_sql.c (free_config, boolean_true_p)
(read_config): Remove. Use gray_env_* functions
instead. All uses updated.
* pam_regex/pam_regex.c: Fix typo.

* pam_ldaphome/Makefile.am: New file.

1 /* This file is part of pam-modules.
2 Copyright (C) 2005-2008, 2010-2011 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE__PAM_ACONF_H
18 # include <security/_pam_aconf.h>
19 #endif
20 #ifndef LINUX_PAM
21 # include <security/pam_appl.h>
22 #endif /* LINUX_PAM */
23 #include <security/pam_modules.h>
24
25 #include <sys/stat.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ldap.h>
29 #include <pwd.h>
30 #include <grp.h>
31
32 #include "graypam.h"
33
34 /* indicate the following groups are defined */
35 #define PAM_SM_AUTH
36
37 static long debug_level;
38 static int cntl_flags;
39 static char *config_file_name;
40 static int ldap_debug_level;
41 /* FIXME: This should be read from sshd_config */
42 static char *authorized_keys_file=".ssh/authorized_keys";
43
44 struct pam_opt pam_opt[] = {
45 { PAM_OPTSTR(debug), pam_opt_long, &debug_level },
46 { PAM_OPTSTR(debug), pam_opt_const, &debug_level, { 1 } },
47 { PAM_OPTSTR(audit), pam_opt_bitmask, &cntl_flags, { CNTL_AUDIT } },
48 { PAM_OPTSTR(waitdebug), pam_opt_null, NULL, { 0 },
49 gray_wait_debug_fun },
50 { PAM_OPTSTR(config), pam_opt_string, &config_file_name },
51 { NULL }
52 };
53
54 static void
55 _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
56 {
57 cntl_flags = 0;
58 debug_level = 0;
59 config_file_name = SYSCONFDIR "/" MODULE_NAME ".conf";
60 gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
61 gray_parseopt(pam_opt, argc, argv);
62 }
63
64 static void
65 argcv_free(int wc, char **wv)
66 {
67 int i;
68
69 for (i = 0; i < wc; i++) {
70 free(wv[i]);
71 free(wv);
72 }
73 }
74
75 static int
76 argcv_split(const char *str, int *pargc, char ***pargv)
77 {
78 int argc, i;
79 char **argv;
80 const char *p;
81 int rc = 0;
82
83 argc = 1;
84 for (p = str; *p; p++) {
85 if (*p == ' ')
86 argc++;
87 }
88 argv = calloc(argc + 1, sizeof(argv[0]));
89 if (!argv)
90 return 1;
91 for (i = 0, p = str;;) {
92 size_t len = strcspn(p, " ");
93 char *q = malloc(len + 1);
94
95 if (!q) {
96 rc = errno;
97 break;
98 }
99 memcpy(q, p, len);
100 q[len] = 0;
101 argv[i++] = q;
102 p += len;
103 if (p)
104 p += strspn(p, " ");
105 if (!*p)
106 break;
107 }
108
109 if (rc) {
110 argcv_free(argc, argv);
111 errno = rc;
112 return 1;
113 }
114
115 argv[i] = NULL;
116 *pargc = argc;
117 *pargv = argv;
118 return 0;
119 }
120
121 static char *
122 argcv_concat(int wc, char **wv)
123 {
124 char *res, *p;
125 size_t size = 0;
126 int i;
127
128 for (i = 0; i < wc; i++)
129 size += strlen(wv[i]) + 1;
130 size++;
131 res = malloc(size);
132 if (!res)
133 return 0;
134 for (p = res, i = 0; ; i++) {
135 strcpy(p, wv[i]);
136 p += strlen(wv[i]);
137 if (i < wc)
138 *p++ = ' ';
139 else
140 break;
141 }
142 *p = 0;
143 return res;
144 }
145
146 char *
147 parse_ldap_uri(const char *uri)
148 {
149 int wc;
150 char **wv;
151 LDAPURLDesc *ludlist, **ludp;
152 char **urls = NULL;
153 int nurls = 0;
154 char *ldapuri = NULL;
155 int rc;
156
157 rc = ldap_url_parse(uri, &ludlist);
158 if (rc != LDAP_URL_SUCCESS) {
159 _pam_log(LOG_ERR, "cannot parse LDAP URL(s)=%s (%d)",
160 uri, rc);
161 return NULL;
162 }
163
164 for (ludp = &ludlist; *ludp; ) {
165 LDAPURLDesc *lud = *ludp;
166 char **tmp;
167
168 if (lud->lud_dn && lud->lud_dn[0]
169 && (lud->lud_host == NULL || lud->lud_host[0] == '\0')) {
170 /* if no host but a DN is provided, try
171 DNS SRV to gather the host list */
172 char *domain = NULL, *hostlist = NULL;
173 size_t i;
174
175 if (ldap_dn2domain (lud->lud_dn, &domain) ||
176 !domain) {
177 _pam_log(LOG_ERR,
178 "DNS SRV: cannot convert "
179 "DN=\"%s\" into a domain",
180 lud->lud_dn);
181 goto dnssrv_free;
182 }
183
184 rc = ldap_domain2hostlist(domain, &hostlist);
185 if (rc) {
186 _pam_log(LOG_ERR,
187 "DNS SRV: cannot convert "
188 "domain=%s into a hostlist",
189 domain);
190 goto dnssrv_free;
191 }
192
193 if (argcv_split(hostlist, &wc, &wv)) {
194 _pam_log(LOG_ERR,
195 "DNS SRV: could not parse "
196 "hostlist=\"%s\": %s",
197 hostlist, strerror(errno));
198 goto dnssrv_free;
199 }
200
201 tmp = realloc(urls, sizeof(char *) * (nurls + wc + 1));
202 if (!tmp) {
203 _pam_log(LOG_ERR,
204 "DNS SRV %s", strerror(errno));
205 goto dnssrv_free;
206 }
207
208 urls = tmp;
209 urls[nurls] = NULL;
210
211 for (i = 0; i < wc; i++) {
212 char *p = malloc(strlen(lud->lud_scheme) +
213 strlen(wv[i]) +
214 3);
215 if (!p) {
216 _pam_log(LOG_ERR, "DNS SRV %s",
217 strerror(errno));
218 goto dnssrv_free;
219 }
220
221 strcpy(p, lud->lud_scheme);
222 strcat(p, "//");
223 strcat(p, wv[i]);
224
225 urls[nurls + i + 1] = NULL;
226 urls[nurls + i] = p;
227 }
228
229 nurls += i;
230
231 dnssrv_free:
232 argcv_free(wc, wv);
233 ber_memfree(hostlist);
234 ber_memfree(domain);
235 } else {
236 tmp = realloc(urls, sizeof(char *) * (nurls + 2));
237 if (!tmp) {
238 _pam_log(LOG_ERR,
239 "DNS SRV %s", strerror(errno));
240 break;
241 }
242 urls = tmp;
243 urls[nurls + 1] = NULL;
244
245 urls[nurls] = ldap_url_desc2str(lud);
246 if (!urls[nurls]) {
247 _pam_log(LOG_ERR, "DNS SRV %s",
248 strerror(errno));
249 break;
250 }
251 nurls++;
252 }
253
254 *ludp = lud->lud_next;
255
256 lud->lud_next = NULL;
257 ldap_free_urldesc(lud);
258 }
259
260 if (ludlist) {
261 ldap_free_urldesc (ludlist);
262 return NULL;
263 } else if (!urls)
264 return NULL;
265 ldapuri = argcv_concat(wc, wv);
266 if (!ldapuri)
267 _pam_log(LOG_ERR, "%s", strerror(errno));
268 ber_memvfree ((void **)urls);
269 return ldapuri;
270 }
271
272 static LDAP *
273 ldap_connect(struct gray_env *env)
274 {
275 int rc;
276 char *ldapuri = NULL;
277 LDAP *ld = NULL;
278 int protocol = LDAP_VERSION3; /* FIXME: must be configurable */
279 char *val;
280
281 if (ldap_debug_level) {
282 if (ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL,
283 &ldap_debug_level)
284 != LBER_OPT_SUCCESS )
285 _pam_log(LOG_ERR,
286 "cannot set LBER_OPT_DEBUG_LEVEL %d",
287 ldap_debug_level);
288
289 if (ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL,
290 &ldap_debug_level)
291 != LDAP_OPT_SUCCESS )
292 _pam_log(LOG_ERR,
293 "could not set LDAP_OPT_DEBUG_LEVEL %d",
294 ldap_debug_level);
295 }
296
297 val = gray_env_get(env, "uri");
298 if (val) {
299 ldapuri = parse_ldap_uri(val);
300 if (!ldapuri)
301 return NULL;
302 }
303 DEBUG(2, ("constructed LDAP URI: %s",
304 ldapuri ? ldapuri : "<DEFAULT>"));
305
306 rc = ldap_initialize(&ld, ldapuri);
307 if (rc != LDAP_SUCCESS) {
308 _pam_log(LOG_ERR,
309 "cannot create LDAP session handle for "
310 "URI=%s (%d): %s",
311 ldapuri, rc, ldap_err2string(rc));
312 free(ldapuri);
313 return NULL;
314 }
315 free(ldapuri);
316
317 val = gray_env_get(env, "tls");
318
319 if (val && gray_boolean_true_p(val)) {
320 rc = ldap_start_tls_s(ld, NULL, NULL);
321 if (rc != LDAP_SUCCESS) {
322 _pam_log(LOG_ERR,
323 "ldap_start_tls failed: %s",
324 ldap_err2string(rc));
325 /* try to continue anyway, to avoid memory
326 leek (ld not being freed) */
327 }
328 }
329
330 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol);
331
332 /* FIXME: Timeouts, SASL, etc. */
333 return ld;
334 }
335
336 static int
337 ldap_bind (LDAP *ld, struct gray_env *env)
338 {
339 int msgid, err, rc;
340 LDAPMessage *result;
341 LDAPControl **ctrls;
342 char msgbuf[256];
343 char *matched = NULL;
344 char *info = NULL;
345 char **refs = NULL;
346 static struct berval passwd;
347 char *binddn;
348
349 binddn = gray_env_get(env, "binddn");
350 passwd.bv_val = gray_env_get(env, "bindpw");
351 passwd.bv_len = passwd.bv_val ? strlen(passwd.bv_val) : 0;
352
353 msgbuf[0] = 0;
354
355 rc = ldap_sasl_bind(ld, binddn, LDAP_SASL_SIMPLE, &passwd,
356 NULL, NULL, &msgid);
357 if (msgid == -1) {
358 _pam_log(LOG_ERR,
359 "ldap_sasl_bind(SIMPLE) failed: %s",
360 ldap_err2string(rc));
361 return 1;
362 }
363
364 if (ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1) {
365 _pam_log(LOG_ERR, "ldap_result failed");
366 return 1;
367 }
368
369 rc = ldap_parse_result(ld, result, &err, &matched, &info, &refs,
370 &ctrls, 1);
371 if (rc != LDAP_SUCCESS) {
372 _pam_log(LOG_ERR, "ldap_parse_result failed: %s",
373 ldap_err2string (rc));
374 return 1;
375 }
376
377 if (ctrls)
378 ldap_controls_free(ctrls);
379
380 if (err != LDAP_SUCCESS
381 || msgbuf[0]
382 || (matched && matched[0])
383 || (info && info[0])
384 || refs) {
385 /* FIXME: Use debug output for that */
386 DEBUG(2,("ldap_bind: %s (%d)%s",
387 ldap_err2string(err), err, msgbuf));
388
389 if (matched && *matched)
390 DEBUG(2,("matched DN: %s", matched));
391
392 if (info && *info)
393 DEBUG(2,("additional info: %s", info));
394
395 if (refs && *refs) {
396 int i;
397 DEBUG(3,("referrals:"));
398 for (i = 0; refs[i]; i++)
399 DEBUG(3,("%s", refs[i]));
400 }
401 }
402
403 if (matched)
404 ber_memfree(matched);
405 if (info)
406 ber_memfree(info);
407 if (refs)
408 ber_memvfree((void **)refs);
409
410 return !(err == LDAP_SUCCESS);
411 }
412
413 static void
414 ldap_unbind(LDAP *ld)
415 {
416 if (ld) {
417 ldap_set_option(ld, LDAP_OPT_SERVER_CONTROLS, NULL);
418 ldap_unbind_ext(ld, NULL, NULL);
419 }
420 }
421
422 static char *
423 get_ldap_attr(LDAP *ld, LDAPMessage *msg, const char *attr)
424 {
425 int rc;
426 BerElement *ber = NULL;
427 struct berval bv;
428 char *ufn = NULL;
429 char *val;
430 struct berval **values;
431
432 rc = ldap_get_dn_ber(ld, msg, &ber, &bv);
433 ufn = ldap_dn2ufn(bv.bv_val);
434 DEBUG(2, ("INFO: %s", ufn));
435 ldap_memfree(ufn);
436
437 values = ldap_get_values_len(ld, msg, attr);
438 if (!values || !values[0]) {
439 _pam_log(LOG_ERR,
440 "LDAP attribute `%s' has NULL value",
441 attr);
442 return NULL;
443 }
444 val = strdup(values[0]->bv_val);
445 if (!val)
446 _pam_log(LOG_ERR, "%s", strerror(errno));
447 else
448 DEBUG(1, ("pubkey: %s", val));
449 ldap_value_free_len(values);
450 return val;
451 }
452
453 static char *
454 ldap_search(LDAP *ld, const char *base, const char *filter, const char *attr)
455 {
456 int rc;
457 LDAPMessage *res, *msg;
458 ber_int_t msgid;
459 char *attrs[2];
460 char *ret;
461
462 attrs[0] = (char*) attr;
463 attrs[1] = NULL;
464 rc = ldap_search_ext(ld, base, LDAP_SCOPE_SUBTREE,
465 filter, attrs, 0,
466 NULL, NULL, NULL, -1, &msgid);
467
468 if (rc != LDAP_SUCCESS) {
469 _pam_log(LOG_ERR, "ldap_search_ext: %s", ldap_err2string(rc));
470 return NULL;
471 }
472
473 rc = ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &res);
474 if (rc < 0) {
475 _pam_log(LOG_ERR, "ldap_result failed");
476 return NULL;
477 }
478
479 rc = ldap_count_entries(ld, res);
480 if (rc == 0) {
481 _pam_log(LOG_ERR, "not enough entires");
482 return NULL;
483 }
484 if (rc > 1)
485 _pam_log(LOG_NOTICE, "LDAP: too many entries for filter %s",
486 filter);
487
488 msg = ldap_first_entry(ld, res);
489 ret = get_ldap_attr(ld, msg, attr);
490 ldap_msgfree(res);
491
492 return ret;
493 }
494
495 static int
496 get_intval(struct gray_env *env, const char *name, unsigned long *pv)
497 {
498 char *p;
499 char *v = gray_env_get(env, name);
500
501 if (!v)
502 return 1;
503 *pv = strtoul(v, &p, 10);
504 if (*p) {
505 _pam_log(LOG_ERR, "configuration variable %s is not integer",
506 name);
507 return 1;
508 }
509 return 0;
510 }
511
512 static int
513 check_groups(int gc, char **gv, const char *username)
514 {
515 int i;
516
517 for (i = 0; i < gc; i++) {
518 struct group *gp = getgrnam(gv[i]);
519 if (gp) {
520 char **p;
521 for (p = gp->gr_mem; *p; p++)
522 if (strcmp(username, *p) == 0)
523 return 0;
524 }
525 }
526 return 1;
527 }
528
529 static int
530 check_user_groups(pam_handle_t *pamh, struct gray_env *env,
531 struct passwd **ppw, int *retval)
532 {
533 int rc;
534 const char *username;
535 struct passwd *pw;
536 unsigned long ival;
537 char *sval;
538
539 rc = pam_get_user(pamh, &username, NULL);
540 if (rc != PAM_SUCCESS || !username) {
541 DEBUG(1,("can not get the username"));
542 *retval = rc;
543 return 1;
544 }
545 pw = getpwnam(username);
546 if (!pw) {
547 *retval = PAM_USER_UNKNOWN;
548 return 1;
549 }
550 *ppw = pw;
551 if (get_intval(env, "min-uid", &ival) == 0) {
552 if (pw->pw_uid < ival) {
553 DEBUG(10, ("ignoring user %s: has UID < %lu",
554 username, ival));
555 *retval = PAM_SUCCESS;
556 return 1;
557 }
558 }
559 if (get_intval(env, "min-gid", &ival) == 0) {
560 if (pw->pw_gid < ival) {
561 DEBUG(10, ("ignoring user %s: has GID < %lu",
562 username, ival));
563 *retval = PAM_SUCCESS;
564 return 1;
565 }
566 }
567 sval = gray_env_get(env, "allow-groups");
568 if (sval) {
569 int gc;
570 char **gv;
571 int rc;
572
573 if (argcv_split(sval, &gc, &gv)) {
574 _pam_log(LOG_ERR, "cannot split allow-groups: %s",
575 strerror(errno));
576 *retval = PAM_AUTH_ERR;
577 return 1;
578 }
579 rc = check_groups(gc, gv, username);
580 argcv_free(gc, gv);
581 if (rc) {
582 DEBUG(10, ("ignoring user %s: not in allowed group list",
583 username, ival));
584 *retval = PAM_SUCCESS;
585 return 1;
586 }
587 }
588 return 0;
589 }
590
591 static int
592 populate_homedir(struct passwd *pw, const char *skel)
593 {
594 // FIXME!!!
595 _pam_log(LOG_ERR, "populate_homedir is not yet implemented!");
596 return 1;
597 }
598
599 /* Create the directory DIR, eventually creating all intermediate directories
600 starting from DIR + BASELEN. */
601 int
602 create_hierarchy(char *dir, size_t baselen)
603 {
604 int rc;
605 struct stat st;
606 char *p;
607
608 if (stat(dir, &st) == 0) {
609 if (!S_ISDIR(st.st_mode)) {
610 _pam_log(LOG_ERR, "component %s is not a directory",
611 dir);
612 return 1;
613 }
614 return 0;
615 } else if (errno != ENOENT) {
616 _pam_log(LOG_ERR, "cannot stat file %s: %s",
617 dir, strerror(errno));
618 return 1;
619 }
620
621 p = strrchr(dir, '/');
622 if (p) {
623 if (p - dir + 1 < baselen) {
624 _pam_log(LOG_ERR, "base directory %s does not exist",
625 dir);
626 return 1;
627 }
628 *p = 0;
629 }
630
631 rc = create_hierarchy(dir, baselen);
632 if (rc == 0) {
633 if (p)
634 *p = '/';
635 if (mkdir(dir, 0755)) {
636 _pam_log(LOG_ERR, "cannot create directory %s: %s",
637 dir, strerror(errno));
638 rc = 1;
639 }
640 }
641 return rc;
642 }
643
644 int
645 create_interdir(const char *path, struct passwd *pw)
646 {
647 char *dir, *p;
648 size_t len;
649 int rc;
650
651 p = strrchr(path, '/');
652 if (!p)
653 return 1;
654 len = p - path;
655 dir = gray_malloc(len + 1);
656 memcpy(dir, path, len);
657 dir[len] = 0;
658 rc = create_hierarchy(dir, strlen(pw->pw_dir));
659 if (rc == 0)
660 chown(dir, pw->pw_uid, pw->pw_gid);
661 free(dir);
662 return rc;
663 }
664
665 static void
666 store_pubkey(const char *key, struct passwd *pw)
667 {
668 FILE *fp;
669 const char *kp;
670 int c;
671 int found = 0;
672 char *file_name;
673 size_t homelen, pathlen, len;
674
675 homelen = strlen(pw->pw_dir);
676 pathlen = strlen(authorized_keys_file);
677 len = homelen + pathlen;
678 if (pw->pw_dir[homelen - 1] != '/')
679 len++;
680 file_name = gray_malloc(len + 1);
681 memcpy(file_name, pw->pw_dir, homelen);
682 if (pw->pw_dir[homelen - 1] != '/')
683 file_name[homelen++] = '/';
684 strcpy(file_name + homelen, authorized_keys_file);
685
686 fp = fopen(file_name, "a+");
687 if (!fp && create_interdir(file_name, pw) == 0)
688 fp = fopen(file_name, "a+");
689 if (!fp) {
690 _pam_log(LOG_EMERG, "cannot open file %s: %s",
691 file_name, strerror(errno));
692 free(file_name);
693 return;
694 }
695 free(file_name);
696 fchown(fileno(fp), pw->pw_uid, pw->pw_gid);
697
698 kp = key;
699 while (!feof(fp)) {
700 while (*kp && (c = getc(fp)) != EOF && c == *kp)
701 kp++;
702 if (*kp == 0) {
703 DEBUG(2, ("key found"));
704 found = 1;
705 break;
706 }
707 kp = key;
708 if (c != '\n') {
709 if (c != EOF) {
710 while ((c = getc(fp)) != EOF && c != '\n')
711 ;
712 }
713 if (c == EOF) {
714 if (ftell(fp))
715 fputc('\n', fp);
716 break;
717 }
718 }
719 }
720
721 if (!found) {
722 fwrite(key, strlen(key), 1, fp);
723 fputc('\n', fp);
724 }
725 fclose(fp);
726 }
727
728 static int
729 import_public_key(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
730 {
731 LDAP *ld;
732 int retval;
733 const char *base = gray_env_get(env, "base");
734 const char *filter_pat = gray_env_get(env, "filter");
735 const char *attr = gray_env_get(env, "pubkey-attr");
736
737 if (!filter_pat) {
738 _pam_log(LOG_ERR, "configuration variable `filter' not set");
739 return PAM_SERVICE_ERR;
740 }
741 if (!attr) {
742 _pam_log(LOG_ERR, "configuration variable `attr' not set");
743 return PAM_SERVICE_ERR;
744 }
745
746 ld = ldap_connect(env);
747 if (!ld)
748 return PAM_SERVICE_ERR;
749 if (ldap_bind(ld, env))
750 retval = PAM_SERVICE_ERR;
751 else {
752 char *filter;
753 gray_slist_t slist;
754 char *pubkey;
755
756 slist = gray_slist_create();
757 gray_expand_string(pamh, filter_pat, slist);
758 gray_slist_append_char(slist, 0);
759 filter = gray_slist_finish(slist);
760
761 pubkey = ldap_search(ld, base, filter, attr);
762 gray_slist_free(&slist);
763 store_pubkey(pubkey, pw);
764 free(pubkey);
765 retval = PAM_SUCCESS;
766 }
767 ldap_unbind(ld);
768 return retval;
769 }
770
771 static int
772 create_home_dir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
773 {
774 struct stat st;
775 char *s;
776
777 if (stat(pw->pw_dir, &st)) {
778 if (errno != ENOENT) {
779 _pam_log(LOG_ERR, "cannot stat home directory %s: %s",
780 pw->pw_dir, strerror(errno));
781 return 1;
782 }
783 /* FIXME: mode must be configurable */
784 if (mkdir(pw->pw_dir, 0775)) {
785 _pam_log(LOG_ERR, "cannot create %s: %s",
786 pw->pw_dir, strerror(errno));
787 return 1;
788 }
789 chown(pw->pw_dir, pw->pw_uid, pw->pw_gid);
790 } else if (!S_ISDIR(st.st_mode)) {
791 _pam_log(LOG_ERR, "%s exists, but is not a directory",
792 pw->pw_dir);
793 return 1;
794 }
795
796 s = gray_env_get(env, "skel");
797 if (s) {
798 if (stat(s, &st)) {
799 _pam_log(LOG_ERR, "cannot stat skeleton directory %s: %s",
800 pw->pw_dir, strerror(errno));
801 return 1;
802 } else if (!S_ISDIR(st.st_mode)) {
803 _pam_log(LOG_ERR, "%s exists, but is not a directory",
804 pw->pw_dir);
805 return 1;
806 }
807 populate_homedir(pw, s);
808 }
809
810 return 0;
811 }
812
813 PAM_EXTERN int
814 pam_sm_authenticate(pam_handle_t *pamh,
815 int flags,
816 int argc,
817 const char **argv)
818 {
819 int retval = PAM_AUTH_ERR;
820 struct gray_env *env;
821
822 _pam_parse(pamh, argc, argv);
823
824 DEBUG(90,("enter pam_sm_authenticate"));
825 gray_pam_init(PAM_AUTHINFO_UNAVAIL);
826 if (gray_env_read(config_file_name, &env) == 0) {
827 struct passwd *pw;
828
829 if (check_user_groups(pamh, env, &pw, &retval) == 0) {
830 if (create_home_dir(pamh, pw, env) == 0 &&
831 import_public_key(pamh, pw, env) == 0)
832 retval = PAM_TRY_AGAIN;
833 }
834 gray_env_free(env);
835 }
836 DEBUG(90,("exit pam_sm_authenticate: %d", retval));
837 return retval;
838 }
839
840 PAM_EXTERN int
841 pam_sm_setcred(pam_handle_t *pamh,
842 int flags,
843 int argc,
844 const char **argv)
845 {
846 return PAM_SUCCESS;
847 }
848
849 #ifdef PAM_STATIC
850
851 struct pam_module _pam_ldaphome_modstruct = {
852 "pam_ldaphome", /* name of the module */
853 pam_sm_authenticate,
854 pam_sm_setcred,
855 NULL,
856 NULL,
857 NULL,
858 NULL
859 };
860
861 #endif

Send suggestions and bug reports to Sergey Poznyakoff
ViewVC Help
Powered by ViewVC 1.1.20