2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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/>.
20 /* this module is for checking a username/password against a system
21 password database. The SMB encrypted password support is elsewhere */
24 #include "system/passwd.h"
28 #define DBGC_CLASS DBGC_AUTH
30 #if !defined(WITH_PAM)
31 static char *ths_salt;
32 /* This must be writable. */
33 static char *get_this_salt(void)
38 /* We may be setting a modified version of the same
39 * string, so don't free before use. */
41 static const char *set_this_salt(const char *newsalt)
43 char *orig_salt = ths_salt;
44 ths_salt = SMB_STRDUP(newsalt);
49 static char *ths_crypted;
50 static const char *get_this_crypted(void)
58 static const char *set_this_crypted(const char *newcrypted)
60 char *orig_crypted = ths_crypted;
61 ths_crypted = SMB_STRDUP(newcrypted);
62 SAFE_FREE(orig_crypted);
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)
76 #define LINUX_PASSWORD_SEG_CHARS 8
80 StrnCpy(salt, salt1, 2);
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)
87 password += LINUX_PASSWORD_SEG_CHARS;
96 /****************************************************************************
97 an enhanced crypt for OSF1
98 ****************************************************************************/
99 static char *osf1_bigcrypt(char *password, char *salt1)
101 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
106 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
107 if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
110 StrnCpy(salt, salt1, 2);
111 StrnCpy(result, salt1, 2);
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;
127 /****************************************************************************
128 core of password checking routine
129 ****************************************************************************/
130 static NTSTATUS password_check(const char *user, const char *password, const void *private_data)
133 const char *rhost = (const char *)private_data;
134 return smb_pam_passcheck(user, rhost, password);
143 ret = (strcmp(osf1_bigcrypt(password, get_this_salt()),
144 get_this_crypted()) == 0);
147 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
148 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
153 return NT_STATUS_WRONG_PASSWORD;
156 #endif /* OSF1_ENH_SEC */
159 ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
163 return NT_STATUS_WRONG_PASSWORD;
166 #endif /* ULTRIX_AUTH */
168 #ifdef LINUX_BIGCRYPT
169 ret = (linux_bigcrypt(password, get_this_salt(), get_this_crypted()));
173 return NT_STATUS_WRONG_PASSWORD;
175 #endif /* LINUX_BIGCRYPT */
177 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
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
186 if (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0)
189 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
193 return NT_STATUS_WRONG_PASSWORD;
195 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
198 ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
202 return NT_STATUS_WRONG_PASSWORD;
204 #endif /* HAVE_BIGCRYPT */
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);
214 return NT_STATUS_WRONG_PASSWORD;
216 #endif /* HAVE_CRYPT */
217 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
218 #endif /* WITH_PAM */
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 ****************************************************************************/
230 NTSTATUS pass_check(const struct passwd *pass,
233 const char *password,
240 #ifdef DEBUG_PASSWORD
241 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
245 return NT_STATUS_LOGON_FAILURE;
247 if ((!*password) && !lp_null_passwords())
248 return NT_STATUS_LOGON_FAILURE;
250 #if defined(WITH_PAM)
253 * If we're using PAM we want to short-circuit all the
254 * checks below and dive straight into the PAM code.
257 DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user));
259 #else /* Not using PAM */
261 DEBUG(4, ("pass_check: Checking password for user %s\n", user));
264 DEBUG(3, ("Couldn't find user %s\n", user));
265 return NT_STATUS_NO_SUCH_USER;
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;
275 if (set_this_salt(pass->pw_passwd) == NULL) {
276 return NT_STATUS_NO_MEMORY;
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 */
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;
293 if (set_this_salt(spass->sp_pwdp) == NULL) {
294 return NT_STATUS_NO_MEMORY;
298 #elif defined(IA_UINFO)
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) */
305 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
306 ia_get_logpwd(uinfo, &(pass->pw_passwd));
310 #ifdef HAVE_GETPRPWNAM
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;
321 #ifdef HAVE_GETPWANAM
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;
335 struct pr_passwd *mypasswd;
336 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
338 mypasswd = getprpwnam(user);
340 user = mypasswd->ufld.fd_name;
341 if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
342 return NT_STATUS_NO_MEMORY;
346 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
354 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
356 if (set_this_crypted(ap->a_password) == NULL) {
358 return NT_STATUS_NO_MEMORY;
365 #if defined(HAVE_TRUNCATED_SALT)
366 /* crypt on some platforms (HPUX in particular)
367 won't work with more than 2 salt characters. */
369 char *trunc_salt = get_this_salt();
370 if (!trunc_salt || strlen(trunc_salt) < 2) {
371 return NT_STATUS_LOGON_FAILURE;
374 if (set_this_salt(trunc_salt) == NULL) {
375 return NT_STATUS_NO_MEMORY;
380 if (!get_this_crypted() || !*get_this_crypted()) {
381 if (!lp_null_passwords()) {
382 DEBUG(2, ("Disallowing %s with null password\n",
384 return NT_STATUS_LOGON_FAILURE;
388 ("Allowing access to %s with null password\n",
394 #endif /* defined(WITH_PAM) */
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) {
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). */
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
412 if (strhasupper(password) && strhaslower(password)) {
416 /* make a copy of it */
417 pass2 = talloc_strdup(talloc_tos(), password);
419 return NT_STATUS_NO_MEMORY;
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;
427 nt_status = password_check(user, pass2, (const void *)rhost);
428 if (NT_STATUS_IS_OK(nt_status)) {
433 return NT_STATUS_WRONG_PASSWORD;