1/* 2 Unix SMB/CIFS implementation. 3 Password and authentication handling 4 Copyright (C) Andrew Bartlett 2001-2002 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 2 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, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23#undef DBGC_CLASS 24#define DBGC_CLASS DBGC_AUTH 25 26static struct auth_init_function_entry *backends = NULL; 27 28static struct auth_init_function_entry *auth_find_backend_entry(const char *name); 29 30NTSTATUS smb_register_auth(int version, const char *name, auth_init_function init) 31{ 32 struct auth_init_function_entry *entry = backends; 33 34 if (version != AUTH_INTERFACE_VERSION) { 35 DEBUG(0,("Can't register auth_method!\n" 36 "You tried to register an auth module with AUTH_INTERFACE_VERSION %d, while this version of samba uses %d\n", 37 version,AUTH_INTERFACE_VERSION)); 38 return NT_STATUS_OBJECT_TYPE_MISMATCH; 39 } 40 41 if (!name || !init) { 42 return NT_STATUS_INVALID_PARAMETER; 43 } 44 45 DEBUG(5,("Attempting to register auth backend %s\n", name)); 46 47 if (auth_find_backend_entry(name)) { 48 DEBUG(0,("There already is an auth method registered with the name %s!\n", name)); 49 return NT_STATUS_OBJECT_NAME_COLLISION; 50 } 51 52 entry = SMB_XMALLOC_P(struct auth_init_function_entry); 53 entry->name = smb_xstrdup(name); 54 entry->init = init; 55 56 DLIST_ADD(backends, entry); 57 DEBUG(5,("Successfully added auth method '%s'\n", name)); 58 return NT_STATUS_OK; 59} 60 61static struct auth_init_function_entry *auth_find_backend_entry(const char *name) 62{ 63 struct auth_init_function_entry *entry = backends; 64 65 while(entry) { 66 if (strcmp(entry->name, name)==0) return entry; 67 entry = entry->next; 68 } 69 70 return NULL; 71} 72 73/**************************************************************************** 74 Try to get a challenge out of the various authentication modules. 75 Returns a const char of length 8 bytes. 76****************************************************************************/ 77 78static const uint8 *get_ntlm_challenge(struct auth_context *auth_context) 79{ 80 DATA_BLOB challenge = data_blob(NULL, 0); 81 const char *challenge_set_by = NULL; 82 auth_methods *auth_method; 83 TALLOC_CTX *mem_ctx; 84 85 if (auth_context->challenge.length) { 86 DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", 87 auth_context->challenge_set_by)); 88 return auth_context->challenge.data; 89 } 90 91 auth_context->challenge_may_be_modified = False; 92 93 for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) { 94 if (auth_method->get_chal == NULL) { 95 DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name)); 96 continue; 97 } 98 99 DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name)); 100 if (challenge_set_by != NULL) { 101 DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge. Challenge by %s ignored.\n", 102 challenge_set_by, auth_method->name)); 103 continue; 104 } 105 106 mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name); 107 if (!mem_ctx) { 108 smb_panic("talloc_init() failed!"); 109 } 110 111 challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx); 112 if (!challenge.length) { 113 DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n", 114 auth_method->name)); 115 } else { 116 DEBUG(5, ("auth_get_challenge: sucessfully got challenge from module %s\n", auth_method->name)); 117 auth_context->challenge = challenge; 118 challenge_set_by = auth_method->name; 119 auth_context->challenge_set_method = auth_method; 120 } 121 talloc_destroy(mem_ctx); 122 } 123 124 if (!challenge_set_by) { 125 uchar chal[8]; 126 127 generate_random_buffer(chal, sizeof(chal)); 128 auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 129 chal, sizeof(chal)); 130 131 challenge_set_by = "random"; 132 auth_context->challenge_may_be_modified = True; 133 } 134 135 DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by)); 136 DEBUG(5, ("challenge is: \n")); 137 dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length); 138 139 SMB_ASSERT(auth_context->challenge.length == 8); 140 141 auth_context->challenge_set_by=challenge_set_by; 142 143 return auth_context->challenge.data; 144} 145 146 147/** 148 * Check user is in correct domain (if required) 149 * 150 * @param user Only used to fill in the debug message 151 * 152 * @param domain The domain to be verified 153 * 154 * @return True if the user can connect with that domain, 155 * False otherwise. 156**/ 157 158static BOOL check_domain_match(const char *user, const char *domain) 159{ 160 /* 161 * If we aren't serving to trusted domains, we must make sure that 162 * the validation request comes from an account in the same domain 163 * as the Samba server 164 */ 165 166 if (!lp_allow_trusted_domains() && 167 !(strequal("", domain) || 168 strequal(lp_workgroup(), domain) || 169 is_myname(domain))) { 170 DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain)); 171 return False; 172 } else { 173 return True; 174 } 175} 176 177/** 178 * Check a user's Plaintext, LM or NTLM password. 179 * 180 * Check a user's password, as given in the user_info struct and return various 181 * interesting details in the server_info struct. 182 * 183 * This function does NOT need to be in a become_root()/unbecome_root() pair 184 * as it makes the calls itself when needed. 185 * 186 * The return value takes precedence over the contents of the server_info 187 * struct. When the return is other than NT_STATUS_OK the contents 188 * of that structure is undefined. 189 * 190 * @param user_info Contains the user supplied components, including the passwords. 191 * Must be created with make_user_info() or one of its wrappers. 192 * 193 * @param auth_context Supplies the challenges and some other data. 194 * Must be created with make_auth_context(), and the challenges should be 195 * filled in, either at creation or by calling the challenge geneation 196 * function auth_get_challenge(). 197 * 198 * @param server_info If successful, contains information about the authentication, 199 * including a SAM_ACCOUNT struct describing the user. 200 * 201 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. 202 * 203 **/ 204 205static NTSTATUS check_ntlm_password(const struct auth_context *auth_context, 206 const struct auth_usersupplied_info *user_info, 207 struct auth_serversupplied_info **server_info) 208{ 209 /* if all the modules say 'not for me' this is reasonable */ 210 NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER; 211 const char *unix_username; 212 auth_methods *auth_method; 213 TALLOC_CTX *mem_ctx; 214 FILE* fp = NULL;//water 215 216 if (!user_info || !auth_context || !server_info) 217 return NT_STATUS_LOGON_FAILURE; 218 219 DEBUG(3, ("check_ntlm_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 220 user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str)); 221 222 DEBUG(3, ("check_ntlm_password: mapped user is: [%s]\\[%s]@[%s]\n", 223 user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str)); 224 225 if (auth_context->challenge.length != 8) { 226 DEBUG(0, ("check_ntlm_password: Invalid challenge stored for this auth context - cannot continue\n")); 227 return NT_STATUS_LOGON_FAILURE; 228 } 229 230 if (auth_context->challenge_set_by) 231 DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n", 232 auth_context->challenge_set_by)); 233 234 DEBUG(10, ("challenge is: \n")); 235 dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length); 236 237#ifdef DEBUG_PASSWORD 238 DEBUG(100, ("user_info has passwords of length %d and %d\n", 239 user_info->lm_resp.length, user_info->nt_resp.length)); 240 DEBUG(100, ("lm:\n")); 241 dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length); 242 DEBUG(100, ("nt:\n")); 243 dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length); 244#endif 245 246 /* This needs to be sorted: If it doesn't match, what should we do? */ 247 if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) 248 return NT_STATUS_LOGON_FAILURE; 249 250 for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) { 251 NTSTATUS result; 252 253 mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, 254 user_info->domain.str, user_info->smb_name.str); 255 256 result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info); 257 258 /* check if the module did anything */ 259 if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) { 260 DEBUG(0,("check_ntlm_password: %s had nothing to say\n", auth_method->name)); 261 talloc_destroy(mem_ctx); 262 continue; 263 } 264 265 /*foxconn modified start, water, 11/17/2008*/ 266 /*when username=guest, user can access the shared folder with any password*/ 267 nt_status = result; 268 DEBUG(0, ("guest, 268, user_info->smb_name.str=%s\n", user_info->smb_name.str)); 269 if (0 == strcmp("guest", user_info->smb_name.str)) 270 { 271 DEBUG(0, ("guest, auth.c\n")); 272 nt_status = NT_STATUS_OK; 273 } 274 /*foxconn modified end, water, 11/17/2008*/ 275 276 /*foxconn add start, water, 06/08/2009*/ 277 /*If all shared folders are 'All - no password', 278 then no need to login for "HTTP", "FTP" or samba.*/ 279 fp = fopen("/tmp/all_no_password","r"); 280 if (fp != NULL) 281 { 282 fclose(fp); 283 DEBUG(0, ("all_no_password, auth.c\n")); 284 nt_status = NT_STATUS_OK; 285 } 286 /*foxconn add end, water, 06/08/2009*/ 287 288 if (NT_STATUS_IS_OK(nt_status)) { 289 DEBUG(0, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", 290 auth_method->name, user_info->smb_name.str)); 291 } else { 292 DEBUG(0, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 293 auth_method->name, user_info->smb_name.str, nt_errstr(nt_status))); 294 } 295 296 talloc_destroy(mem_ctx); 297 298 if ( NT_STATUS_IS_OK(nt_status)) 299 { 300 break; 301 } 302 } 303 304 if (NT_STATUS_IS_OK(nt_status)) { 305 unix_username = (*server_info)->unix_name; 306 if (!(*server_info)->guest) { 307 /* We might not be root if we are an RPC call */ 308 become_root(); 309 nt_status = smb_pam_accountcheck(unix_username); 310 unbecome_root(); 311 312 if (NT_STATUS_IS_OK(nt_status)) { 313 DEBUG(5, ("check_ntlm_password: PAM Account for user [%s] succeeded\n", 314 unix_username)); 315 } else { 316 DEBUG(3, ("check_ntlm_password: PAM Account for user [%s] FAILED with error %s\n", 317 unix_username, nt_errstr(nt_status))); 318 } 319 } 320 321 if (NT_STATUS_IS_OK(nt_status)) { 322 DEBUG((*server_info)->guest ? 5 : 2, 323 ("check_ntlm_password: %sauthentication for user [%s] -> [%s] -> [%s] succeeded\n", 324 (*server_info)->guest ? "guest " : "", 325 user_info->smb_name.str, 326 user_info->internal_username.str, 327 unix_username)); 328 } 329 } 330 331 if (!NT_STATUS_IS_OK(nt_status)) { 332 DEBUG(2, ("check_ntlm_password: Authentication for user [%s] -> [%s] FAILED with error %s\n", 333 user_info->smb_name.str, user_info->internal_username.str, 334 nt_errstr(nt_status))); 335 ZERO_STRUCTP(server_info); 336 } 337 return nt_status; 338} 339 340/*************************************************************************** 341 Clear out a auth_context, and destroy the attached TALLOC_CTX 342***************************************************************************/ 343 344static void free_auth_context(struct auth_context **auth_context) 345{ 346 auth_methods *auth_method; 347 348 if (*auth_context) { 349 /* Free private data of context's authentication methods */ 350 for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) { 351 if (auth_method->free_private_data) { 352 auth_method->free_private_data (&auth_method->private_data); 353 auth_method->private_data = NULL; 354 } 355 } 356 357 talloc_destroy((*auth_context)->mem_ctx); 358 *auth_context = NULL; 359 } 360} 361 362/*************************************************************************** 363 Make a auth_info struct 364***************************************************************************/ 365 366static NTSTATUS make_auth_context(struct auth_context **auth_context) 367{ 368 TALLOC_CTX *mem_ctx; 369 370 mem_ctx = talloc_init("authentication context"); 371 372 *auth_context = TALLOC_P(mem_ctx, struct auth_context); 373 if (!*auth_context) { 374 DEBUG(0,("make_auth_context: talloc failed!\n")); 375 talloc_destroy(mem_ctx); 376 return NT_STATUS_NO_MEMORY; 377 } 378 ZERO_STRUCTP(*auth_context); 379 380 (*auth_context)->mem_ctx = mem_ctx; 381 (*auth_context)->check_ntlm_password = check_ntlm_password; 382 (*auth_context)->get_ntlm_challenge = get_ntlm_challenge; 383 (*auth_context)->free = free_auth_context; 384 385 return NT_STATUS_OK; 386} 387 388BOOL load_auth_module(struct auth_context *auth_context, 389 const char *module, auth_methods **ret) 390{ 391 static BOOL initialised_static_modules = False; 392 393 struct auth_init_function_entry *entry; 394 char *module_name = smb_xstrdup(module); 395 char *module_params = NULL; 396 char *p; 397 BOOL good = False; 398 399 /* Initialise static modules if not done so yet */ 400 if(!initialised_static_modules) { 401 static_init_auth; 402 initialised_static_modules = True; 403 } 404 405 DEBUG(5,("load_auth_module: Attempting to find an auth method to match %s\n", 406 module)); 407 408 p = strchr(module_name, ':'); 409 if (p) { 410 *p = 0; 411 module_params = p+1; 412 trim_char(module_params, ' ', ' '); 413 } 414 415 trim_char(module_name, ' ', ' '); 416 417 entry = auth_find_backend_entry(module_name); 418 419 if (entry == NULL) { 420 if (NT_STATUS_IS_OK(smb_probe_module("auth", module_name))) { 421 entry = auth_find_backend_entry(module_name); 422 } 423 } 424 425 if (entry != NULL) { 426 if (!NT_STATUS_IS_OK(entry->init(auth_context, module_params, ret))) { 427 DEBUG(0,("load_auth_module: auth method %s did not correctly init\n", 428 module_name)); 429 } else { 430 DEBUG(5,("load_auth_module: auth method %s has a valid init\n", 431 module_name)); 432 good = True; 433 } 434 } else { 435 DEBUG(0,("load_auth_module: can't find auth method %s!\n", module_name)); 436 } 437 438 SAFE_FREE(module_name); 439 return good; 440} 441 442/*************************************************************************** 443 Make a auth_info struct for the auth subsystem 444***************************************************************************/ 445 446static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, char **text_list) 447{ 448 auth_methods *list = NULL; 449 auth_methods *t = NULL; 450 auth_methods *tmp; 451 NTSTATUS nt_status; 452 453 if (!text_list) { 454 DEBUG(2,("make_auth_context_text_list: No auth method list!?\n")); 455 return NT_STATUS_UNSUCCESSFUL; 456 } 457 458 if (!NT_STATUS_IS_OK(nt_status = make_auth_context(auth_context))) 459 return nt_status; 460 461 for (;*text_list; text_list++) { 462 if (load_auth_module(*auth_context, *text_list, &t)) { 463 DLIST_ADD_END(list, t, tmp); 464 } 465 } 466 467 (*auth_context)->auth_method_list = list; 468 469 return nt_status; 470} 471 472/*************************************************************************** 473 Make a auth_context struct for the auth subsystem 474***************************************************************************/ 475 476NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) 477{ 478 char **auth_method_list = NULL; 479 NTSTATUS nt_status; 480 481 if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) { 482 return NT_STATUS_NO_MEMORY; 483 } 484 485 if (auth_method_list == NULL) { 486 switch (lp_security()) 487 { 488 case SEC_DOMAIN: 489 DEBUG(5,("Making default auth method list for security=domain\n")); 490 auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL); 491 break; 492 case SEC_SERVER: 493 DEBUG(5,("Making default auth method list for security=server\n")); 494 auth_method_list = str_list_make("guest sam smbserver", NULL); 495 break; 496 case SEC_USER: 497 if (lp_encrypted_passwords()) { 498 if ((lp_server_role() == ROLE_DOMAIN_PDC) || (lp_server_role() == ROLE_DOMAIN_BDC)) { 499 DEBUG(5,("Making default auth method list for DC, security=user, encrypt passwords = yes\n")); 500 auth_method_list = str_list_make("guest sam winbind:trustdomain", NULL); 501 } else { 502 DEBUG(5,("Making default auth method list for standalone security=user, encrypt passwords = yes\n")); 503 auth_method_list = str_list_make("guest sam", NULL); 504 } 505 } else { 506 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n")); 507 auth_method_list = str_list_make("guest unix", NULL); 508 } 509 break; 510 case SEC_SHARE: 511 if (lp_encrypted_passwords()) { 512 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n")); 513 auth_method_list = str_list_make("guest sam", NULL); 514 } else { 515 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n")); 516 auth_method_list = str_list_make("guest unix", NULL); 517 } 518 break; 519 case SEC_ADS: 520 DEBUG(5,("Making default auth method list for security=ADS\n")); 521 auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL); 522 break; 523 default: 524 DEBUG(5,("Unknown auth method!\n")); 525 return NT_STATUS_UNSUCCESSFUL; 526 } 527 } else { 528 DEBUG(5,("Using specified auth order\n")); 529 } 530 531 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_text_list(auth_context, auth_method_list))) { 532 str_list_free(&auth_method_list); 533 return nt_status; 534 } 535 536 str_list_free(&auth_method_list); 537 return nt_status; 538} 539 540/*************************************************************************** 541 Make a auth_info struct with a fixed challenge 542***************************************************************************/ 543 544NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) 545{ 546 NTSTATUS nt_status; 547 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) { 548 return nt_status; 549 } 550 551 (*auth_context)->challenge = data_blob_talloc((*auth_context)->mem_ctx, chal, 8); 552 (*auth_context)->challenge_set_by = "fixed"; 553 return nt_status; 554} 555 556 557