mirror of
git://git.gnu.org.ua/pam-modules.git
synced 2025-04-26 00:19:52 +03:00
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.
This commit is contained in:
parent
fc8bf4028f
commit
55620228a8
2 changed files with 102 additions and 55 deletions
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
_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
|
||||
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue