2 Unix SMB/Netbios implementation.
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
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.
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.
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.
27 * Check user is in correct domain (if required)
29 * @param user Only used to fill in the debug message
31 * @param domain The domain to be verified
33 * @return True if the user can connect with that domain,
37 static BOOL check_domain_match(const char *user, const char *domain)
40 * If we aren't serving to trusted domains, we must make sure that
41 * the validation request comes from an account in the same domain
45 if (!lp_allow_trusted_domains() &&
46 !(strequal("", domain) ||
47 strequal(lp_workgroup(), domain) ||
48 is_netbios_alias_or_name(domain))) {
49 DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
57 * Check a user's Plaintext, LM or NTLM password.
59 * Check a user's password, as given in the user_info struct and return various
60 * interesting details in the server_info struct.
62 * This function does NOT need to be in a become_root()/unbecome_root() pair
63 * as it makes the calls itself when needed.
65 * The return value takes precedence over the contents of the server_info
66 * struct. When the return is other than NT_STATUS_OK the contents
67 * of that structure is undefined.
69 * @param user_info Contains the user supplied components, including the passwords.
70 * Must be created with make_user_info() or one of its wrappers.
72 * @param auth_info Supplies the challanges and some other data.
73 * Must be created with make_auth_info(), and the challanges should be
74 * filled in, either at creation or by calling the challange geneation
75 * function auth_get_challange().
77 * @param server_info If successful, contains information about the authenticaion,
78 * including a SAM_ACCOUNT struct describing the user.
80 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
84 NTSTATUS check_password(const auth_usersupplied_info *user_info,
85 const auth_authsupplied_info *auth_info,
86 auth_serversupplied_info **server_info)
89 NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
90 const char *pdb_username;
91 auth_methods *auth_method;
93 if (!user_info || !auth_info || !server_info) {
94 return NT_STATUS_LOGON_FAILURE;
97 DEBUG(3, ("check_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n",
98 user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str));
100 DEBUG(3, ("check_password: mapped user is: [%s]\\[%s]@[%s]\n",
101 user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
102 if (auth_info->challenge_set_by) {
103 DEBUG(10, ("auth_info challenge created by %s\n", auth_info->challenge_set_by));
105 DEBUG(10, ("challenge is: \n"));
106 dump_data(5, (auth_info)->challenge.data, (auth_info)->challenge.length);
108 #ifdef DEBUG_PASSWORD
109 DEBUG(100, ("user_info has passwords of length %d and %d\n",
110 user_info->lm_resp.length, user_info->nt_resp.length));
111 DEBUG(100, ("lm:\n"));
112 dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
113 DEBUG(100, ("nt:\n"));
114 dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
117 /* This needs to be sorted: If it doesn't match, what should we do? */
118 if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) {
119 return NT_STATUS_LOGON_FAILURE;
122 for (auth_method = auth_info->auth_method_list;auth_method; auth_method = auth_method->next)
124 nt_status = auth_method->auth(auth_method->private_data, user_info, auth_info, server_info);
125 if (NT_STATUS_IS_OK(nt_status)) {
126 DEBUG(3, ("check_password: %s authentication for user [%s] suceeded\n",
127 auth_method->name, user_info->smb_name.str));
129 DEBUG(5, ("check_password: %s authentication for user [%s] FAILED with error %s\n",
130 auth_method->name, user_info->smb_name.str, get_nt_error_msg(nt_status)));
133 if (NT_STATUS_IS_OK(nt_status)) {
138 /* This is one of the few places the *relies* (rather than just sets defaults
139 on the value of lp_security(). This needs to change. A new paramater
141 if (lp_security() >= SEC_SERVER) {
142 smb_user_control(user_info, *server_info, nt_status);
145 if (NT_STATUS_IS_OK(nt_status)) {
146 pdb_username = pdb_get_username((*server_info)->sam_account);
147 if (!(*server_info)->guest) {
148 /* We might not be root if we are an RPC call */
150 nt_status = smb_pam_accountcheck(pdb_username);
153 if (NT_STATUS_IS_OK(nt_status)) {
154 DEBUG(5, ("check_password: PAM Account for user [%s] suceeded\n",
157 DEBUG(3, ("check_password: PAM Account for user [%s] FAILED with error %s\n",
158 pdb_username, get_nt_error_msg(nt_status)));
162 if (NT_STATUS_IS_OK(nt_status)) {
163 DEBUG((*server_info)->guest ? 5 : 2,
164 ("check_password: %sauthenticaion for user [%s] -> [%s] -> [%s] suceeded\n",
165 (*server_info)->guest ? "guest " : "",
166 user_info->smb_name.str,
167 user_info->internal_username.str,
172 if (!NT_STATUS_IS_OK(nt_status)) {
173 DEBUG(2, ("check_password: Authenticaion for user [%s] -> [%s] FAILED with error %s\n",
174 user_info->smb_name.str, user_info->internal_username.str,
175 get_nt_error_msg(nt_status)));
176 ZERO_STRUCTP(server_info);
183 * Squash an NT_STATUS in line with security requirements.
184 * In an attempt to avoid giving the whole game away when users
185 * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and
186 * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations
187 * (session setups in particular).
189 * @param nt_status NTSTATUS input for squashing.
190 * @return the 'squashed' nt_status
193 NTSTATUS nt_status_squash(NTSTATUS nt_status)
195 if NT_STATUS_IS_OK(nt_status) {
197 } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
198 /* Match WinXP and don't give the game away */
199 return NT_STATUS_LOGON_FAILURE;
201 } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
202 /* Match WinXP and don't give the game away */
203 return NT_STATUS_LOGON_FAILURE;
211 /****************************************************************************
212 COMPATABILITY INTERFACES:
213 ***************************************************************************/
215 /****************************************************************************
216 check if a username/password is OK assuming the password is a 24 byte
218 return True if the password is correct, False otherwise
219 ****************************************************************************/
221 static NTSTATUS pass_check_smb(char *smb_name,
225 DATA_BLOB plaintext_password,
230 auth_usersupplied_info *user_info = NULL;
231 extern auth_authsupplied_info *negprot_global_auth_info;
232 auth_serversupplied_info *server_info = NULL;
234 make_user_info_for_reply_enc(&user_info, smb_name,
239 nt_status = check_password(user_info, negprot_global_auth_info, &server_info);
241 auth_authsupplied_info *plaintext_auth_info = NULL;
243 if (!make_auth_info_subsystem(&plaintext_auth_info)) {
244 return NT_STATUS_NO_MEMORY;
247 chal = auth_get_challenge(plaintext_auth_info);
249 if (!make_user_info_for_reply(&user_info,
250 smb_name, domain, chal.data,
251 plaintext_password)) {
252 return NT_STATUS_NO_MEMORY;
255 nt_status = check_password(user_info, plaintext_auth_info, &server_info);
257 data_blob_free(&chal);
258 free_auth_info(&plaintext_auth_info);
260 free_user_info(&user_info);
261 free_server_info(&server_info);
265 /****************************************************************************
266 check if a username/password pair is OK either via the system password
267 database or the encrypted SMB password database
268 return True if the password is correct, False otherwise
269 ****************************************************************************/
270 BOOL password_ok(char *smb_name, DATA_BLOB password_blob)
273 DATA_BLOB null_password = data_blob(NULL, 0);
274 extern BOOL global_encrypted_passwords_negotiated;
275 BOOL encrypted = (global_encrypted_passwords_negotiated && password_blob.length == 24);
279 * The password could be either NTLM or plain LM. Try NTLM first,
280 * but fall-through as required.
281 * NTLMv2 makes no sense here.
283 if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, encrypted))) {
287 if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, encrypted))) {
291 if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, encrypted))) {