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;
smb_pam_copy_string(const char * s)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 {
78 #ifdef WITH_PAM
79 	const char *rhost = (const char *)private_data;
80 	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 }
122 
123 
smb_pam_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)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 {
138 	char *pass2 = NULL;
139 
140 	NTSTATUS nt_status;
141 
142 #ifdef DEBUG_PASSWORD
143 	DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
144 #endif
145 
146 	if (!password)
147 		return NT_STATUS_LOGON_FAILURE;
148 
149 	if ((!*password) && !lp_null_passwords())
150 		return NT_STATUS_LOGON_FAILURE;
151 
152 #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 	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 	nt_status = password_check(user, password, (const void *)rhost);
258         if NT_STATUS_IS_OK(nt_status) {
259 		return (nt_status);
260 	} else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
261                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
262                 return (nt_status);
263         }
264 
265 	if (!run_cracker) {
266 		return (nt_status);
267 	}
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 	if (strhasupper(password) && strhaslower(password)) {
273 		return nt_status;
274 	}
275 
276 	/* make a copy of it */
277 	pass2 = talloc_strdup(talloc_tos(), password);
278 	if (!pass2) {
279 		return NT_STATUS_NO_MEMORY;
280 	}
281 
282 	/* try all lowercase if it's currently all uppercase */
283 	if (strhasupper(pass2)) {
284 		if (!strlower_m(pass2)) {
285 			return NT_STATUS_INVALID_PARAMETER;
286 		}
287 		nt_status = password_check(user, pass2, (const void *)rhost);
288 		if (NT_STATUS_IS_OK(nt_status)) {
289 			return (nt_status);
290 		}
291 	}
292 
293 	return NT_STATUS_WRONG_PASSWORD;
294 }
295