aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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,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)

Return to:

Send suggestions and report system problems to the System administrator.