/src/samba/source3/auth/pass_check.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Password checking |
4 | | Copyright (C) Andrew Tridgell 1992-1998 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | /* this module is for checking a username/password against a system |
21 | | password database. The SMB encrypted password support is elsewhere */ |
22 | | |
23 | | #include "includes.h" |
24 | | #include "system/passwd.h" |
25 | | #include "auth.h" |
26 | | |
27 | | #undef DBGC_CLASS |
28 | 0 | #define DBGC_CLASS DBGC_AUTH |
29 | | |
30 | | #if !defined(WITH_PAM) |
31 | | static char *ths_salt; |
32 | | /* This must be writable. */ |
33 | | static char *get_this_salt(void) |
34 | | { |
35 | | return ths_salt; |
36 | | } |
37 | | |
38 | | /* We may be setting a modified version of the same |
39 | | * string, so don't free before use. */ |
40 | | |
41 | | static const char *set_this_salt(const char *newsalt) |
42 | | { |
43 | | char *orig_salt = ths_salt; |
44 | | ths_salt = SMB_STRDUP(newsalt); |
45 | | SAFE_FREE(orig_salt); |
46 | | return ths_salt; |
47 | | } |
48 | | |
49 | | static char *ths_crypted; |
50 | | static const char *get_this_crypted(void) |
51 | | { |
52 | | if (!ths_crypted) { |
53 | | return ""; |
54 | | } |
55 | | return ths_crypted; |
56 | | } |
57 | | |
58 | | static const char *set_this_crypted(const char *newcrypted) |
59 | | { |
60 | | char *orig_crypted = ths_crypted; |
61 | | ths_crypted = SMB_STRDUP(newcrypted); |
62 | | SAFE_FREE(orig_crypted); |
63 | | return ths_crypted; |
64 | | } |
65 | | #endif |
66 | | |
67 | | |
68 | | |
69 | | |
70 | | |
71 | | |
72 | | |
73 | | /**************************************************************************** |
74 | | core of password checking routine |
75 | | ****************************************************************************/ |
76 | | static NTSTATUS password_check(const char *user, const char *password, const void *private_data) |
77 | 0 | { |
78 | 0 | #ifdef WITH_PAM |
79 | 0 | const char *rhost = (const char *)private_data; |
80 | 0 | return smb_pam_passcheck(user, rhost, password); |
81 | | #else |
82 | | |
83 | | bool ret; |
84 | | |
85 | | |
86 | | |
87 | | |
88 | | #ifdef ULTRIX_AUTH |
89 | | ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0); |
90 | | if (ret) { |
91 | | return NT_STATUS_OK; |
92 | | } else { |
93 | | return NT_STATUS_WRONG_PASSWORD; |
94 | | } |
95 | | |
96 | | #endif /* ULTRIX_AUTH */ |
97 | | |
98 | | |
99 | | |
100 | | #ifdef HAVE_BIGCRYPT |
101 | | ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0); |
102 | | if (ret) { |
103 | | return NT_STATUS_OK; |
104 | | } else { |
105 | | return NT_STATUS_WRONG_PASSWORD; |
106 | | } |
107 | | #endif /* HAVE_BIGCRYPT */ |
108 | | |
109 | | #ifndef HAVE_CRYPT |
110 | | DEBUG(1, ("Warning - no crypt available\n")); |
111 | | return NT_STATUS_LOGON_FAILURE; |
112 | | #else /* HAVE_CRYPT */ |
113 | | ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0); |
114 | | if (ret) { |
115 | | return NT_STATUS_OK; |
116 | | } else { |
117 | | return NT_STATUS_WRONG_PASSWORD; |
118 | | } |
119 | | #endif /* HAVE_CRYPT */ |
120 | | #endif /* WITH_PAM */ |
121 | 0 | } |
122 | | |
123 | | |
124 | | |
125 | | /**************************************************************************** |
126 | | CHECK if a username/password is OK |
127 | | the function pointer fn() points to a function to call when a successful |
128 | | match is found and is used to update the encrypted password file |
129 | | return NT_STATUS_OK on correct match, appropriate error otherwise |
130 | | ****************************************************************************/ |
131 | | |
132 | | NTSTATUS pass_check(const struct passwd *pass, |
133 | | const char *user, |
134 | | const char *rhost, |
135 | | const char *password, |
136 | | bool run_cracker) |
137 | 0 | { |
138 | 0 | char *pass2 = NULL; |
139 | |
|
140 | 0 | NTSTATUS nt_status; |
141 | |
|
142 | 0 | #ifdef DEBUG_PASSWORD |
143 | 0 | DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password)); |
144 | 0 | #endif |
145 | |
|
146 | 0 | if (!password) |
147 | 0 | return NT_STATUS_LOGON_FAILURE; |
148 | | |
149 | 0 | if ((!*password) && !lp_null_passwords()) |
150 | 0 | return NT_STATUS_LOGON_FAILURE; |
151 | | |
152 | 0 | #if defined(WITH_PAM) |
153 | | |
154 | | /* |
155 | | * If we're using PAM we want to short-circuit all the |
156 | | * checks below and dive straight into the PAM code. |
157 | | */ |
158 | | |
159 | 0 | DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user)); |
160 | |
|
161 | | #else /* Not using PAM */ |
162 | | |
163 | | DEBUG(4, ("pass_check: Checking password for user %s\n", user)); |
164 | | |
165 | | if (!pass) { |
166 | | DEBUG(3, ("Couldn't find user %s\n", user)); |
167 | | return NT_STATUS_NO_SUCH_USER; |
168 | | } |
169 | | |
170 | | |
171 | | /* Copy into global for the convenience of looping code */ |
172 | | /* Also the place to keep the 'password' no matter what |
173 | | crazy struct it started in... */ |
174 | | if (set_this_crypted(pass->pw_passwd) == NULL) { |
175 | | return NT_STATUS_NO_MEMORY; |
176 | | } |
177 | | if (set_this_salt(pass->pw_passwd) == NULL) { |
178 | | return NT_STATUS_NO_MEMORY; |
179 | | } |
180 | | |
181 | | #ifdef HAVE_GETSPNAM |
182 | | { |
183 | | struct spwd *spass; |
184 | | |
185 | | /* many shadow systems require you to be root to get |
186 | | the password, in most cases this should already be |
187 | | the case when this function is called, except |
188 | | perhaps for IPC password changing requests */ |
189 | | |
190 | | spass = getspnam(pass->pw_name); |
191 | | if (spass && spass->sp_pwdp) { |
192 | | if (set_this_crypted(spass->sp_pwdp) == NULL) { |
193 | | return NT_STATUS_NO_MEMORY; |
194 | | } |
195 | | if (set_this_salt(spass->sp_pwdp) == NULL) { |
196 | | return NT_STATUS_NO_MEMORY; |
197 | | } |
198 | | } |
199 | | } |
200 | | #elif defined(IA_UINFO) |
201 | | { |
202 | | /* Need to get password with SVR4.2's ia_ functions |
203 | | instead of get{sp,pw}ent functions. Required by |
204 | | UnixWare 2.x, tested on version |
205 | | 2.1. (tangent@cyberport.com) */ |
206 | | uinfo_t uinfo; |
207 | | if (ia_openinfo(pass->pw_name, &uinfo) != -1) |
208 | | ia_get_logpwd(uinfo, &(pass->pw_passwd)); |
209 | | } |
210 | | #endif |
211 | | |
212 | | |
213 | | #ifdef HAVE_GETPWANAM |
214 | | { |
215 | | struct passwd_adjunct *pwret; |
216 | | pwret = getpwanam(s); |
217 | | if (pwret && pwret->pwa_passwd) { |
218 | | if (set_this_crypted(pwret->pwa_passwd) == NULL) { |
219 | | return NT_STATUS_NO_MEMORY; |
220 | | } |
221 | | } |
222 | | } |
223 | | #endif |
224 | | |
225 | | |
226 | | #ifdef ULTRIX_AUTH |
227 | | { |
228 | | AUTHORIZATION *ap = getauthuid(pass->pw_uid); |
229 | | if (ap) { |
230 | | if (set_this_crypted(ap->a_password) == NULL) { |
231 | | endauthent(); |
232 | | return NT_STATUS_NO_MEMORY; |
233 | | } |
234 | | endauthent(); |
235 | | } |
236 | | } |
237 | | #endif |
238 | | |
239 | | |
240 | | if (!get_this_crypted() || !*get_this_crypted()) { |
241 | | if (!lp_null_passwords()) { |
242 | | DEBUG(2, ("Disallowing %s with null password\n", |
243 | | user)); |
244 | | return NT_STATUS_LOGON_FAILURE; |
245 | | } |
246 | | if (!*password) { |
247 | | DEBUG(3, |
248 | | ("Allowing access to %s with null password\n", |
249 | | user)); |
250 | | return NT_STATUS_OK; |
251 | | } |
252 | | } |
253 | | |
254 | | #endif /* defined(WITH_PAM) */ |
255 | | |
256 | | /* try it as it came to us */ |
257 | 0 | nt_status = password_check(user, password, (const void *)rhost); |
258 | 0 | if NT_STATUS_IS_OK(nt_status) { |
259 | 0 | return (nt_status); |
260 | 0 | } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { |
261 | | /* No point continuing if its not the password that's to blame (ie PAM disabled). */ |
262 | 0 | return (nt_status); |
263 | 0 | } |
264 | | |
265 | 0 | if (!run_cracker) { |
266 | 0 | return (nt_status); |
267 | 0 | } |
268 | | |
269 | | /* if the password was given to us with mixed case then we don't |
270 | | * need to proceed as we know it hasn't been case modified by the |
271 | | * client */ |
272 | 0 | if (strhasupper(password) && strhaslower(password)) { |
273 | 0 | return nt_status; |
274 | 0 | } |
275 | | |
276 | | /* make a copy of it */ |
277 | 0 | pass2 = talloc_strdup(talloc_tos(), password); |
278 | 0 | if (!pass2) { |
279 | 0 | return NT_STATUS_NO_MEMORY; |
280 | 0 | } |
281 | | |
282 | | /* try all lowercase if it's currently all uppercase */ |
283 | 0 | if (strhasupper(pass2)) { |
284 | 0 | if (!strlower_m(pass2)) { |
285 | 0 | return NT_STATUS_INVALID_PARAMETER; |
286 | 0 | } |
287 | 0 | nt_status = password_check(user, pass2, (const void *)rhost); |
288 | 0 | if (NT_STATUS_IS_OK(nt_status)) { |
289 | 0 | return (nt_status); |
290 | 0 | } |
291 | 0 | } |
292 | | |
293 | 0 | return NT_STATUS_WRONG_PASSWORD; |
294 | 0 | } |