aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-12-22 15:22:14 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2017-12-22 15:25:58 +0200
commit55620228a87786860e5eeabbab146a835e9830cf (patch)
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.
-rw-r--r--doc/pam_fshadow.8in37
-rw-r--r--pam_fshadow/pam_fshadow.c118
2 files changed, 101 insertions, 54 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 @@
.\" 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
.\" it under the terms of the GNU General Public License as published by
@@ -14,14 +14,17 @@
.\" You should have received a copy of the GNU General Public License
.\" 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
.SH SYNOPSIS
.nh
.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]\
[\fBnoshadow\fR]\
@@ -29,9 +32,8 @@ pam_fshadow \- use alternative passwd and/or shadow files
[\fBrevert\-index\fR]\
[\fBsysconfdir=\fIDIR\fR]\
[\fBuse_authtok\fR]\
- [\fBdebug\fR[\fB=\fINUMBER\fR]]\
- [\fBwaitdebug\fR]\
- [\fBaudit\fR]
+ [\fBusername\-index=\fIN\fR]\
+ [\fBwaitdebug\fR]
.ad
.hy
.SH DESCRIPTION
@@ -54,7 +56,7 @@ provided to disable reading of either file. E.g. if \fBnoshadow\fR is
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
parts using a regular expression supplied with the \fBregex\fR option.
@@ -62,8 +64,7 @@ The configuration directory name is then constructed by concatenating the
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
\fBbasic\fR
@@ -86,12 +87,12 @@ Use only \fBpasswd\fR file for authentication.
.TP
\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
regex=(.*)@(.*)
@@ -100,9 +101,17 @@ 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
Use \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)
#define CNTL_REGEX 0x0080
#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[] = {
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
@@ -139,6 +139,8 @@ struct pam_opt pam_opt[] = {
{ .value = CNTL_SHADOW } },
{ 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 }
};
@@ -162,13 +164,23 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
"either passwd or shadow must be true");
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);
if (buf) {
@@ -182,11 +194,16 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
"cannot compile regex `%s'",
regex_str);
retval = PAM_AUTHINFO_UNAVAIL;
- } else if (rexp.re_nsub != 2) {
+ } else if (!(username_index <= rexp.re_nsub
+ && domain_index <= rexp.re_nsub)) {
+ if (username_index > rexp.re_nsub)
_pam_log(LOG_NOTICE,
- "invalid regular expression `%s': "
- "must contain two reference groups",
- regex_str);
+ "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;
} else
@@ -438,11 +455,50 @@ 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;
int rc;
@@ -455,8 +511,8 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags,
confdir = sysconfdir;
/* 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)
regfree(&rexp);
@@ -464,39 +520,21 @@ 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 */
if (_pam_get_password(pamh, &password, "Password:"))
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);
else

Return to:

Send suggestions and report system problems to the System administrator.