66cf8b8873ab3ede83f6dbb8e6dc3d6eeabccab8
[nivanova/samba-autobuild/.git] / source3 / auth / pass_check.c
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 #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 #ifdef LINUX_BIGCRYPT
71 /****************************************************************************
72 an enhanced crypt for Linux to handle password longer than 8 characters
73 ****************************************************************************/
74 static int linux_bigcrypt(char *password, char *salt1, char *crypted)
75 {
76 #define LINUX_PASSWORD_SEG_CHARS 8
77         char salt[3];
78         int i;
79
80         StrnCpy(salt, salt1, 2);
81         crypted += 2;
82
83         for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
84                 char *p = crypt(password, salt) + 2;
85                 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
86                         return (0);
87                 password += LINUX_PASSWORD_SEG_CHARS;
88                 crypted += strlen(p);
89         }
90
91         return (1);
92 }
93 #endif
94
95 #ifdef OSF1_ENH_SEC
96 /****************************************************************************
97 an enhanced crypt for OSF1
98 ****************************************************************************/
99 static char *osf1_bigcrypt(char *password, char *salt1)
100 {
101         static char result[AUTH_MAX_PASSWD_LENGTH] = "";
102         char *p1;
103         char *p2 = password;
104         char salt[3];
105         int i;
106         int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
107         if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
108                 parts++;
109
110         StrnCpy(salt, salt1, 2);
111         StrnCpy(result, salt1, 2);
112         result[2] = '\0';
113
114         for (i = 0; i < parts; i++) {
115                 p1 = crypt(p2, salt);
116                 strncat(result, p1 + 2,
117                         AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
118                 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
119                 p2 += AUTH_CLEARTEXT_SEG_CHARS;
120         }
121
122         return (result);
123 }
124 #endif
125
126
127 /****************************************************************************
128 core of password checking routine
129 ****************************************************************************/
130 static NTSTATUS password_check(const char *user, const char *password, const void *private_data)
131 {
132 #ifdef WITH_PAM
133         const char *rhost = (const char *)private_data;
134         return smb_pam_passcheck(user, rhost, password);
135 #else
136
137         bool ret;
138
139
140
141 #ifdef OSF1_ENH_SEC
142
143         ret = (strcmp(osf1_bigcrypt(password, get_this_salt()),
144                       get_this_crypted()) == 0);
145         if (!ret) {
146                 DEBUG(2,
147                       ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
148                 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
149         }
150         if (ret) {
151                 return NT_STATUS_OK;
152         } else {
153                 return NT_STATUS_WRONG_PASSWORD;
154         }
155
156 #endif /* OSF1_ENH_SEC */
157
158 #ifdef ULTRIX_AUTH
159         ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
160         if (ret) {
161                 return NT_STATUS_OK;
162         } else {
163                 return NT_STATUS_WRONG_PASSWORD;
164         }
165
166 #endif /* ULTRIX_AUTH */
167
168 #ifdef LINUX_BIGCRYPT
169         ret = (linux_bigcrypt(password, get_this_salt(), get_this_crypted()));
170         if (ret) {
171                 return NT_STATUS_OK;
172         } else {
173                 return NT_STATUS_WRONG_PASSWORD;
174         }
175 #endif /* LINUX_BIGCRYPT */
176
177 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
178
179         /*
180          * Some systems have bigcrypt in the C library but might not
181          * actually use it for the password hashes (HPUX 10.20) is
182          * a noteable example. So we try bigcrypt first, followed
183          * by crypt.
184          */
185
186         if (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0)
187                 return NT_STATUS_OK;
188         else
189                 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
190         if (ret) {
191                 return NT_STATUS_OK;
192         } else {
193                 return NT_STATUS_WRONG_PASSWORD;
194         }
195 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
196
197 #ifdef HAVE_BIGCRYPT
198         ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
199         if (ret) {
200                 return NT_STATUS_OK;
201         } else {
202                 return NT_STATUS_WRONG_PASSWORD;
203         }
204 #endif /* HAVE_BIGCRYPT */
205
206 #ifndef HAVE_CRYPT
207         DEBUG(1, ("Warning - no crypt available\n"));
208         return NT_STATUS_LOGON_FAILURE;
209 #else /* HAVE_CRYPT */
210         ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
211         if (ret) {
212                 return NT_STATUS_OK;
213         } else {
214                 return NT_STATUS_WRONG_PASSWORD;
215         }
216 #endif /* HAVE_CRYPT */
217 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
218 #endif /* WITH_PAM */
219 }
220
221
222
223 /****************************************************************************
224 CHECK if a username/password is OK
225 the function pointer fn() points to a function to call when a successful
226 match is found and is used to update the encrypted password file 
227 return NT_STATUS_OK on correct match, appropriate error otherwise
228 ****************************************************************************/
229
230 NTSTATUS pass_check(const struct passwd *pass,
231                     const char *user,
232                     const char *rhost,
233                     const char *password,
234                     bool run_cracker)
235 {
236         char *pass2 = NULL;
237
238         NTSTATUS nt_status;
239
240 #ifdef DEBUG_PASSWORD
241         DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
242 #endif
243
244         if (!password)
245                 return NT_STATUS_LOGON_FAILURE;
246
247         if ((!*password) && !lp_null_passwords())
248                 return NT_STATUS_LOGON_FAILURE;
249
250 #if defined(WITH_PAM) 
251
252         /*
253          * If we're using PAM we want to short-circuit all the 
254          * checks below and dive straight into the PAM code.
255          */
256
257         DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user));
258
259 #else /* Not using PAM */
260
261         DEBUG(4, ("pass_check: Checking password for user %s\n", user));
262
263         if (!pass) {
264                 DEBUG(3, ("Couldn't find user %s\n", user));
265                 return NT_STATUS_NO_SUCH_USER;
266         }
267
268
269         /* Copy into global for the convenience of looping code */
270         /* Also the place to keep the 'password' no matter what
271            crazy struct it started in... */
272         if (set_this_crypted(pass->pw_passwd) == NULL) {
273                 return NT_STATUS_NO_MEMORY;
274         }
275         if (set_this_salt(pass->pw_passwd) == NULL) {
276                 return NT_STATUS_NO_MEMORY;
277         }
278
279 #ifdef HAVE_GETSPNAM
280         {
281                 struct spwd *spass;
282
283                 /* many shadow systems require you to be root to get
284                    the password, in most cases this should already be
285                    the case when this function is called, except
286                    perhaps for IPC password changing requests */
287
288                 spass = getspnam(pass->pw_name);
289                 if (spass && spass->sp_pwdp) {
290                         if (set_this_crypted(spass->sp_pwdp) == NULL) {
291                                 return NT_STATUS_NO_MEMORY;
292                         }
293                         if (set_this_salt(spass->sp_pwdp) == NULL) {
294                                 return NT_STATUS_NO_MEMORY;
295                         }
296                 }
297         }
298 #elif defined(IA_UINFO)
299         {
300                 /* Need to get password with SVR4.2's ia_ functions
301                    instead of get{sp,pw}ent functions. Required by
302                    UnixWare 2.x, tested on version
303                    2.1. (tangent@cyberport.com) */
304                 uinfo_t uinfo;
305                 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
306                         ia_get_logpwd(uinfo, &(pass->pw_passwd));
307         }
308 #endif
309
310 #ifdef HAVE_GETPRPWNAM
311         {
312                 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
313                 if (pr_pw && pr_pw->ufld.fd_encrypt) {
314                         if (set_this_crypted(pr_pw->ufld.fd_encrypt) == NULL) {
315                                 return NT_STATUS_NO_MEMORY;
316                         }
317                 }
318         }
319 #endif
320
321 #ifdef HAVE_GETPWANAM
322         {
323                 struct passwd_adjunct *pwret;
324                 pwret = getpwanam(s);
325                 if (pwret && pwret->pwa_passwd) {
326                         if (set_this_crypted(pwret->pwa_passwd) == NULL) {
327                                 return NT_STATUS_NO_MEMORY;
328                         }
329                 }
330         }
331 #endif
332
333 #ifdef OSF1_ENH_SEC
334         {
335                 struct pr_passwd *mypasswd;
336                 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
337                           user));
338                 mypasswd = getprpwnam(user);
339                 if (mypasswd) {
340                         user = mypasswd->ufld.fd_name;
341                         if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
342                                 return NT_STATUS_NO_MEMORY;
343                         }
344                 } else {
345                         DEBUG(5,
346                               ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
347                                user));
348                 }
349         }
350 #endif
351
352 #ifdef ULTRIX_AUTH
353         {
354                 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
355                 if (ap) {
356                         if (set_this_crypted(ap->a_password) == NULL) {
357                                 endauthent();
358                                 return NT_STATUS_NO_MEMORY;
359                         }
360                         endauthent();
361                 }
362         }
363 #endif
364
365 #if defined(HAVE_TRUNCATED_SALT)
366         /* crypt on some platforms (HPUX in particular)
367            won't work with more than 2 salt characters. */
368         {
369                 char *trunc_salt = get_this_salt();
370                 if (!trunc_salt || strlen(trunc_salt) < 2) {
371                         return NT_STATUS_LOGON_FAILURE;
372                 }
373                 trunc_salt[2] = 0;
374                 if (set_this_salt(trunc_salt) == NULL) {
375                         return NT_STATUS_NO_MEMORY;
376                 }
377         }
378 #endif
379
380         if (!get_this_crypted() || !*get_this_crypted()) {
381                 if (!lp_null_passwords()) {
382                         DEBUG(2, ("Disallowing %s with null password\n",
383                                   user));
384                         return NT_STATUS_LOGON_FAILURE;
385                 }
386                 if (!*password) {
387                         DEBUG(3,
388                               ("Allowing access to %s with null password\n",
389                                user));
390                         return NT_STATUS_OK;
391                 }
392         }
393
394 #endif /* defined(WITH_PAM) */
395
396         /* try it as it came to us */
397         nt_status = password_check(user, password, (const void *)rhost);
398         if NT_STATUS_IS_OK(nt_status) {
399                 return (nt_status);
400         } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
401                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
402                 return (nt_status);
403         }
404
405         if (!run_cracker) {
406                 return (nt_status);
407         }
408
409         /* if the password was given to us with mixed case then we don't
410          * need to proceed as we know it hasn't been case modified by the
411          * client */
412         if (strhasupper(password) && strhaslower(password)) {
413                 return nt_status;
414         }
415
416         /* make a copy of it */
417         pass2 = talloc_strdup(talloc_tos(), password);
418         if (!pass2) {
419                 return NT_STATUS_NO_MEMORY;
420         }
421
422         /* try all lowercase if it's currently all uppercase */
423         if (strhasupper(pass2)) {
424                 if (!strlower_m(pass2)) {
425                         return NT_STATUS_INVALID_PARAMETER;
426                 }
427                 nt_status = password_check(user, pass2, (const void *)rhost);
428                 if (NT_STATUS_IS_OK(nt_status)) {
429                         return (nt_status);
430                 }
431         }
432
433         return NT_STATUS_WRONG_PASSWORD;
434 }