1/* 2 Unix SMB/CIFS implementation. 3 Password and authentication handling 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 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/* users from session setup */ 24static char *session_userlist = NULL; 25static int len_session_userlist = 0; 26 27/* this holds info on user ids that are already validated for this VC */ 28static user_struct *validated_users; 29static int next_vuid = VUID_OFFSET; 30static int num_validated_vuids; 31 32extern userdom_struct current_user_info; 33 34 35/**************************************************************************** 36 Check if a uid has been validated, and return an pointer to the user_struct 37 if it has. NULL if not. vuid is biased by an offset. This allows us to 38 tell random client vuid's (normally zero) from valid vuids. 39****************************************************************************/ 40 41user_struct *get_valid_user_struct(uint16 vuid) 42{ 43 user_struct *usp; 44 int count=0; 45 46 if (vuid == UID_FIELD_INVALID) 47 return NULL; 48 49 for (usp=validated_users;usp;usp=usp->next,count++) { 50 if (vuid == usp->vuid) { 51 if (count > 10) { 52 DLIST_PROMOTE(validated_users, usp); 53 } 54 return usp; 55 } 56 } 57 58 return NULL; 59} 60 61/**************************************************************************** 62 Invalidate a uid. 63****************************************************************************/ 64 65void invalidate_vuid(uint16 vuid) 66{ 67 user_struct *vuser = get_valid_user_struct(vuid); 68 69 if (vuser == NULL) 70 return; 71 72 SAFE_FREE(vuser->homedir); 73 SAFE_FREE(vuser->unix_homedir); 74 SAFE_FREE(vuser->logon_script); 75 76 session_yield(vuser); 77 SAFE_FREE(vuser->session_keystr); 78 79 free_server_info(&vuser->server_info); 80 81 data_blob_free(&vuser->session_key); 82 83 DLIST_REMOVE(validated_users, vuser); 84 85 /* clear the vuid from the 'cache' on each connection, and 86 from the vuid 'owner' of connections */ 87 conn_clear_vuid_cache(vuid); 88 89 SAFE_FREE(vuser->groups); 90 delete_nt_token(&vuser->nt_user_token); 91 SAFE_FREE(vuser); 92 num_validated_vuids--; 93} 94 95/**************************************************************************** 96 Invalidate all vuid entries for this process. 97****************************************************************************/ 98 99void invalidate_all_vuids(void) 100{ 101 user_struct *usp, *next=NULL; 102 103 for (usp=validated_users;usp;usp=next) { 104 next = usp->next; 105 106 invalidate_vuid(usp->vuid); 107 } 108} 109 110/** 111 * register that a valid login has been performed, establish 'session'. 112 * @param server_info The token returned from the authentication process. 113 * (now 'owned' by register_vuid) 114 * 115 * @param session_key The User session key for the login session (now also 'owned' by register_vuid) 116 * 117 * @param respose_blob The NT challenge-response, if available. (May be freed after this call) 118 * 119 * @param smb_name The untranslated name of the user 120 * 121 * @return Newly allocated vuid, biased by an offset. (This allows us to 122 * tell random client vuid's (normally zero) from valid vuids.) 123 * 124 */ 125 126int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DATA_BLOB response_blob, const char *smb_name) 127{ 128 user_struct *vuser = NULL; 129 130 /* Ensure no vuid gets registered in share level security. */ 131 if(lp_security() == SEC_SHARE) { 132 data_blob_free(&session_key); 133 return UID_FIELD_INVALID; 134 } 135 136 /* Limit allowed vuids to 16bits - VUID_OFFSET. */ 137 if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) { 138 data_blob_free(&session_key); 139 return UID_FIELD_INVALID; 140 } 141 142 if((vuser = SMB_MALLOC_P(user_struct)) == NULL) { 143 DEBUG(0,("Failed to malloc users struct!\n")); 144 data_blob_free(&session_key); 145 return UID_FIELD_INVALID; 146 } 147 148 ZERO_STRUCTP(vuser); 149 150 /* Allocate a free vuid. Yes this is a linear search... :-) */ 151 while( get_valid_user_struct(next_vuid) != NULL ) { 152 next_vuid++; 153 /* Check for vuid wrap. */ 154 if (next_vuid == UID_FIELD_INVALID) 155 next_vuid = VUID_OFFSET; 156 } 157 158 DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid )); 159 160 vuser->vuid = next_vuid; 161 162 /* the next functions should be done by a SID mapping system (SMS) as 163 * the new real sam db won't have reference to unix uids or gids 164 */ 165 166 vuser->uid = server_info->uid; 167 vuser->gid = server_info->gid; 168 169 vuser->n_groups = server_info->n_groups; 170 if (vuser->n_groups) { 171 if (!(vuser->groups = memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) { 172 DEBUG(0,("register_vuid: failed to memdup vuser->groups\n")); 173 data_blob_free(&session_key); 174 free(vuser); 175 free_server_info(&server_info); 176 return UID_FIELD_INVALID; 177 } 178 } 179 180 vuser->guest = server_info->guest; 181 fstrcpy(vuser->user.unix_name, server_info->unix_name); 182 183 /* This is a potentially untrusted username */ 184 alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", sizeof(vuser->user.smb_name)); 185 186 fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account)); 187 fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account)); 188 189 { 190 /* Keep the homedir handy */ 191 const char *homedir = pdb_get_homedir(server_info->sam_account); 192 const char *logon_script = pdb_get_logon_script(server_info->sam_account); 193 194 if (!IS_SAM_DEFAULT(server_info->sam_account, PDB_UNIXHOMEDIR)) { 195 const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); 196 if (unix_homedir) { 197 vuser->unix_homedir = smb_xstrdup(unix_homedir); 198 } 199 } else { 200 struct passwd *passwd = getpwnam_alloc(vuser->user.unix_name); 201 if (passwd) { 202 vuser->unix_homedir = smb_xstrdup(passwd->pw_dir); 203 passwd_free(&passwd); 204 } 205 } 206 207 if (homedir) { 208 vuser->homedir = smb_xstrdup(homedir); 209 } 210 if (logon_script) { 211 vuser->logon_script = smb_xstrdup(logon_script); 212 } 213 } 214 215 vuser->session_key = session_key; 216 217 DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", 218 (unsigned int)vuser->uid, 219 (unsigned int)vuser->gid, 220 vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, vuser->guest )); 221 222 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name)); 223 224 if (server_info->ptok) { 225 vuser->nt_user_token = dup_nt_token(server_info->ptok); 226 } else { 227 DEBUG(1, ("server_info does not contain a user_token - cannot continue\n")); 228 free_server_info(&server_info); 229 data_blob_free(&session_key); 230 SAFE_FREE(vuser->homedir); 231 SAFE_FREE(vuser->unix_homedir); 232 SAFE_FREE(vuser->logon_script); 233 234 SAFE_FREE(vuser); 235 return UID_FIELD_INVALID; 236 } 237 238 /* use this to keep tabs on all our info from the authentication */ 239 vuser->server_info = server_info; 240 241 DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",(int)vuser->uid,vuser->user.unix_name, vuser->vuid)); 242 243 next_vuid++; 244 num_validated_vuids++; 245 246 DLIST_ADD(validated_users, vuser); 247 248 if (!session_claim(vuser)) { 249 DEBUG(1,("Failed to claim session for vuid=%d\n", vuser->vuid)); 250 invalidate_vuid(vuser->vuid); 251 return -1; 252 } 253 254 /* Register a home dir service for this user iff 255 256 (a) This is not a guest connection, 257 (b) we have a home directory defined 258 (c) there s not an existing static share by that name 259 260 If a share exists by this name (autoloaded or not) reuse it . */ 261 262 vuser->homes_snum = -1; 263 264 if ( (!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) 265 { 266 int servicenumber = lp_servicenumber(vuser->user.unix_name); 267 268 if ( servicenumber == -1 ) { 269 DEBUG(3, ("Adding homes service for user '%s' using home directory: '%s'\n", 270 vuser->user.unix_name, vuser->unix_homedir)); 271 vuser->homes_snum = add_home_service(vuser->user.unix_name, 272 vuser->user.unix_name, vuser->unix_homedir); 273 } else { 274 DEBUG(3, ("Using static (or previously created) service for user '%s'; path = '%s'\n", 275 vuser->user.unix_name, lp_pathname(servicenumber) )); 276 vuser->homes_snum = servicenumber; 277 } 278 } 279 280 if (srv_is_signing_negotiated() && !vuser->guest && !srv_signing_started()) { 281 /* Try and turn on server signing on the first non-guest sessionsetup. */ 282 srv_set_signing(vuser->session_key, response_blob); 283 } 284 285 /* fill in the current_user_info struct */ 286 set_current_user_info( &vuser->user ); 287 288 289 return vuser->vuid; 290} 291 292/**************************************************************************** 293 Add a name to the session users list. 294****************************************************************************/ 295 296void add_session_user(const char *user) 297{ 298 fstring suser; 299 struct passwd *passwd; 300 301 if (!(passwd = Get_Pwnam(user))) 302 return; 303 304 fstrcpy(suser,passwd->pw_name); 305 306 if(!*suser) 307 return; 308 309 if( session_userlist && in_list(suser,session_userlist,False) ) 310 return; 311 312 if( !session_userlist || (strlen(suser) + strlen(session_userlist) + 2 >= len_session_userlist) ) { 313 char *newlist; 314 315 if (len_session_userlist > 128 * PSTRING_LEN) { 316 DEBUG(3,("add_session_user: session userlist already too large.\n")); 317 return; 318 } 319 newlist = SMB_REALLOC( session_userlist, len_session_userlist + PSTRING_LEN ); 320 if( newlist == NULL ) { 321 DEBUG(1,("Unable to resize session_userlist\n")); 322 return; 323 } 324 if (!session_userlist) { 325 *newlist = '\0'; 326 } 327 session_userlist = newlist; 328 len_session_userlist += PSTRING_LEN; 329 } 330 331 safe_strcat(session_userlist," ",len_session_userlist-1); 332 safe_strcat(session_userlist,suser,len_session_userlist-1); 333} 334 335/**************************************************************************** 336 Check if a username is valid. 337****************************************************************************/ 338 339BOOL user_ok(const char *user,int snum, gid_t *groups, size_t n_groups) 340{ 341 char **valid, **invalid; 342 BOOL ret; 343 344 valid = invalid = NULL; 345 ret = True; 346 347 if (lp_invalid_users(snum)) { 348 str_list_copy(&invalid, lp_invalid_users(snum)); 349 if (invalid && str_list_substitute(invalid, "%S", lp_servicename(snum))) { 350 if ( invalid && str_list_sub_basic(invalid, current_user_info.smb_name) ) { 351 ret = !user_in_list(user, (const char **)invalid, groups, n_groups); 352 } 353 } 354 } 355 if (invalid) 356 str_list_free (&invalid); 357 358 if (ret && lp_valid_users(snum)) { 359 str_list_copy(&valid, lp_valid_users(snum)); 360 if ( valid && str_list_substitute(valid, "%S", lp_servicename(snum)) ) { 361 if ( valid && str_list_sub_basic(valid, current_user_info.smb_name) ) { 362 ret = user_in_list(user, (const char **)valid, groups, n_groups); 363 } 364 } 365 } 366 if (valid) 367 str_list_free (&valid); 368 369 if (ret && lp_onlyuser(snum)) { 370 char **user_list = str_list_make (lp_username(snum), NULL); 371 if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { 372 ret = user_in_list(user, (const char **)user_list, groups, n_groups); 373 } 374 if (user_list) str_list_free (&user_list); 375 } 376 377 return(ret); 378} 379 380/**************************************************************************** 381 Validate a group username entry. Return the username or NULL. 382****************************************************************************/ 383 384static char *validate_group(char *group, DATA_BLOB password,int snum) 385{ 386#ifdef HAVE_NETGROUP 387 { 388 char *host, *user, *domain; 389 setnetgrent(group); 390 while (getnetgrent(&host, &user, &domain)) { 391 if (user) { 392 if (user_ok(user, snum, NULL, 0) && 393 password_ok(user,password)) { 394 endnetgrent(); 395 return(user); 396 } 397 } 398 } 399 endnetgrent(); 400 } 401#endif 402 403#ifdef HAVE_GETGRENT 404 { 405 struct group *gptr; 406 setgrent(); 407 while ((gptr = (struct group *)getgrent())) { 408 if (strequal(gptr->gr_name,group)) 409 break; 410 } 411 412 /* 413 * As user_ok can recurse doing a getgrent(), we must 414 * copy the member list into a pstring on the stack before 415 * use. Bug pointed out by leon@eatworms.swmed.edu. 416 */ 417 418 if (gptr) { 419 pstring member_list; 420 char *member; 421 size_t copied_len = 0; 422 int i; 423 424 *member_list = '\0'; 425 member = member_list; 426 427 for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) { 428 size_t member_len = strlen(gptr->gr_mem[i]) + 1; 429 if( copied_len + member_len < sizeof(pstring)) { 430 431 DEBUG(10,("validate_group: = gr_mem = %s\n", gptr->gr_mem[i])); 432 433 safe_strcpy(member, gptr->gr_mem[i], sizeof(pstring) - copied_len - 1); 434 copied_len += member_len; 435 member += copied_len; 436 } else { 437 *member = '\0'; 438 } 439 } 440 441 endgrent(); 442 443 member = member_list; 444 while (*member) { 445 static fstring name; 446 fstrcpy(name,member); 447 if (user_ok(name,snum, NULL, 0) && 448 password_ok(name,password)) { 449 endgrent(); 450 return(&name[0]); 451 } 452 453 DEBUG(10,("validate_group = member = %s\n", member)); 454 455 member += strlen(member) + 1; 456 } 457 } else { 458 endgrent(); 459 return NULL; 460 } 461 } 462#endif 463 return(NULL); 464} 465 466/**************************************************************************** 467 Check for authority to login to a service with a given username/password. 468 Note this is *NOT* used when logging on using sessionsetup_and_X. 469****************************************************************************/ 470 471BOOL authorise_login(int snum, fstring user, DATA_BLOB password, 472 BOOL *guest) 473{ 474 BOOL ok = False; 475 476#ifdef DEBUG_PASSWORD 477 DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s\n", 478 user,password.data)); 479#endif 480 481 *guest = False; 482 483 /* there are several possibilities: 484 1) login as the given user with given password 485 2) login as a previously registered username with the given password 486 3) login as a session list username with the given password 487 4) login as a previously validated user/password pair 488 5) login as the "user =" user with given password 489 6) login as the "user =" user with no password (guest connection) 490 7) login as guest user with no password 491 492 if the service is guest_only then steps 1 to 5 are skipped 493 */ 494 495 /* now check the list of session users */ 496 if (!ok) { 497 char *auser; 498 char *user_list = NULL; 499 500 if ( session_userlist ) 501 user_list = SMB_STRDUP(session_userlist); 502 else 503 user_list = SMB_STRDUP(""); 504 505 if (!user_list) 506 return(False); 507 508 for (auser=strtok(user_list,LIST_SEP); !ok && auser; 509 auser = strtok(NULL,LIST_SEP)) { 510 fstring user2; 511 fstrcpy(user2,auser); 512 if (!user_ok(user2,snum, NULL, 0)) 513 continue; 514 515 if (password_ok(user2,password)) { 516 ok = True; 517 fstrcpy(user,user2); 518 DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \ 519and given password ok\n", user)); 520 } 521 } 522 523 SAFE_FREE(user_list); 524 } 525 526 /* check the user= fields and the given password */ 527 if (!ok && lp_username(snum)) { 528 char *auser; 529 pstring user_list; 530 pstrcpy(user_list,lp_username(snum)); 531 532 pstring_sub(user_list,"%S",lp_servicename(snum)); 533 534 for (auser=strtok(user_list,LIST_SEP); auser && !ok; 535 auser = strtok(NULL,LIST_SEP)) { 536 if (*auser == '@') { 537 auser = validate_group(auser+1,password,snum); 538 if (auser) { 539 ok = True; 540 fstrcpy(user,auser); 541 DEBUG(3,("authorise_login: ACCEPTED: group username \ 542and given password ok (%s)\n", user)); 543 } 544 } else { 545 fstring user2; 546 fstrcpy(user2,auser); 547 if (user_ok(user2,snum, NULL, 0) && password_ok(user2,password)) { 548 ok = True; 549 fstrcpy(user,user2); 550 DEBUG(3,("authorise_login: ACCEPTED: user list username \ 551and given password ok (%s)\n", user)); 552 } 553 } 554 } 555 } 556 557 /* check for a normal guest connection */ 558 if (!ok && GUEST_OK(snum)) { 559 fstring guestname; 560 fstrcpy(guestname,lp_guestaccount()); 561 if (Get_Pwnam(guestname)) { 562 fstrcpy(user,guestname); 563 ok = True; 564 DEBUG(3,("authorise_login: ACCEPTED: guest account and guest ok (%s)\n", 565 user)); 566 } else { 567 DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname)); 568 } 569 *guest = True; 570 } 571 572 if (ok && !user_ok(user, snum, NULL, 0)) { 573 DEBUG(0,("authorise_login: rejected invalid user %s\n",user)); 574 ok = False; 575 } 576 577 return(ok); 578} 579