67f80afdda883e31f1ba9517a3b3d9b46b36df84
[ira/wip.git] / source3 / auth / auth.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Andrew Tridgell              1992-2000
6    Copyright (C) Luke Kenneth Casson Leighton 1996-2000
7    Copyright (C) Andrew Bartlett              2001
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /****************************************************************************
27  Check user is in correct domain if required
28 ****************************************************************************/
29
30 static BOOL check_domain_match(char *user, char *domain) 
31 {
32   /*
33    * If we aren't serving to trusted domains, we must make sure that
34    * the validation request comes from an account in the same domain
35    * as the Samba server
36    */
37
38   if (!lp_allow_trusted_domains() &&
39       !strequal(lp_workgroup(), domain) ) {
40       DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
41       return False;
42   } else {
43       return True;
44   }
45 }
46
47 /****************************************************************************
48  Check a users password, as given in the user-info struct and return various
49  interesting details in the server_info struct.
50
51  This functions does NOT need to be in a become_root()/unbecome_root() pair
52  as it makes the calls itself when needed.
53
54  The return value takes precedence over the contents of the server_info 
55  struct.  When the return is other than NT_STATUS_NOPROBLEMO the contents 
56  of that structure is undefined.
57
58 ****************************************************************************/
59
60 NTSTATUS check_password(const auth_usersupplied_info *user_info, 
61                         auth_serversupplied_info **server_info)
62 {
63         
64         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
65         BOOL done_pam = False;
66         const char *pdb_username;
67
68         DEBUG(3, ("check_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
69                   user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str));
70
71         DEBUG(3, ("check_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
72                   user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
73
74         if (!NT_STATUS_IS_OK(nt_status)) {
75                 nt_status = check_guest_security(user_info, server_info);
76                 if (NT_STATUS_IS_OK(nt_status)) {
77                         DEBUG(5, ("check_password:  checking guest-account for user [%s] suceeded\n", user_info->smb_name.str));
78                 } else {
79                         DEBUG(10, ("check_password:  checking gusst-account for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
80                         
81                 }               
82         }
83
84         /* This needs to be sorted:  If it doesn't match, what should we do? */
85         if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) {
86                 return NT_STATUS_LOGON_FAILURE;
87         }
88
89         if (!NT_STATUS_IS_OK(nt_status)) {
90                 nt_status = check_rhosts_security(user_info, server_info);
91                 if (NT_STATUS_IS_OK(nt_status)) {
92                         DEBUG(3, ("check_password:  Password (rhosts) for user [%s] suceeded\n", user_info->smb_name.str));
93                 } else {
94                         DEBUG(10, ("check_password:  Password (rhosts) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
95                         
96                 }               
97         }
98         
99         if ((lp_security() == SEC_DOMAIN) && !NT_STATUS_IS_OK(nt_status)) {
100                 nt_status = check_domain_security(user_info, server_info);
101                 if (NT_STATUS_IS_OK(nt_status)) {
102                         DEBUG(7, ("check_password:  Password (domain) for user [%s] suceeded\n", user_info->smb_name.str));
103                 } else {
104                         DEBUG(5, ("check_password:  Password (domain) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
105                         
106                 }               
107         }
108         
109         if ((lp_security() == SEC_SERVER) && !NT_STATUS_IS_OK(nt_status)) {
110                 nt_status = check_server_security(user_info, server_info);
111                 if (NT_STATUS_IS_OK(nt_status)) {
112                         DEBUG(7, ("check_password:  Password (server) for user [%s] suceeded\n", user_info->smb_name.str));
113                 } else {
114                         DEBUG(5, ("check_password:  Password (server) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
115                         
116                 }               
117         }
118
119         if (lp_security() >= SEC_SERVER) {
120                 smb_user_control(user_info, *server_info, nt_status);
121         }
122
123         if (!NT_STATUS_IS_OK(nt_status)) {
124                 if (user_info->encrypted || lp_plaintext_to_smbpasswd()) { 
125                         nt_status = check_smbpasswd_security(user_info, server_info);
126                 } else {
127                         nt_status = check_unix_security(user_info, server_info);
128                         done_pam = True;
129                 }
130                 
131                 if (NT_STATUS_IS_OK(nt_status)) {
132                         DEBUG(7, ("check_password:  Password (unix/smbpasswd) for user [%s] suceeded\n", user_info->smb_name.str));
133                 } else {
134                         DEBUG(5, ("check_password:  Password (unix/smbpasswd) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
135                         
136                 }               
137         }
138
139         if (NT_STATUS_IS_OK(nt_status)) {
140                 pdb_username = pdb_get_username((*server_info)->sam_account);
141                 if (!done_pam && !(*server_info)->guest) {
142                         /* We might not be root if we are an RPC call */
143                         become_root();
144                         nt_status = smb_pam_accountcheck(pdb_username);
145                         unbecome_root();
146                         
147                         if (NT_STATUS_IS_OK(nt_status)) {
148                                 DEBUG(5, ("check_password:  PAM Account for user [%s] suceeded\n", pdb_username));
149                         } else {
150                                 DEBUG(3, ("check_password:  PAM Account for user [%s] FAILED with error %s\n", pdb_username, get_nt_error_msg(nt_status)));
151                         } 
152                 }
153         }
154
155         if (NT_STATUS_IS_OK(nt_status)) {
156                 DEBUG(3, ("check_password:  %sauthenticaion for user [%s] -> [%s] -> [%s] suceeded\n", 
157                           (*server_info)->guest ? "guest " : "", 
158                           user_info->smb_name.str, 
159                           user_info->internal_username.str, 
160                           pdb_username));
161         } else {
162                 DEBUG(3, ("check_password:  Authenticaion for user [%s] -> [%s] FAILED with error %s\n", user_info->smb_name.str, user_info->internal_username.str, get_nt_error_msg(nt_status)));
163                 ZERO_STRUCTP(server_info);
164         }               
165
166         return nt_status;
167
168 }
169
170 /****************************************************************************
171  Squash an NT_STATUS return in line with requirements for unauthenticated 
172  connections.  (session setups in particular)
173 ****************************************************************************/
174
175 NTSTATUS nt_status_squash(NTSTATUS nt_status) 
176 {
177         if NT_STATUS_IS_OK(nt_status) {
178                 return nt_status;               
179         } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
180                 /* Match WinXP and don't give the game away */
181                 return NT_STATUS_LOGON_FAILURE;
182                 
183         } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
184                 /* Match WinXP and don't give the game away */
185                 return NT_STATUS_LOGON_FAILURE;
186         } else {
187                 return nt_status;
188         }  
189 }
190
191
192
193 /****************************************************************************
194  COMPATABILITY INTERFACES:
195  ***************************************************************************/
196
197 /****************************************************************************
198 check if a username/password is OK assuming the password is a 24 byte
199 SMB hash
200 return True if the password is correct, False otherwise
201 ****************************************************************************/
202
203 static NTSTATUS pass_check_smb(char *smb_name,
204                                char *domain, 
205                                DATA_BLOB lm_pwd,
206                                DATA_BLOB nt_pwd,
207                                DATA_BLOB plaintext_password,
208                                BOOL encrypted)
209
210 {
211         NTSTATUS nt_status;
212         auth_usersupplied_info *user_info = NULL;
213         auth_serversupplied_info *server_info = NULL;
214
215         make_user_info_for_reply(&user_info, smb_name, 
216                                  domain, 
217                                  lm_pwd, 
218                                  nt_pwd, 
219                                  plaintext_password, 
220                                  encrypted);
221         
222         nt_status = check_password(user_info, &server_info);
223         free_user_info(&user_info);
224         free_server_info(&server_info);
225         return nt_status;
226 }
227
228 /****************************************************************************
229 check if a username/password pair is OK either via the system password
230 database or the encrypted SMB password database
231 return True if the password is correct, False otherwise
232 ****************************************************************************/
233 BOOL password_ok(char *smb_name, DATA_BLOB password_blob)
234 {
235
236         DATA_BLOB null_password = data_blob(NULL, 0);
237         extern BOOL global_encrypted_passwords_negotiated;
238
239         if (global_encrypted_passwords_negotiated) {
240                 /* 
241                  * The password could be either NTLM or plain LM.  Try NTLM first, 
242                  * but fall-through as required.
243                  * NTLMv2 makes no sense here.
244                  */
245                 if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, global_encrypted_passwords_negotiated))) {
246                         return True;
247                 }
248                 
249                 if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, global_encrypted_passwords_negotiated))) {
250                         return True;
251                 }
252         } else {
253                 if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, global_encrypted_passwords_negotiated))) {
254                         return True;
255                 }
256         }
257
258         return False;
259 }
260
261