diff options
-rw-r--r-- | doc/pam_fshadow.8in | 37 | ||||
-rw-r--r-- | pam_fshadow/pam_fshadow.c | 120 |
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,5 +1,5 @@ | |||
1 | .\" This file is part of PAM-Modules -*- nroff -*- | 1 | .\" This file is part of PAM-Modules -*- nroff -*- |
2 | .\" Copyright (C) 2001-2015 Sergey Poznyakoff | 2 | .\" Copyright (C) 2001-2017 Sergey Poznyakoff |
3 | .\" | 3 | .\" |
4 | .\" PAM-Modules is free software; you can redistribute it and/or modify | 4 | .\" PAM-Modules is free software; you can redistribute it and/or modify |
5 | .\" it under the terms of the GNU General Public License as published by | 5 | .\" it under the terms of the GNU General Public License as published by |
@@ -14,14 +14,17 @@ | |||
14 | .\" You should have received a copy of the GNU General Public License | 14 | .\" You should have received a copy of the GNU General Public License |
15 | .\" along with PAM-Modules. If not, see <http://www.gnu.org/licenses/>. | 15 | .\" along with PAM-Modules. If not, see <http://www.gnu.org/licenses/>. |
16 | .so config.so | 16 | .so config.so |
17 | .TH PAM_FSHADOW 8 "March 30, 2014" "PAM-MODULES" "Pam-Modules User Reference" | 17 | .TH PAM_FSHADOW 8 "December 22, 2017" "PAM-MODULES" "Pam-Modules User Reference" |
18 | .SH NAME | 18 | .SH NAME |
19 | pam_fshadow \- use alternative passwd and/or shadow files | 19 | pam_fshadow \- use alternative passwd and/or shadow files |
20 | .SH SYNOPSIS | 20 | .SH SYNOPSIS |
21 | .nh | 21 | .nh |
22 | .na | 22 | .na |
23 | \fBpam_fshadow\fR\ | 23 | \fBpam_fshadow\fR\ |
24 | [\fBaudit\fR]\ | ||
25 | [\fBdebug\fR[\fB=\fINUMBER\fR]]\ | ||
24 | [\fBbasic\fR|\fBextended\fR]\ | 26 | [\fBbasic\fR|\fBextended\fR]\ |
27 | [\fBdomain\-index=\fIN\fR]\ | ||
25 | [\fBignore\-case\fR|\fBicase\fR|\fBcase\fR]\ | 28 | [\fBignore\-case\fR|\fBicase\fR|\fBcase\fR]\ |
26 | [\fBnopasswd\fR]\ | 29 | [\fBnopasswd\fR]\ |
27 | [\fBnoshadow\fR]\ | 30 | [\fBnoshadow\fR]\ |
@@ -29,9 +32,8 @@ pam_fshadow \- use alternative passwd and/or shadow files | |||
29 | [\fBrevert\-index\fR]\ | 32 | [\fBrevert\-index\fR]\ |
30 | [\fBsysconfdir=\fIDIR\fR]\ | 33 | [\fBsysconfdir=\fIDIR\fR]\ |
31 | [\fBuse_authtok\fR]\ | 34 | [\fBuse_authtok\fR]\ |
32 | [\fBdebug\fR[\fB=\fINUMBER\fR]]\ | 35 | [\fBusername\-index=\fIN\fR]\ |
33 | [\fBwaitdebug\fR]\ | 36 | [\fBwaitdebug\fR] |
34 | [\fBaudit\fR] | ||
35 | .ad | 37 | .ad |
36 | .hy | 38 | .hy |
37 | .SH DESCRIPTION | 39 | .SH DESCRIPTION |
@@ -54,7 +56,7 @@ provided to disable reading of either file. E.g. if \fBnoshadow\fR is | |||
54 | given, the module will expect all authentication information to be | 56 | given, the module will expect all authentication information to be |
55 | stored in the \fBpasswd\fR file. | 57 | stored in the \fBpasswd\fR file. |
56 | .PP | 58 | .PP |
57 | The \fBvirtual domain\fR mode select the \fBpasswd\fR,\fBshadow\fR | 59 | The \fBvirtual domain\fR mode selects the \fBpasswd\fR,\fBshadow\fR |
58 | pair to use depending on the user name. To that effect, the user name | 60 | pair to use depending on the user name. To that effect, the user name |
59 | is first split into the \fBlocal\fR and \fBauthentication domain\fR | 61 | is first split into the \fBlocal\fR and \fBauthentication domain\fR |
60 | parts using a regular expression supplied with the \fBregex\fR option. | 62 | 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 | |||
62 | system configuration directory, a directory separator character (\fB/\fR), | 64 | system configuration directory, a directory separator character (\fB/\fR), |
63 | and the name of the authentication domain. The authentication then | 65 | and the name of the authentication domain. The authentication then |
64 | proceeds as described above for the plain mode. If the supplied user name | 66 | proceeds as described above for the plain mode. If the supplied user name |
65 | does not match the regular expression, \fBpam_fshadow\fR falls back to | 67 | does not match the regular expression, \fBpam_fshadow\fR refuses access. |
66 | the plain mode. | ||
67 | .SH OPTIONS | 68 | .SH OPTIONS |
68 | .TP | 69 | .TP |
69 | \fBbasic\fR | 70 | \fBbasic\fR |
@@ -86,12 +87,12 @@ Use only \fBpasswd\fR file for authentication. | |||
86 | .TP | 87 | .TP |
87 | \fBregex=\fIEXPR\fR | 88 | \fBregex=\fIEXPR\fR |
88 | Defines a regular expression for splitting user name into the proper | 89 | Defines a regular expression for splitting user name into the proper |
89 | name and authentication domain. The expression must contain two | 90 | name and authentication domain. The expression must contain at least two |
90 | parentesized groups. If it matches, the group 1 will be used to | 91 | parentesized groups. If it matches, the group 1 will be used to |
91 | extract local user name and the group 2 will select the authentication | 92 | extract local user name and the group 2 will select the authentication |
92 | domain. The \fBrevert\-index\fR option changes this behavior, causing | 93 | domain. These default group indices can be changed using the |
93 | group 1 to be used for authentication domain and group 2 for user | 94 | \fBusername\-index\fR and \fBdomain\-index\fR options. Additionally the |
94 | name. For example: | 95 | \fBrevert\-index\fR option swaps the meaning of the two indices. For example: |
95 | .RS | 96 | .RS |
96 | .EX | 97 | .EX |
97 | regex=(.*)@(.*) | 98 | regex=(.*)@(.*) |
@@ -100,9 +101,17 @@ regex=(.*)@(.*) | |||
100 | 101 | ||
101 | This regular expression will match user names like \fBsmith@domain\fR. | 102 | This regular expression will match user names like \fBsmith@domain\fR. |
102 | .TP | 103 | .TP |
104 | \fBusername\-index=\fIN\fR | ||
105 | Use \fIN\fRth parenthesized group of the regular expression as the | ||
106 | user name. Default is 1. | ||
107 | .TP | ||
108 | \fBdomain\-index=\fIN\fR | ||
109 | Use \fIN\fRth parenthesized group of the regular expression as the | ||
110 | group name. Default is 2. | ||
111 | .TP | ||
103 | \fBrevert\-index\fR | 112 | \fBrevert\-index\fR |
104 | Use group #2 from the regular expression as the user name and group #1 | 113 | Swap indices of the username and domain part parenthesized groups in |
105 | as the authentication domain. | 114 | the regexp. |
106 | .TP | 115 | .TP |
107 | \fBsysconfdir=\fIDIR\fR | 116 | \fBsysconfdir=\fIDIR\fR |
108 | Use \fIDIR\fR as the system configuration directory, instead of the | 117 | 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) | |||
103 | #define CNTL_REGEX 0x0080 | 103 | #define CNTL_REGEX 0x0080 |
104 | #define CNTL_REVERT_INDEX 0x0100 | 104 | #define CNTL_REVERT_INDEX 0x0100 |
105 | 105 | ||
106 | char *sysconfdir = SYSCONFDIR; | 106 | static regex_t rexp; |
107 | static char *sysconfdir = SYSCONFDIR; | ||
107 | static int cntl_flags = CNTL_PASSWD|CNTL_SHADOW; | 108 | static int cntl_flags = CNTL_PASSWD|CNTL_SHADOW; |
108 | static long debug_level = 0; | 109 | static long debug_level = 0; |
109 | 110 | ||
110 | static regex_t rexp; | ||
111 | static const char *regex_str = NULL; | 111 | static const char *regex_str = NULL; |
112 | static int regex_flags = REG_EXTENDED; | 112 | static int regex_flags = REG_EXTENDED; |
113 | static int username_index = 1; | 113 | static long username_index = 1; |
114 | static int domain_index = 2; | 114 | static long domain_index = 2; |
115 | 115 | ||
116 | struct pam_opt pam_opt[] = { | 116 | struct pam_opt pam_opt[] = { |
117 | { PAM_OPTSTR(debug), pam_opt_long, &debug_level }, | 117 | { PAM_OPTSTR(debug), pam_opt_long, &debug_level }, |
@@ -139,6 +139,8 @@ struct pam_opt pam_opt[] = { | |||
139 | { .value = CNTL_SHADOW } }, | 139 | { .value = CNTL_SHADOW } }, |
140 | { PAM_OPTSTR(revert-index), pam_opt_bool, &cntl_flags, | 140 | { PAM_OPTSTR(revert-index), pam_opt_bool, &cntl_flags, |
141 | { .value = CNTL_REVERT_INDEX } }, | 141 | { .value = CNTL_REVERT_INDEX } }, |
142 | { PAM_OPTSTR(username-index), pam_opt_long, &username_index }, | ||
143 | { PAM_OPTSTR(domain-index), pam_opt_long, &domain_index }, | ||
142 | { NULL } | 144 | { NULL } |
143 | }; | 145 | }; |
144 | 146 | ||
@@ -162,13 +164,23 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) | |||
162 | "either passwd or shadow must be true"); | 164 | "either passwd or shadow must be true"); |
163 | return PAM_AUTHINFO_UNAVAIL; | 165 | return PAM_AUTHINFO_UNAVAIL; |
164 | } | 166 | } |
167 | if (username_index <= 0) { | ||
168 | _pam_log(LOG_CRIT, "username-index out of range"); | ||
169 | return PAM_AUTHINFO_UNAVAIL; | ||
170 | } | ||
171 | if (domain_index <= 0) { | ||
172 | _pam_log(LOG_CRIT, "domain-index out of range"); | ||
173 | return PAM_AUTHINFO_UNAVAIL; | ||
174 | } | ||
175 | |||
165 | if (cntl_flags & CNTL_REVERT_INDEX) { | 176 | if (cntl_flags & CNTL_REVERT_INDEX) { |
166 | username_index = 2; | 177 | long t = username_index; |
167 | domain_index = 1; | 178 | username_index = domain_index; |
179 | domain_index = t; | ||
168 | } | 180 | } |
169 | if (regex_str) { | 181 | if (regex_str) { |
170 | int rc; | 182 | int rc; |
171 | if (rc = regcomp(&rexp, regex_str, regex_flags)) { | 183 | if ((rc = regcomp(&rexp, regex_str, regex_flags))) { |
172 | size_t s = regerror(rc, &rexp, NULL, 0); | 184 | size_t s = regerror(rc, &rexp, NULL, 0); |
173 | char *buf = malloc (s); | 185 | char *buf = malloc (s); |
174 | if (buf) { | 186 | if (buf) { |
@@ -182,11 +194,16 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) | |||
182 | "cannot compile regex `%s'", | 194 | "cannot compile regex `%s'", |
183 | regex_str); | 195 | regex_str); |
184 | retval = PAM_AUTHINFO_UNAVAIL; | 196 | retval = PAM_AUTHINFO_UNAVAIL; |
185 | } else if (rexp.re_nsub != 2) { | 197 | } else if (!(username_index <= rexp.re_nsub |
186 | _pam_log(LOG_NOTICE, | 198 | && domain_index <= rexp.re_nsub)) { |
187 | "invalid regular expression `%s': " | 199 | if (username_index > rexp.re_nsub) |
188 | "must contain two reference groups", | 200 | _pam_log(LOG_NOTICE, |
189 | regex_str); | 201 | "not enough parenthesized groups" |
202 | " to satisfy username-index"); | ||
203 | if (domain_index > rexp.re_nsub) | ||
204 | _pam_log(LOG_NOTICE, | ||
205 | "not enough parenthesized groups" | ||
206 | " to satisfy domain-index"); | ||
190 | regfree(&rexp); | 207 | regfree(&rexp); |
191 | retval = PAM_AUTHINFO_UNAVAIL; | 208 | retval = PAM_AUTHINFO_UNAVAIL; |
192 | } else | 209 | } else |
@@ -438,11 +455,50 @@ copy_backref (pam_handle_t *pamh, const char *name, | |||
438 | 455 | ||
439 | /* --- authentication management functions (only) --- */ | 456 | /* --- authentication management functions (only) --- */ |
440 | 457 | ||
458 | static int | ||
459 | translate(pam_handle_t *pamh, char const *input, | ||
460 | char **ret_username, char **ret_confdir) | ||
461 | { | ||
462 | size_t nmatch = (domain_index > username_index | ||
463 | ? domain_index : username_index) + 1; | ||