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.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,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);

Return to:

Send suggestions and report system problems to the System administrator.