1 |
This message is fairly long, however I've decided to pass it along in the hope |
2 |
that someone may find it useful as a reference source. It was originally |
3 |
intended to be a problem description and debugging request for the gnomes to |
4 |
ponder over. |
5 |
|
6 |
|
7 |
I've recently encountered an interesting debugging paradox. Upon deploying |
8 |
Subversion with an Apache-based server, I discovered an interesting issue |
9 |
with PAM that seems to be intent on defying explanation: |
10 |
|
11 |
I have a repository that's accessible through <https://svn.domain.com/>, with |
12 |
the repository root set at location / (using Subversion 1.2.0, which has a |
13 |
fix for the cache bug that prevented repositories from being located at the |
14 |
root of a web address). The server is setup to allow read-only access to the |
15 |
repository through unencrypted HTTP connections, while write operations must |
16 |
use HTTPS (TLSv1, AES256). |
17 |
|
18 |
When accessing the repository through HTTPS, Apache dispatches an |
19 |
authorization request to mod_auth_pam and PAM, which in turn passes the |
20 |
request off as follows: |
21 |
|
22 |
The username and password authentication (auth) process is passed to pam_krb5 |
23 |
and the accompanying KDC. This process works flawlessly on every service, |
24 |
including Apache's requests. The logs indicate successful logins when |
25 |
submitting a username and password via web request. |
26 |
|
27 |
The account management (account) process is passed to pam_unix, which then |
28 |
does a bit of nsswitch magic to tie everything together. In this context, |
29 |
only network-based user accounts are permitted, therefore nsswitch uses the |
30 |
NSVS (MySQL backend) service to retrieve all of the information. For example, |
31 |
calls to getspnam are handled as follows: |
32 |
|
33 |
getspnam \ |
34 |
SELECT \ |
35 |
'%1$s','x',1,0,99999,7,0,DATEDIFF(expiration_date,'1970-01-01'),0 \ |
36 |
FROM users \ |
37 |
WHERE username='%1$s' \ |
38 |
LIMIT 1 |
39 |
|
40 |
Herein lies the problem. During the authorization process, PAM will fail |
41 |
during the account stage with the error: "PAM: user 'agorecki' - invalid |
42 |
account: Authentication service cannot retrieve authentication info." |
43 |
|
44 |
For whatever reason, the debug and audit flags in the pam_unix module are not |
45 |
functional. As a result, I extracted the information I needed directly from |
46 |
the source code, and found the error location to be: |
47 |
|
48 |
./Linux-PAM-0.78/modules/pam_unix/pam_unix_acct.c: |
49 |
127 spent = _pammodutil_getspnam (pamh, uname); |
50 |
128 else |
51 |
129 return PAM_SUCCESS; |
52 |
130 |
53 |
131 if (!spent) |
54 |
132 if (on(UNIX_BROKEN_SHADOW,ctrl)) |
55 |
133 return PAM_SUCCESS; |
56 |
134 |
57 |
135 if (!spent) |
58 |
136 return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from |
59 |
shadow */ |
60 |
|
61 |
The call on line 127 takes place, and the error originates on line 136. |
62 |
|
63 |
For the purposes of debugging, I've removed all chroot restrictions from |
64 |
Apache and have given it complete access to the filesystem. The Apache |
65 |
Subversion interface works through the unencrypted connections, which do not |
66 |
require authentication. |
67 |
|
68 |
Hours of Google searching turned up nothing of use; what I don't understand is |
69 |
how Apache can fail to retrieve the shadow information when it's accessible |
70 |
by any unprivileged-- |
71 |
|
72 |
While writing the above, it occurred to me to run a final check on the debug |
73 |
output of nsvsd, which produced: |
74 |
|
75 |
run_query: query: SELECT 'agorecki','x',user_id,group_id,CONCAT(first_name,' |
76 |
',last_name),CONCAT('/home/',username),'/bin/bash' FROM users WHERE |
77 |
username='agorecki' AND group_id IS NOT NULL LIMIT 1 |
78 |
send_response: sending 120-byte response |
79 |
main_loop: pid 12314 unauthorized for type 8 |
80 |
main_loop: pid 12314 unauthorized for type 8 |
81 |
|
82 |
The obligatory check of the code found: |
83 |
|
84 |
./nsvs/src/nsvsd/nsvsd.c: |
85 |
449 /* |
86 |
450 * Don't allow shadow queries to non-root users |
87 |
451 * It is CRITICAL that this code occurs AFTER reading the |
88 |
key |
89 |
452 * to avoid clientside sigpipe issues |
90 |
453 */ |
91 |
454 if ((req.type == GETSPBYNAME || req.type == GETSP) && |
92 |
caller.uid != 0) |
93 |
455 { |
94 |
456 nsvs_log (LOG_DEBUG, "%s: pid %d unauthorized for type |
95 |
%d", |
96 |
457 __FUNCTION__, caller.pid, req.type); |
97 |
|
98 |
|
99 |
Having non-root users access the shadow-emulated MySQL information is of no |
100 |
consequence to me as I don't use that system for password storage, however |
101 |
I'd prefer not to start patching software to work around the above |
102 |
restriction. |
103 |
|
104 |
Having wasted forty-five minutes typing the above only to find the cause of |
105 |
the problem that was illuding me, I'm left with the next problem: |
106 |
|
107 |
My network authentication scheme cannot solely rely on Kerberos' built-in |
108 |
account expiration and suspension system, because a user could still login |
109 |
through SSH using a certificate. As a result, I've tied the entire system's |
110 |
account expiration process into the emulated shadow suite so that I can |
111 |
expire all access simply by changing the expiration date of the account in |
112 |
the MySQL database. Consequently, I can't use the broken_shadow option of |
113 |
pam_unix to get around the problem that way, otherwise I wouldn't be able to |
114 |
keep someone from modifying the repository without deleting their account or |
115 |
changing the account's password. |
116 |
|
117 |
Therefore, the only viable option would seem to be to use mod_auth_external |
118 |
and an authentication binary to serve as an intermediary between PAM and |
119 |
Apache. Unfortunately, that process would be considerably slower than calling |
120 |
the PAM functions directly or through a library. I also don't see a SASL |
121 |
module for a Apache. |
122 |
|
123 |
Does anyone have a suggestion that would fit the requirements, other than |
124 |
using mod_auth_external, coupled with an authentication program? An interface |
125 |
to Cyrus-SASL would be ideal since I already have saslauthd running for |
126 |
Postfix. |
127 |
|
128 |
In addition, does anyone have an idea as to what authentication program could |
129 |
be used as the aforementioned intermediary? |
130 |
|
131 |
Thanks. |
132 |
|
133 |
|
134 |
-- |
135 |
Anthony Gorecki |
136 |
Ectro-Linux Foundation |