Line data Source code
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 :
71 :
72 :
73 : /****************************************************************************
74 : core of password checking routine
75 : ****************************************************************************/
76 0 : static NTSTATUS password_check(const char *user, const char *password, const void *private_data)
77 : {
78 : #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 : }
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 0 : 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 0 : char *pass2 = NULL;
139 :
140 0 : NTSTATUS nt_status;
141 :
142 : #ifdef DEBUG_PASSWORD
143 0 : DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
144 : #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 : #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 : }
264 :
265 0 : if (!run_cracker) {
266 0 : 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 0 : if (strhasupper(password) && strhaslower(password)) {
273 0 : return nt_status;
274 : }
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 : }
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 : }
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 : }
291 : }
292 :
293 0 : return NT_STATUS_WRONG_PASSWORD;
294 : }
|