diff options
-rw-r--r-- | doc/pam_fshadow.8in | 37 | ||||
-rw-r--r-- | pam_fshadow/pam_fshadow.c | 120 |
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,3 +1,3 @@ .\" This file is part of PAM-Modules -*- nroff -*- -.\" Copyright (C) 2001-2015 Sergey Poznyakoff +.\" Copyright (C) 2001-2017 Sergey Poznyakoff .\" @@ -16,3 +16,3 @@ .so config.so -.TH PAM_FSHADOW 8 "March 30, 2014" "PAM-MODULES" "Pam-Modules User Reference" +.TH PAM_FSHADOW 8 "December 22, 2017" "PAM-MODULES" "Pam-Modules User Reference" .SH NAME @@ -23,3 +23,6 @@ pam_fshadow \- use alternative passwd and/or shadow files \fBpam_fshadow\fR\ + [\fBaudit\fR]\ + [\fBdebug\fR[\fB=\fINUMBER\fR]]\ [\fBbasic\fR|\fBextended\fR]\ + [\fBdomain\-index=\fIN\fR]\ [\fBignore\-case\fR|\fBicase\fR|\fBcase\fR]\ @@ -31,5 +34,4 @@ pam_fshadow \- use alternative passwd and/or shadow files [\fBuse_authtok\fR]\ - [\fBdebug\fR[\fB=\fINUMBER\fR]]\ - [\fBwaitdebug\fR]\ - [\fBaudit\fR] + [\fBusername\-index=\fIN\fR]\ + [\fBwaitdebug\fR] .ad @@ -56,3 +58,3 @@ stored in the \fBpasswd\fR file. .PP -The \fBvirtual domain\fR mode select the \fBpasswd\fR,\fBshadow\fR +The \fBvirtual domain\fR mode selects the \fBpasswd\fR,\fBshadow\fR pair to use depending on the user name. To that effect, the user name @@ -64,4 +66,3 @@ and the name of the authentication domain. The authentication then proceeds as described above for the plain mode. If the supplied user name -does not match the regular expression, \fBpam_fshadow\fR falls back to -the plain mode. +does not match the regular expression, \fBpam_fshadow\fR refuses access. .SH OPTIONS @@ -88,8 +89,8 @@ Use only \fBpasswd\fR file for authentication. Defines a regular expression for splitting user name into the proper -name and authentication domain. The expression must contain two +name and authentication domain. The expression must contain at least two parentesized groups. If it matches, the group 1 will be used to extract local user name and the group 2 will select the authentication -domain. The \fBrevert\-index\fR option changes this behavior, causing -group 1 to be used for authentication domain and group 2 for user -name. For example: +domain. These default group indices can be changed using the +\fBusername\-index\fR and \fBdomain\-index\fR options. Additionally the +\fBrevert\-index\fR option swaps the meaning of the two indices. For example: .RS @@ -102,5 +103,13 @@ This regular expression will match user names like \fBsmith@domain\fR. .TP +\fBusername\-index=\fIN\fR +Use \fIN\fRth parenthesized group of the regular expression as the +user name. Default is 1. +.TP +\fBdomain\-index=\fIN\fR +Use \fIN\fRth parenthesized group of the regular expression as the +group name. Default is 2. +.TP \fBrevert\-index\fR -Use group #2 from the regular expression as the user name and group #1 -as the authentication domain. +Swap indices of the username and domain part parenthesized groups in +the regexp. .TP 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 @@ -105,3 +105,4 @@ fgetpwent(FILE *fp) -char *sysconfdir = SYSCONFDIR; +static regex_t rexp; +static char *sysconfdir = SYSCONFDIR; static int cntl_flags = CNTL_PASSWD|CNTL_SHADOW; @@ -109,7 +110,6 @@ static long debug_level = 0; -static regex_t rexp; static const char *regex_str = NULL; static int regex_flags = REG_EXTENDED; -static int username_index = 1; -static int domain_index = 2; +static long username_index = 1; +static long domain_index = 2; @@ -141,2 +141,4 @@ struct pam_opt pam_opt[] = { { .value = CNTL_REVERT_INDEX } }, + { PAM_OPTSTR(username-index), pam_opt_long, &username_index }, + { PAM_OPTSTR(domain-index), pam_opt_long, &domain_index }, { NULL } @@ -164,5 +166,15 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) } + if (username_index <= 0) { + _pam_log(LOG_CRIT, "username-index out of range"); + return PAM_AUTHINFO_UNAVAIL; + } + if (domain_index <= 0) { + _pam_log(LOG_CRIT, "domain-index out of range"); + return PAM_AUTHINFO_UNAVAIL; + } + if (cntl_flags & CNTL_REVERT_INDEX) { - username_index = 2; - domain_index = 1; + long t = username_index; + username_index = domain_index; + domain_index = t; } @@ -170,3 +182,3 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) int rc; - if (rc = regcomp(&rexp, regex_str, regex_flags)) { + if ((rc = regcomp(&rexp, regex_str, regex_flags))) { size_t s = regerror(rc, &rexp, NULL, 0); @@ -184,7 +196,12 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) retval = PAM_AUTHINFO_UNAVAIL; - } else if (rexp.re_nsub != 2) { - _pam_log(LOG_NOTICE, - "invalid regular expression `%s': " - "must contain two reference groups", - regex_str); + } else if (!(username_index <= rexp.re_nsub + && domain_index <= rexp.re_nsub)) { + if (username_index > rexp.re_nsub) + _pam_log(LOG_NOTICE, + "not enough parenthesized groups" + " to satisfy username-index"); + if (domain_index > rexp.re_nsub) + _pam_log(LOG_NOTICE, + "not enough parenthesized groups" + " to satisfy domain-index"); regfree(&rexp); @@ -440,2 +457,40 @@ copy_backref (pam_handle_t *pamh, const char *name, +static int +translate(pam_handle_t *pamh, char const *input, + char **ret_username, char **ret_confdir) +{ + size_t nmatch = (domain_index > username_index + ? domain_index : username_index) + 1; + regmatch_t *rmatch; + int rc; + + rmatch = calloc(nmatch, sizeof(rmatch[0])); + if (!rmatch) { + _pam_log(LOG_ERR, "out of memory"); + return PAM_SERVICE_ERR; + } + + if (regexec(&rexp, input, nmatch, rmatch, 0) == 0) { + char *domain; + + if ((rc = copy_backref(pamh, "DOMAIN", input, rmatch, + domain_index, &domain)) == PAM_SUCCESS + && ((rc = copy_backref(pamh, "USERNAME", input, rmatch, + username_index, ret_username)) + == PAM_SUCCESS)) { + *ret_confdir = mkfilename(sysconfdir, domain); + pam_set_data(pamh, "CONFDIR", + (void *)*ret_confdir, gray_cleanup_string); + } + } else { + DEBUG(1,("user name `%s' does not match regular " + "expression `%s'", + input, + regex_str)); + rc = PAM_AUTH_ERR; + } + free(rmatch); + return rc; +} + PAM_EXTERN int @@ -444,3 +499,4 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, { - const char *username; + const char *input_username; + char *username; char *password; @@ -457,4 +513,4 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, /* Get the username */ - retval = pam_get_user(pamh, &username, NULL); - if (retval != PAM_SUCCESS || !username) { + retval = pam_get_user(pamh, &input_username, NULL); + if (retval != PAM_SUCCESS || !input_username) { DEBUG(1,("can not get the username")); @@ -466,25 +522,12 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, if (cntl_flags & CNTL_REGEX) { - regmatch_t rmatch[3]; - if (regexec(&rexp, username, 3, rmatch, 0) == 0) { - char *domain; - - rc = copy_backref(pamh, "DOMAIN", username, rmatch, - domain_index, &domain); - if (rc != PAM_SUCCESS) - return rc; - rc = copy_backref(pamh, "USERNAME", username, rmatch, - username_index, (char **) &username); - if (rc != PAM_SUCCESS) - return rc; - confdir = mkfilename(sysconfdir, domain); - pam_set_data(pamh, "CONFDIR", - (void *)confdir, gray_cleanup_string); - } else { - DEBUG(1,("user name `%s' does not match regular " - "expression `%s'", - username, - regex_str)); - } + retval = translate(pamh, input_username, &username, &confdir); regfree(&rexp); + } else { + retval = PAM_SUCCESS; + username = (char *) input_username; + confdir = sysconfdir; } + + if (retval != PAM_SUCCESS) + return retval; @@ -494,7 +537,2 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR, "Could not retrive user's password"); - return -2; - } - if (cntl_flags & CNTL_PASSWD) |