summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2017-12-22 13:22:14 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2017-12-22 13:25:58 (GMT)
commit55620228a87786860e5eeabbab146a835e9830cf (patch) (unidiff)
tree3692518804feccff77aae50cf1ea3614ccb639be
parentfc8bf4028f468848ab00efb41e6c2a76be2174c9 (diff)
downloadpam-modules-55620228a87786860e5eeabbab146a835e9830cf.tar.gz
pam-modules-55620228a87786860e5eeabbab146a835e9830cf.tar.bz2
pam_fshadow: allow the user to use arbitrary group numbers for username and domain parts.
New options username-index and domain-index are used to indicate indices of the parenthesized groups used to extract the user and the domain name. The default corresponds to 'user-index=1 domain-index=1'. Additionally, change the behavior in case if the user name doesn't match the regexp. Previous versions would fall back to plain authentication in this case. New behavior is to reject access. * pam_fshadow/pam_fshadow.c (pam_opt): New options username-index and domain-index. (pam_sm_authenticate): Move username splitting into a separate function. * doc/pam_fshadow.8in: Document the new options.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--doc/pam_fshadow.8in37
-rw-r--r--pam_fshadow/pam_fshadow.c120
2 files changed, 102 insertions, 55 deletions
diff --git a/doc/pam_fshadow.8in b/doc/pam_fshadow.8in
index de4e471..261e0a8 100644
--- a/doc/pam_fshadow.8in
+++ b/doc/pam_fshadow.8in
@@ -1,5 +1,5 @@
1.\" This file is part of PAM-Modules -*- nroff -*- 1.\" This file is part of PAM-Modules -*- nroff -*-
2.\" Copyright (C) 2001-2015 Sergey Poznyakoff 2.\" Copyright (C) 2001-2017 Sergey Poznyakoff
3.\" 3.\"
4.\" PAM-Modules is free software; you can redistribute it and/or modify 4.\" PAM-Modules is free software; you can redistribute it and/or modify
5.\" it under the terms of the GNU General Public License as published by 5.\" it under the terms of the GNU General Public License as published by
@@ -14,14 +14,17 @@
14.\" You should have received a copy of the GNU General Public License 14.\" You should have received a copy of the GNU General Public License
15.\" along with PAM-Modules. If not, see <http://www.gnu.org/licenses/>. 15.\" along with PAM-Modules. If not, see <http://www.gnu.org/licenses/>.
16.so config.so 16.so config.so
17.TH PAM_FSHADOW 8 "March 30, 2014" "PAM-MODULES" "Pam-Modules User Reference" 17.TH PAM_FSHADOW 8 "December 22, 2017" "PAM-MODULES" "Pam-Modules User Reference"
18.SH NAME 18.SH NAME
19pam_fshadow \- use alternative passwd and/or shadow files 19pam_fshadow \- use alternative passwd and/or shadow files
20.SH SYNOPSIS 20.SH SYNOPSIS
21.nh 21.nh
22.na 22.na
23\fBpam_fshadow\fR\ 23\fBpam_fshadow\fR\
24 [\fBaudit\fR]\
25 [\fBdebug\fR[\fB=\fINUMBER\fR]]\
24 [\fBbasic\fR|\fBextended\fR]\ 26 [\fBbasic\fR|\fBextended\fR]\
27 [\fBdomain\-index=\fIN\fR]\
25 [\fBignore\-case\fR|\fBicase\fR|\fBcase\fR]\ 28 [\fBignore\-case\fR|\fBicase\fR|\fBcase\fR]\
26 [\fBnopasswd\fR]\ 29 [\fBnopasswd\fR]\
27 [\fBnoshadow\fR]\ 30 [\fBnoshadow\fR]\
@@ -29,9 +32,8 @@ pam_fshadow \- use alternative passwd and/or shadow files
29 [\fBrevert\-index\fR]\ 32 [\fBrevert\-index\fR]\
30 [\fBsysconfdir=\fIDIR\fR]\ 33 [\fBsysconfdir=\fIDIR\fR]\
31 [\fBuse_authtok\fR]\ 34 [\fBuse_authtok\fR]\
32 [\fBdebug\fR[\fB=\fINUMBER\fR]]\ 35 [\fBusername\-index=\fIN\fR]\
33 [\fBwaitdebug\fR]\ 36 [\fBwaitdebug\fR]
34 [\fBaudit\fR]
35.ad 37.ad
36.hy 38.hy
37.SH DESCRIPTION 39.SH DESCRIPTION
@@ -54,7 +56,7 @@ provided to disable reading of either file. E.g. if \fBnoshadow\fR is
54given, the module will expect all authentication information to be 56given, the module will expect all authentication information to be
55stored in the \fBpasswd\fR file. 57stored in the \fBpasswd\fR file.
56.PP 58.PP
57The \fBvirtual domain\fR mode select the \fBpasswd\fR,\fBshadow\fR 59The \fBvirtual domain\fR mode selects the \fBpasswd\fR,\fBshadow\fR
58pair to use depending on the user name. To that effect, the user name 60pair to use depending on the user name. To that effect, the user name
59is first split into the \fBlocal\fR and \fBauthentication domain\fR 61is first split into the \fBlocal\fR and \fBauthentication domain\fR
60parts using a regular expression supplied with the \fBregex\fR option. 62parts using a regular expression supplied with the \fBregex\fR option.
@@ -62,8 +64,7 @@ The configuration directory name is then constructed by concatenating the
62system configuration directory, a directory separator character (\fB/\fR), 64system configuration directory, a directory separator character (\fB/\fR),
63and the name of the authentication domain. The authentication then 65and the name of the authentication domain. The authentication then
64proceeds as described above for the plain mode. If the supplied user name 66proceeds as described above for the plain mode. If the supplied user name
65does not match the regular expression, \fBpam_fshadow\fR falls back to 67does not match the regular expression, \fBpam_fshadow\fR refuses access.
66the plain mode.
67.SH OPTIONS 68.SH OPTIONS
68.TP 69.TP
69\fBbasic\fR 70\fBbasic\fR
@@ -86,12 +87,12 @@ Use only \fBpasswd\fR file for authentication.
86.TP 87.TP
87\fBregex=\fIEXPR\fR 88\fBregex=\fIEXPR\fR
88Defines a regular expression for splitting user name into the proper 89Defines a regular expression for splitting user name into the proper
89name and authentication domain. The expression must contain two 90name and authentication domain. The expression must contain at least two
90parentesized groups. If it matches, the group 1 will be used to 91parentesized groups. If it matches, the group 1 will be used to
91extract local user name and the group 2 will select the authentication 92extract local user name and the group 2 will select the authentication
92domain. The \fBrevert\-index\fR option changes this behavior, causing 93domain. These default group indices can be changed using the
93group 1 to be used for authentication domain and group 2 for user 94\fBusername\-index\fR and \fBdomain\-index\fR options. Additionally the
94name. For example: 95\fBrevert\-index\fR option swaps the meaning of the two indices. For example:
95.RS 96.RS
96.EX 97.EX
97regex=(.*)@(.*) 98regex=(.*)@(.*)
@@ -100,9 +101,17 @@ regex=(.*)@(.*)
100 101
101This regular expression will match user names like \fBsmith@domain\fR. 102This regular expression will match user names like \fBsmith@domain\fR.
102.TP 103.TP
104\fBusername\-index=\fIN\fR
105Use \fIN\fRth parenthesized group of the regular expression as the
106user name. Default is 1.
107.TP
108\fBdomain\-index=\fIN\fR
109Use \fIN\fRth parenthesized group of the regular expression as the
110group name. Default is 2.
111.TP
103\fBrevert\-index\fR 112\fBrevert\-index\fR
104Use group #2 from the regular expression as the user name and group #1 113Swap indices of the username and domain part parenthesized groups in
105as the authentication domain. 114the regexp.
106.TP 115.TP
107\fBsysconfdir=\fIDIR\fR 116\fBsysconfdir=\fIDIR\fR
108Use \fIDIR\fR as the system configuration directory, instead of the 117Use \fIDIR\fR as the system configuration directory, instead of the
diff --git a/pam_fshadow/pam_fshadow.c b/pam_fshadow/pam_fshadow.c
index 058dd44..3dd07f5 100644
--- a/pam_fshadow/pam_fshadow.c
+++ b/pam_fshadow/pam_fshadow.c
@@ -103,15 +103,15 @@ fgetpwent(FILE *fp)
103#define CNTL_REGEX 0x0080 103#define CNTL_REGEX 0x0080
104#define CNTL_REVERT_INDEX 0x0100 104#define CNTL_REVERT_INDEX 0x0100
105 105
106char *sysconfdir = SYSCONFDIR; 106static regex_t rexp;
107static char *sysconfdir = SYSCONFDIR;
107static int cntl_flags = CNTL_PASSWD|CNTL_SHADOW; 108static int cntl_flags = CNTL_PASSWD|CNTL_SHADOW;
108static long debug_level = 0; 109static long debug_level = 0;
109 110
110static regex_t rexp;
111static const char *regex_str = NULL; 111static const char *regex_str = NULL;
112static int regex_flags = REG_EXTENDED; 112static int regex_flags = REG_EXTENDED;
113static int username_index = 1; 113static long username_index = 1;
114static int domain_index = 2; 114static long domain_index = 2;
115 115
116struct pam_opt pam_opt[] = { 116struct pam_opt pam_opt[] = {
117 { PAM_OPTSTR(debug), pam_opt_long, &debug_level }, 117 { PAM_OPTSTR(debug), pam_opt_long, &debug_level },
@@ -139,6 +139,8 @@ struct pam_opt pam_opt[] = {
139 { .value = CNTL_SHADOW } }, 139 { .value = CNTL_SHADOW } },
140 { PAM_OPTSTR(revert-index), pam_opt_bool, &cntl_flags, 140 { PAM_OPTSTR(revert-index), pam_opt_bool, &cntl_flags,
141 { .value = CNTL_REVERT_INDEX } }, 141 { .value = CNTL_REVERT_INDEX } },
142 { PAM_OPTSTR(username-index), pam_opt_long, &username_index },
143 { PAM_OPTSTR(domain-index), pam_opt_long, &domain_index },
142 { NULL } 144 { NULL }
143}; 145};
144 146
@@ -162,13 +164,23 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
162 "either passwd or shadow must be true"); 164 "either passwd or shadow must be true");
163 return PAM_AUTHINFO_UNAVAIL; 165 return PAM_AUTHINFO_UNAVAIL;
164 } 166 }
167 if (username_index <= 0) {
168 _pam_log(LOG_CRIT, "username-index out of range");
169 return PAM_AUTHINFO_UNAVAIL;
170 }
171 if (domain_index <= 0) {
172 _pam_log(LOG_CRIT, "domain-index out of range");
173 return PAM_AUTHINFO_UNAVAIL;
174 }
175
165 if (cntl_flags & CNTL_REVERT_INDEX) { 176 if (cntl_flags & CNTL_REVERT_INDEX) {
166 username_index = 2; 177 long t = username_index;
167 domain_index = 1; 178 username_index = domain_index;
179 domain_index = t;
168 } 180 }
169 if (regex_str) { 181 if (regex_str) {
170 int rc; 182 int rc;
171 if (rc = regcomp(&rexp, regex_str, regex_flags)) { 183 if ((rc = regcomp(&rexp, regex_str, regex_flags))) {
172 size_t s = regerror(rc, &rexp, NULL, 0); 184 size_t s = regerror(rc, &rexp, NULL, 0);
173 char *buf = malloc (s); 185 char *buf = malloc (s);
174 if (buf) { 186 if (buf) {
@@ -182,11 +194,16 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
182 "cannot compile regex `%s'", 194 "cannot compile regex `%s'",
183 regex_str); 195 regex_str);
184 retval = PAM_AUTHINFO_UNAVAIL; 196 retval = PAM_AUTHINFO_UNAVAIL;
185 } else if (rexp.re_nsub != 2) { 197 } else if (!(username_index <= rexp.re_nsub
186 _pam_log(LOG_NOTICE, 198 && domain_index <= rexp.re_nsub)) {
187 "invalid regular expression `%s': " 199 if (username_index > rexp.re_nsub)
188 "must contain two reference groups", 200 _pam_log(LOG_NOTICE,
189 regex_str); 201 "not enough parenthesized groups"
202 " to satisfy username-index");
203 if (domain_index > rexp.re_nsub)
204 _pam_log(LOG_NOTICE,
205 "not enough parenthesized groups"
206 " to satisfy domain-index");
190 regfree(&rexp); 207 regfree(&rexp);
191 retval = PAM_AUTHINFO_UNAVAIL; 208 retval = PAM_AUTHINFO_UNAVAIL;
192 } else 209 } else
@@ -438,11 +455,50 @@ copy_backref (pam_handle_t *pamh, const char *name,
438 455
439/* --- authentication management functions (only) --- */ 456/* --- authentication management functions (only) --- */
440 457
458static int
459translate(pam_handle_t *pamh, char const *input,
460 char **ret_username, char **ret_confdir)
461{
462 size_t nmatch = (domain_index > username_index
463 ? domain_index : username_index) + 1;
464 regmatch_t *rmatch;
465 int rc;
466
467 rmatch = calloc(nmatch, sizeof(rmatch[0]));
468 if (!rmatch) {
469 _pam_log(LOG_ERR, "out of memory");
470 return PAM_SERVICE_ERR;
471 }
472
473 if (regexec(&rexp, input, nmatch, rmatch, 0) == 0) {
474 char *domain;
475
476 if ((rc = copy_backref(pamh, "DOMAIN", input, rmatch,
477 domain_index, &domain)) == PAM_SUCCESS
478 && ((rc = copy_backref(pamh, "USERNAME", input, rmatch,
479 username_index, ret_username))
480 == PAM_SUCCESS)) {
481 *ret_confdir = mkfilename(sysconfdir, domain);
482 pam_set_data(pamh, "CONFDIR",
483 (void *)*ret_confdir, gray_cleanup_string);
484 }
485 } else {
486 DEBUG(1,("user name `%s' does not match regular "
487 "expression `%s'",
488 input,
489 regex_str));
490 rc = PAM_AUTH_ERR;
491 }
492 free(rmatch);
493 return rc;
494 }
495
441PAM_EXTERN int 496PAM_EXTERN int
442pam_sm_authenticate(pam_handle_t *pamh, int flags, 497pam_sm_authenticate(pam_handle_t *pamh, int flags,
443 int argc, const char **argv) 498 int argc, const char **argv)
444{ 499{
445 const char *username; 500 const char *input_username;
501 char *username;
446 char *password; 502 char *password;
447 int retval = PAM_AUTH_ERR; 503 int retval = PAM_AUTH_ERR;
448 int rc; 504 int rc;
@@ -455,8 +511,8 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags,
455 confdir = sysconfdir; 511 confdir = sysconfdir;
456 512
457 /* Get the username */ 513 /* Get the username */
458 retval = pam_get_user(pamh, &username, NULL); 514 retval = pam_get_user(pamh, &input_username, NULL);
459 if (retval != PAM_SUCCESS || !username) { 515 if (retval != PAM_SUCCESS || !input_username) {
460 DEBUG(1,("can not get the username")); 516 DEBUG(1,("can not get the username"));
461 if (cntl_flags & CNTL_REGEX) 517 if (cntl_flags & CNTL_REGEX)
462 regfree(&rexp); 518 regfree(&rexp);
@@ -464,39 +520,21 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags,
464 } 520 }
465 521
466 if (cntl_flags & CNTL_REGEX) { 522 if (cntl_flags & CNTL_REGEX) {
467 regmatch_t rmatch[3]; 523 retval = translate(pamh, input_username, &username, &confdir);
468 if (regexec(&rexp, username, 3, rmatch, 0) == 0) {
469 char *domain;
470
471 rc = copy_backref(pamh, "DOMAIN", username, rmatch,
472 domain_index, &domain);
473 if (rc != PAM_SUCCESS)
474 return rc;
475 rc = copy_backref(pamh, "USERNAME", username, rmatch,
476 username_index, (char **) &username);
477 if (rc != PAM_SUCCESS)
478 return rc;
479 confdir = mkfilename(sysconfdir, domain);
480 pam_set_data(pamh, "CONFDIR",
481 (void *)confdir, gray_cleanup_string);
482 } else {
483 DEBUG(1,("user name `%s' does not match regular "
484 "expression `%s'",
485 username,
486 regex_str));
487 }
488 regfree(&rexp); 524 regfree(&rexp);
525 } else {
526 retval = PAM_SUCCESS;
527 username = (char *) input_username;
528 confdir = sysconfdir;
489 } 529 }
530
531 if (retval != PAM_SUCCESS)
532 return retval;
490 533
491 /* Get the password */ 534 /* Get the password */
492 if (_pam_get_password(pamh, &password, "Password:")) 535 if (_pam_get_password(pamh, &password, "Password:"))
493 return PAM_SERVICE_ERR; 536 return PAM_SERVICE_ERR;
494 537
495 if (retval != PAM_SUCCESS) {
496 _pam_log(LOG_ERR, "Could not retrive user's password");
497 return -2;
498 }
499
500 if (cntl_flags & CNTL_PASSWD) 538 if (cntl_flags & CNTL_PASSWD)
501 retval = verify_user_acct(confdir, username, &pwstr); 539 retval = verify_user_acct(confdir, username, &pwstr);
502 else 540 else

Return to:

Send suggestions and report system problems to the System administrator.