diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-12-22 15:22:14 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-12-22 15:25:58 +0200 |
commit | 55620228a87786860e5eeabbab146a835e9830cf (patch) | |
tree | 3692518804feccff77aae50cf1ea3614ccb639be | |
parent | fc8bf4028f468848ab00efb41e6c2a76be2174c9 (diff) | |
download | pam-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.
-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,4 +1,4 @@ .\" This file is part of PAM-Modules -*- nroff -*- -.\" Copyright (C) 2001-2015 Sergey Poznyakoff +.\" Copyright (C) 2001-2017 Sergey Poznyakoff .\" .\" PAM-Modules is free software; you can redistribute it and/or modify @@ -15,5 +15,5 @@ .\" along with PAM-Modules. If not, see <http://www.gnu.org/licenses/>. .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 pam_fshadow \- use alternative passwd and/or shadow files @@ -22,5 +22,8 @@ pam_fshadow \- use alternative passwd and/or shadow files .na \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]\ [\fBnopasswd\fR]\ @@ -30,7 +33,6 @@ pam_fshadow \- use alternative passwd and/or shadow files [\fBsysconfdir=\fIDIR\fR]\ [\fBuse_authtok\fR]\ - [\fBdebug\fR[\fB=\fINUMBER\fR]]\ - [\fBwaitdebug\fR]\ - [\fBaudit\fR] + [\fBusername\-index=\fIN\fR]\ + [\fBwaitdebug\fR] .ad .hy @@ -55,5 +57,5 @@ given, the module will expect all authentication information to be 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 is first split into the \fBlocal\fR and \fBauthentication domain\fR @@ -63,6 +65,5 @@ system configuration directory, a directory separator character (\fB/\fR), 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 .TP @@ -87,10 +88,10 @@ Use only \fBpasswd\fR file for authentication. \fBregex=\fIEXPR\fR 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 .EX @@ -101,7 +102,15 @@ regex=(.*)@(.*) 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 \fBsysconfdir=\fIDIR\fR 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 @@ -104,13 +104,13 @@ fgetpwent(FILE *fp) #define CNTL_REVERT_INDEX 0x0100 -char *sysconfdir = SYSCONFDIR; +static regex_t rexp; +static char *sysconfdir = SYSCONFDIR; static int cntl_flags = CNTL_PASSWD|CNTL_SHADOW; 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; struct pam_opt pam_opt[] = { @@ -140,4 +140,6 @@ struct pam_opt pam_opt[] = { { PAM_OPTSTR(revert-index), pam_opt_bool, &cntl_flags, { .value = CNTL_REVERT_INDEX } }, + { PAM_OPTSTR(username-index), pam_opt_long, &username_index }, + { PAM_OPTSTR(domain-index), pam_opt_long, &domain_index }, { NULL } }; @@ -163,11 +165,21 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) return PAM_AUTHINFO_UNAVAIL; } + 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; } if (regex_str) { 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); char *buf = malloc (s); @@ -183,9 +195,14 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) regex_str); 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); retval = PAM_AUTHINFO_UNAVAIL; @@ -439,9 +456,48 @@ copy_backref (pam_handle_t *pamh, const char *name, /* --- authentication management functions (only) --- */ +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 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { - const char *username; + const char *input_username; + char *username; char *password; int retval = PAM_AUTH_ERR; @@ -456,6 +512,6 @@ 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")); if (cntl_flags & CNTL_REGEX) @@ -465,27 +521,14 @@ 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; /* Get the password */ @@ -493,9 +536,4 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, return PAM_SERVICE_ERR; - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR, "Could not retrive user's password"); - return -2; - } - if (cntl_flags & CNTL_PASSWD) retval = verify_user_acct(confdir, username, &pwstr); |