6450559175c88765aac2568ac747355d31c4a816
[amitay/samba.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
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
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 #if defined(HAVE_TRUNCATED_SALT)
240         /* crypt on some platforms (HPUX in particular)
241            won't work with more than 2 salt characters. */
242         {
243                 char *trunc_salt = get_this_salt();
244                 if (!trunc_salt || strlen(trunc_salt) < 2) {
245                         return NT_STATUS_LOGON_FAILURE;
246                 }
247                 trunc_salt[2] = 0;
248                 if (set_this_salt(trunc_salt) == NULL) {
249                         return NT_STATUS_NO_MEMORY;
250                 }
251         }
252 #endif
253
254         if (!get_this_crypted() || !*get_this_crypted()) {
255                 if (!lp_null_passwords()) {
256                         DEBUG(2, ("Disallowing %s with null password\n",
257                                   user));
258                         return NT_STATUS_LOGON_FAILURE;
259                 }
260                 if (!*password) {
261                         DEBUG(3,
262                               ("Allowing access to %s with null password\n",
263                                user));
264                         return NT_STATUS_OK;
265                 }
266         }
267
268 #endif /* defined(WITH_PAM) */
269
270         /* try it as it came to us */
271         nt_status = password_check(user, password, (const void *)rhost);
272         if NT_STATUS_IS_OK(nt_status) {
273                 return (nt_status);
274         } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
275                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
276                 return (nt_status);
277         }
278
279         if (!run_cracker) {
280                 return (nt_status);
281         }
282
283         /* if the password was given to us with mixed case then we don't
284          * need to proceed as we know it hasn't been case modified by the
285          * client */
286         if (strhasupper(password) && strhaslower(password)) {
287                 return nt_status;
288         }
289
290         /* make a copy of it */
291         pass2 = talloc_strdup(talloc_tos(), password);
292         if (!pass2) {
293                 return NT_STATUS_NO_MEMORY;
294         }
295
296         /* try all lowercase if it's currently all uppercase */
297         if (strhasupper(pass2)) {
298                 if (!strlower_m(pass2)) {
299                         return NT_STATUS_INVALID_PARAMETER;
300                 }
301                 nt_status = password_check(user, pass2, (const void *)rhost);
302                 if (NT_STATUS_IS_OK(nt_status)) {
303                         return (nt_status);
304                 }
305         }
306
307         return NT_STATUS_WRONG_PASSWORD;
308 }