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,8 +1,8 @@
.\" 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
.\" the Free Software Foundation; either version 3, or (at your option)
.\" any later version.
.\"
@@ -11,30 +11,32 @@
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" 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]\
[\fBregex=\fIEXPR\fR]\
[\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
Authenticates the user against alternative \fBpasswd\fR and
\fBshadow\fR files. There are two operation modes:
\fBplain\fR mode, in which the module uses only
@@ -51,22 +53,21 @@ parameter.
.PP
The command line options \fBnopasswd\fR and \fBnoshadow\fR are
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.
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
The argument to the \fBregex\fR option is a basic regular expression.
.TP
\fBextended\fR
@@ -83,29 +84,37 @@ Use only \fBshadow\fR file for authentication.
.TP
\fBnoshadow\fR
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=(.*)@(.*)
.EE
.RE
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
default \fB\*(ET\fR.
.TP
\fBuse_authtok\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
@@ -100,21 +100,21 @@ fgetpwent(FILE *fp)
#define CNTL_AUTHTOK 0x0010
#define CNTL_PASSWD 0x0020
#define CNTL_SHADOW 0x0040
#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 },
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, { 1 } },
{ PAM_OPTSTR(audit), pam_opt_const, &debug_level, { 100 } },
{ PAM_OPTSTR(waitdebug), pam_opt_null, NULL, { 0 },
@@ -136,12 +136,14 @@ struct pam_opt pam_opt[] = {
{ PAM_OPTSTR(passwd), pam_opt_bool, &cntl_flags,
{ .value = CNTL_PASSWD } },
{ PAM_OPTSTR(shadow), pam_opt_bool, &cntl_flags,
{ .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 }
};
static int
_pam_parse(pam_handle_t *pamh, int argc, const char **argv)
{
@@ -159,19 +161,29 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
if ((cntl_flags & (CNTL_PASSWD|CNTL_SHADOW)) == 0) {
_pam_log(LOG_CRIT,
"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) {
regerror(rc, &rexp, buf, s);
_pam_log(LOG_NOTICE,
"cannot compile regex `%s': %s",
@@ -179,17 +191,22 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv)
free (buf);
} else
_pam_log(LOG_NOTICE,
"cannot compile regex `%s'",
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;
} else
cntl_flags |= CNTL_REGEX;
}
@@ -435,71 +452,92 @@ copy_backref (pam_handle_t *pamh, const char *name,
}
return rc;
}
/* --- 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;
char *confdir;
char *pwstr = NULL;
/* parse arguments */
if ((rc = _pam_parse(pamh, argc, argv)) != PAM_SUCCESS)
return rc;
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);
return PAM_SERVICE_ERR;
}
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
retval = PAM_SUCCESS;
if (retval == PAM_SUCCESS) {
if (pwstr) {

Return to:

Send suggestions and report system problems to the System administrator.