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

Contents of /trunk/pam_fshadow/pam_fshadow.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 61 - (show annotations)
Mon Aug 27 22:38:35 2007 UTC (14 years, 5 months ago) by gray
File MIME type: text/plain
File size: 12494 byte(s)
Lots of fixes in pam_mysql
1 /* This file is part of pam-modules.
2 * Copyright (C) 2001, 2005, 2007 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
18 /* pam_fshadow */
19
20 #if defined(HAVE_CONFIG_H)
21 # include <config.h>
22 #endif
23
24 #include <security/_pam_aconf.h>
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <syslog.h>
31 #include <stdarg.h>
32 #include <time.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <pwd.h>
38 #include <shadow.h>
39 #include <regex.h>
40
41 #define PAM_SM_AUTH
42 #define PAM_SM_ACCOUNT
43
44 #include <security/pam_modules.h>
45
46 #include <common.c>
47
48 char *sysconfdir = SYSCONFDIR;
49 static int cntl_flags = 0;
50
51 static regex_t rexp;
52 const char *regex_str = NULL;
53 static int username_index = 1;
54 static int domain_index = 2;
55
56 #define CNTL_DEBUG 0x0001
57 #define CNTL_AUTHTOK 0x0002
58 #define CNTL_NOPASSWD 0x0004
59 #define CNTL_REGEX 0x0008
60
61 #define CNTL_DEBUG_LEV() (cntl_flags>>16)
62 #define CNTL_SET_DEBUG_LEV(cntl,n) (cntl |= ((n)<<16))
63 #define DEBUG(m,c) if (CNTL_DEBUG_LEV()>=(m)) _pam_debug c
64
65 static int
66 _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
67 {
68 int regex_flags = 0;
69 int retval = PAM_SUCCESS;
70
71 /* step through arguments */
72 for (cntl_flags = 0; argc-- > 0; ++argv) {
73
74 /* generic options */
75
76 if (!strncmp(*argv, "debug", 5)) {
77 cntl_flags |= CNTL_DEBUG;
78 if ((*argv)[5] == '=')
79 CNTL_SET_DEBUG_LEV(cntl_flags,
80 atoi(*argv + 6));
81 else
82 CNTL_SET_DEBUG_LEV(cntl_flags, 1);
83 } else if (!strncmp(*argv, "waitdebug", 9))
84 WAITDEBUG(*argv + 9);
85 else if (!strcmp(*argv,"use_authtok"))
86 cntl_flags |= CNTL_AUTHTOK;
87 else if (!strncmp(*argv, "sysconfdir=", 11))
88 sysconfdir = (char*) (*argv + 11);
89 else if (!strncmp(*argv, "regex=", 6))
90 regex_str = (*argv + 6);
91 else if (!strcmp(*argv, "basic"))
92 regex_flags &= ~REG_EXTENDED;
93 else if (!strcmp(*argv, "extended"))
94 regex_flags |= REG_EXTENDED;
95 else if (!strcmp(*argv, "icase")
96 || !strcmp(*argv, "ignore-case"))
97 regex_flags |= REG_ICASE;
98 else if (!strcmp(*argv, "revert-index")) {
99 username_index = 2;
100 domain_index = 1;
101 } else if (!strcmp(*argv, "nopasswd"))
102 cntl_flags |= CNTL_NOPASSWD;
103 else
104 _pam_log(LOG_ERR,
105 "unknown option: %s", *argv);
106 }
107
108
109 if (regex_str) {
110 int rc;
111 if (rc = regcomp(&rexp, regex_str, regex_flags)) {
112 size_t s = regerror(rc, &rexp, NULL, 0);
113 char *buf = malloc (s);
114 if (buf) {
115 regerror(rc, &rexp, buf, s);
116 _pam_log(LOG_NOTICE,
117 "cannot compile regex `%s': %s",
118 regex_str, buf);
119 free (buf);
120 } else
121 _pam_log(LOG_NOTICE,
122 "cannot compile regex `%s'",
123 regex_str);
124 retval = PAM_AUTHINFO_UNAVAIL;
125 } else if (rexp.re_nsub != 2) {
126 _pam_log(LOG_NOTICE,
127 "invalid regular expression `%s': "
128 "must contain two reference groups",
129 regex_str);
130 regfree(&rexp);
131 retval = PAM_AUTHINFO_UNAVAIL;
132 } else {
133 cntl_flags |= CNTL_REGEX;
134 rc = pam_set_data(pamh, "REGEX", &rexp,
135 _cleanup_regex);
136
137 if (rc != PAM_SUCCESS) {
138 _pam_log(LOG_NOTICE,
139 "can't keep data [%s]: %s",
140 "REGEX",
141 pam_strerror(pamh, rc));
142 }
143 }
144 }
145
146 return retval;
147 }
148
149 static int
150 converse(pam_handle_t *pamh,
151 int nargs,
152 struct pam_message **message,
153 struct pam_response **response)
154 {
155 int retval;
156 struct pam_conv *conv;
157
158 DEBUG(100,("enter converse"));
159
160 retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
161 DEBUG(10,("pam_get_item(PAM_CONV): %d", retval));
162 if (retval == PAM_SUCCESS) {
163
164 retval = conv->conv(nargs,
165 (const struct pam_message **) message,
166 response,
167 conv->appdata_ptr);
168
169 DEBUG(10, ("app conversation returned %d", retval));
170
171 if (retval != PAM_SUCCESS) {
172 _pam_log(LOG_ERR,
173 "conversation failure [%s]",
174 pam_strerror(pamh, retval));
175 }
176 } else if (retval != PAM_CONV_AGAIN) {
177 _pam_log(LOG_ERR,
178 "couldn't obtain coversation function: %s",
179 pam_strerror(pamh, retval));
180 }
181
182 DEBUG(100,("exit converse: %d", retval));
183
184 return retval; /* propagate error status */
185 }
186
187 static int
188 _pam_get_password(pam_handle_t *pamh, char **password, const char *prompt)
189 {
190 char *item, *token;
191 int retval;
192 struct pam_message msg[3], *pmsg[3];
193 struct pam_response *resp;
194 int i, replies;
195
196 DEBUG(100,("enter _pam_get_password"));
197
198 if (cntl_flags & CNTL_AUTHTOK) {
199 /*
200 * get the password from the PAM item
201 */
202 retval = pam_get_item(pamh, PAM_AUTHTOK,
203 (const void **) &item);
204 if (retval != PAM_SUCCESS) {
205 /* very strange. */
206 _pam_log(LOG_ALERT,
207 "can't retrieve password item: %s",
208 pam_strerror(pamh, retval));
209 return retval;
210 } else if (item != NULL) {
211 *password = item;
212 item = NULL;
213 return PAM_SUCCESS;
214 } else
215 return PAM_AUTHTOK_RECOVER_ERR;
216 }
217
218 /*
219 * ask user for the password
220 */
221 /* prepare to converse */
222
223 i = 0;
224 pmsg[i] = &msg[i];
225 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
226 msg[i++].msg = (const void*)prompt;
227 replies = 1;
228
229 /* run conversation */
230 resp = NULL;
231 token = NULL;
232 retval = converse(pamh, i, pmsg, &resp);
233
234 if (resp != NULL) {
235 if (retval == PAM_SUCCESS) { /* a good conversation */
236 token = XSTRDUP(resp[i - replies].resp);
237 DEBUG(10,("app returned [%s]", token));
238 PAM_DROP_REPLY(resp, 1);
239 } else {
240 _pam_log(LOG_ERR, "conversation error: %s",
241 pam_strerror(pamh, retval));
242 }
243
244 } else {
245 retval = (retval == PAM_SUCCESS)
246 ? PAM_AUTHTOK_RECOVER_ERR : retval;
247 }
248
249 if (retval == PAM_SUCCESS) {
250 /*
251 * keep password as data specific to this module. pam_end()
252 * will arrange to clean it up.
253 */
254 retval = pam_set_data(pamh, "password",
255 (void *)token,
256 _cleanup_string);
257 if (retval != PAM_SUCCESS) {
258 _pam_log(LOG_CRIT,
259 "can't keep password: %s",
260 pam_strerror(pamh, retval));
261 _pam_delete(token);
262 } else {
263 *password = token;
264 token = NULL; /* break link to password */
265 }
266 } else {
267 _pam_log(LOG_ERR,
268 "unable to obtain a password: %s",
269 pam_strerror(pamh, retval));
270 }
271
272 DEBUG(100,("exit _pam_get_password: %d", retval));
273 return retval;
274 }
275
276 char *
277 mkfilename(const char *dir, const char *name)
278 {
279 int len = strlen(dir) + strlen(name);
280 char *p = malloc(len+2);
281 if (!p) {
282 _pam_log(LOG_EMERG, "not enough memory");
283 abort ();
284 }
285 sprintf(p, "%s/%s", dir, name);
286 return p;
287 }
288
289 int
290 verify_user_acct(const char *confdir, const char *username, char **pwd)
291 {
292 char *filename = mkfilename(confdir, "passwd");
293 FILE *fp;
294 int retval;
295
296 DEBUG(10,("Looking up user `%s' in `%s'",
297 username, filename));
298
299 *pwd = NULL;
300 fp = fopen (filename, "r");
301 if (fp) {
302 struct passwd *pw;
303
304 while ((pw = fgetpwent (fp)) != NULL) {
305 if (strcmp (pw->pw_name, username) == 0)
306 break;
307 }
308 if (!pw) {
309 _pam_log(LOG_ERR, "user %s not found in %s",
310 username, filename);
311 retval = PAM_USER_UNKNOWN;
312 } else {
313 if (pw->pw_passwd && strlen(pw->pw_passwd) > 1)
314 *pwd = strdup(pw->pw_passwd);
315 retval = PAM_SUCCESS;
316 }
317 } else {
318 _pam_log(LOG_ERR, "can't open %s: %s",
319 filename, strerror(errno));
320 retval = PAM_SERVICE_ERR;
321 }
322 free(filename);
323 return retval;
324 }
325
326 int
327 verify_user_pass(const char *confdir, const char *username,
328 const char *password)
329 {
330 struct spwd *sp = NULL;
331 time_t curdays;
332 FILE *fp;
333 int retval = PAM_AUTH_ERR;
334 char *shadow = mkfilename(confdir, "shadow");
335
336 DEBUG(10,("Verifying user `%s' with password `%s' in `%s'",
337 username, password, shadow));
338
339 fp = fopen(shadow, "r");
340 if (!fp) {
341 _pam_log(LOG_ERR,
342 "can't open %s: %s", shadow, strerror(errno));
343 free(shadow);
344 return PAM_SERVICE_ERR;
345 }
346
347 while ((sp = fgetspent(fp)) != NULL
348 && strcmp(sp->sp_namp, username))
349 ;
350 fclose(fp);
351
352 if (!sp) {
353 _pam_log(LOG_ERR,
354 "entry for %s not found in %s",
355 username, shadow);
356 free(shadow);
357 return PAM_USER_UNKNOWN;
358 }
359
360 /* We have the user's information, now let's check if his account
361 has expired */
362 curdays = time(NULL) / (60 * 60 * 24);
363 if (sp->sp_min != -1 && curdays < sp->sp_lstchg + sp->sp_min)
364 retval = PAM_AUTHTOK_ERR;
365 else if (sp->sp_max != -1 && sp->sp_inact != -1 && sp->sp_lstchg != 0
366 && curdays > sp->sp_lstchg + sp->sp_max + sp->sp_inact)
367 /* Password is too old */
368 retval = PAM_ACCT_EXPIRED;
369 else if (sp->sp_expire != -1 && sp->sp_lstchg != 0
370 && curdays > sp->sp_expire)
371 /* Account has expired */
372 retval = PAM_ACCT_EXPIRED;
373 else if (strcmp(sp->sp_pwdp, crypt(password, sp->sp_pwdp)) == 0)
374 retval = PAM_SUCCESS;
375 else
376 retval = PAM_AUTH_ERR;
377
378 free(shadow);
379 return retval;
380 }
381
382 static int
383 copy_backref (pam_handle_t *pamh, const char *name,
384 const char *buf, regmatch_t rmatch[3], int index, char **pstr)
385 {
386 char *str;
387 size_t size;
388 int rc;
389
390 if (rmatch[index].rm_so == -1)
391 size = 0;
392 else
393 size = rmatch[index].rm_eo - rmatch[index].rm_so;
394
395 str = malloc (size + 1);
396 if (!str) {
397 _pam_log(LOG_CRIT, "not enough memory");
398 return PAM_SYSTEM_ERR;
399 }
400 rc = pam_set_data(pamh, name, (void *)str, _cleanup_string);
401 if (rc != PAM_SUCCESS) {
402 _pam_log(LOG_CRIT,
403 "can't keep data [%s]: %s",
404 name,
405 pam_strerror(pamh, rc));
406 _pam_delete(str);
407 } else {
408 if (size != 0)
409 memcpy(str, buf + rmatch[index].rm_so, size);
410 str[size] = 0;
411 *pstr = str;
412 }
413 return rc;
414 }
415
416 /* --- authentication management functions (only) --- */
417
418 PAM_EXTERN int
419 pam_sm_authenticate(pam_handle_t *pamh, int flags,
420 int argc, const char **argv)
421 {
422 const char *username;
423 char *password;
424 int retval = PAM_AUTH_ERR;
425 int rc;
426 char *confdir;
427 char *pwstr;
428
429 /* parse arguments */
430 if ((rc = _pam_parse(pamh, argc, argv)) != PAM_SUCCESS)
431 return rc;
432 confdir = sysconfdir;
433
434 /* Get the username */
435 retval = pam_get_user(pamh, &username, NULL);
436 if (retval != PAM_SUCCESS || !username) {
437 _pam_log(LOG_DEBUG,"can not get the username");
438 return PAM_SERVICE_ERR;
439 }
440
441 if (cntl_flags & CNTL_REGEX) {
442 regmatch_t rmatch[3];
443 if (regexec(&rexp, username, 3, rmatch, 0) == 0) {
444 char *domain;
445
446 rc = copy_backref(pamh, "DOMAIN", username, rmatch,
447 domain_index, &domain);
448 if (rc != PAM_SUCCESS)
449 return rc;
450 rc = copy_backref(pamh, "USERNAME", username, rmatch,
451 username_index, (char **) &username);
452 if (rc != PAM_SUCCESS)
453 return rc;
454 confdir = mkfilename(sysconfdir, domain);
455 pam_set_data(pamh, "CONFDIR",
456 (void *)confdir, _cleanup_string);
457 } else {
458 _pam_log(LOG_DEBUG,
459 "user name `%s' does not match regular "
460 "expression `%s'",
461 username,
462 regex_str);
463 }
464 }
465
466
467 /* Get the password */
468 if (_pam_get_password(pamh, &password, "Password:"))
469 return PAM_SERVICE_ERR;
470
471 if (retval != PAM_SUCCESS) {
472 _pam_log(LOG_ERR, "Could not retrive user's password");
473 return -2;
474 }
475
476 if (cntl_flags & CNTL_NOPASSWD)
477 retval = 0;
478 else
479 retval = verify_user_acct(confdir, username, &pwstr);
480 if (retval == PAM_SUCCESS) {
481 if (pwstr) {
482 if (strcmp(pwstr, crypt(password, pwstr)) == 0)
483 retval = PAM_SUCCESS;
484 else
485 retval = PAM_AUTH_ERR;
486 free(pwstr);
487 } else
488 retval = verify_user_pass(confdir, username, password);
489 }
490
491 switch (retval) {
492 case PAM_ACCT_EXPIRED:
493 _pam_log(LOG_NOTICE, "user '%s': account expired", username);
494 break;
495 case PAM_SUCCESS:
496 _pam_log(LOG_NOTICE, "user '%s' granted access", username);
497 break;
498 default:
499 _pam_log(LOG_NOTICE, "user '%s' failed to authenticate",
500 username);
501 }
502
503 return retval;
504 }
505
506 PAM_EXTERN
507 int pam_sm_setcred(pam_handle_t *pamh, int flags,
508 int argc, const char **argv)
509 {
510 return PAM_SUCCESS;
511 }
512
513 PAM_EXTERN
514 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
515 int argc, const char **argv)
516 {
517 return PAM_SUCCESS;
518 }
519
520
521 #ifdef PAM_STATIC
522
523 /* static module data */
524
525 struct pam_module _pam_fshadow_modstruct = {
526 "pam_fshadow",
527 pam_sm_authenticate,
528 pam_sm_setcred,
529 NULL,
530 NULL,
531 NULL,
532 NULL,
533 };
534
535 #endif

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

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