/ [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 63 - (show annotations)
Thu Mar 13 13:53:32 2008 UTC (13 years, 7 months ago) by gray
File MIME type: text/plain
File size: 11305 byte(s)
* configure.ac (PAM_COMMON_INCLUDES): Add -I${top_srcdir}/lib.
(AC_OUTPUT): Add lib/Makefile.
* doc/pam-modules.texi: Document `transform' option.
* Make.rules: New file.

* lib/mem.c, lib/slist.c, lib/log.c, lib/converse.c,
lib/graypam.h, lib/Makefile.am, lib/transform.c.

* pam_regex/pam_regex.c: Implement user name transformations.

* pam_fshadow/Makefile.am, pam_sql/Makefile.am:
Add ../lib/libgraypam.la to LDADD
* pam_fshadow/pam_fshadow.c, pam_sql/pam_mysql.c,
pam_sql/pam_pgsql.c, pam_sql/pam_sql.c: Use functions from ../lib.

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