1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/sid.h> 28 #include <sys/priv_names.h> 29 #include <sys/socket.h> 30 #include <netinet/in.h> 31 #include <smbsrv/smb_idmap.h> 32 #include <smbsrv/smb_kproto.h> 33 #include <smbsrv/smb_token.h> 34 35 static int smb_authenticate(smb_request_t *, smb_arg_sessionsetup_t *); 36 static int smb_authenticate_core(smb_request_t *, smb_arg_sessionsetup_t *); 37 static uint32_t smb_priv_xlate(smb_token_t *); 38 #ifdef _KERNEL 39 static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid); 40 static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps); 41 #endif /* _KERNEL */ 42 43 /* 44 * In NTLM 0.12, the padding between the Native OS and Native LM is a bit 45 * strange. On NT4.0, there is a 2 byte pad between the OS (Windows NT 1381) 46 * and LM (Windows NT 4.0). On Windows 2000, there is no padding between 47 * the OS (Windows 2000 2195) and LM (Windows 2000 5.0). 48 * If the padding is removed from the decode string the NT4.0 LM comes out 49 * as an empty string. So if the client's native OS is Win NT we consider 50 * the padding otherwise we don't. 51 * 52 * For Pre-NTLM 0.12, despite the CIFS/1.0 spec, the user and domain are 53 * not always present in the message. We try to get the account name and 54 * the primary domain but we don't care about the the native OS or native 55 * LM fields. 56 * 57 * If the Native LM cannot be determined, default to Windows NT. 58 */ 59 smb_sdrc_t 60 smb_pre_session_setup_andx(smb_request_t *sr) 61 { 62 smb_arg_sessionsetup_t *sinfo; 63 char *native_os; 64 char *native_lm; 65 uint32_t junk_sesskey; 66 uint16_t maxbufsize; 67 uint16_t vcnumber; 68 int rc = 0; 69 70 sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t)); 71 sr->sr_ssetup = sinfo; 72 73 if (sr->session->dialect >= NT_LM_0_12) { 74 rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com, 75 &sr->andx_off, &maxbufsize, 76 &sinfo->ssi_maxmpxcount, &vcnumber, 77 &junk_sesskey, &sinfo->ssi_cipwlen, 78 &sinfo->ssi_cspwlen, &sinfo->ssi_capabilities); 79 if (rc != 0) 80 goto pre_session_setup_andx_done; 81 82 sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1); 83 sinfo->ssi_cspwd = smb_srm_zalloc(sr, sinfo->ssi_cspwlen + 1); 84 85 rc = smbsr_decode_data(sr, "%#c#cuuu", 86 sr, 87 sinfo->ssi_cipwlen, sinfo->ssi_cipwd, 88 sinfo->ssi_cspwlen, sinfo->ssi_cspwd, 89 &sinfo->ssi_user, 90 &sinfo->ssi_domain, 91 &native_os); 92 if (rc != 0) 93 goto pre_session_setup_andx_done; 94 95 sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0; 96 sinfo->ssi_cspwd[sinfo->ssi_cspwlen] = 0; 97 98 sr->session->native_os = smbnative_os_value(native_os); 99 100 if (sr->session->native_os == NATIVE_OS_WINNT) 101 rc = smbsr_decode_data(sr, "%,u", sr, &native_lm); 102 else 103 rc = smbsr_decode_data(sr, "%u", sr, &native_lm); 104 105 if (rc != 0 || native_lm == NULL) 106 native_lm = "NT LAN Manager 4.0"; 107 108 sr->session->native_lm = smbnative_lm_value(native_lm); 109 } else { 110 rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com, 111 &sr->andx_off, &maxbufsize, 112 &sinfo->ssi_maxmpxcount, &vcnumber, 113 &junk_sesskey, &sinfo->ssi_cipwlen); 114 if (rc != 0) 115 goto pre_session_setup_andx_done; 116 117 sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1); 118 rc = smbsr_decode_data(sr, "%#c", sr, sinfo->ssi_cipwlen, 119 sinfo->ssi_cipwd); 120 if (rc != 0) 121 goto pre_session_setup_andx_done; 122 123 sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0; 124 125 if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_user) != 0) 126 sinfo->ssi_user = ""; 127 128 if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_domain) != 0) 129 sinfo->ssi_domain = ""; 130 131 native_lm = "NT LAN Manager 4.0"; 132 sr->session->native_os = NATIVE_OS_WINNT; 133 sr->session->native_lm = smbnative_lm_value(native_lm); 134 } 135 136 sr->session->vcnumber = vcnumber; 137 sr->session->smb_msg_size = maxbufsize; 138 139 pre_session_setup_andx_done: 140 DTRACE_SMB_2(op__SessionSetupX__start, smb_request_t *, sr, 141 smb_arg_sessionsetup_t, sinfo); 142 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 143 } 144 145 void 146 smb_post_session_setup_andx(smb_request_t *sr) 147 { 148 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; 149 150 DTRACE_SMB_2(op__SessionSetupX__done, smb_request_t *, sr, 151 smb_arg_sessionsetup_t, sinfo); 152 153 if (sinfo->ssi_cipwd != NULL) 154 bzero(sinfo->ssi_cipwd, sinfo->ssi_cipwlen + 1); 155 156 if (sinfo->ssi_cspwd != NULL) 157 bzero(sinfo->ssi_cspwd, sinfo->ssi_cspwlen + 1); 158 } 159 160 /* 161 * If signing has not already been enabled on this session check to see if 162 * it should be enabled. The first authenticated logon provides the MAC 163 * key and sequence numbers for signing all subsequent sessions on the same 164 * connection. 165 * 166 * NT systems use different native OS and native LanMan values dependent on 167 * whether they are acting as a client or a server. NT 4.0 server responds 168 * with the following values: 169 * 170 * NativeOS: Windows NT 4.0 171 * NativeLM: NT LAN Manager 4.0 172 */ 173 smb_sdrc_t 174 smb_com_session_setup_andx(smb_request_t *sr) 175 { 176 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; 177 int rc; 178 179 if (smb_authenticate(sr, sinfo) != 0) 180 return (SDRC_ERROR); 181 182 if (sr->session->native_lm == NATIVE_LM_WIN2000) 183 sinfo->ssi_capabilities |= CAP_LARGE_FILES | 184 CAP_LARGE_READX | CAP_LARGE_WRITEX; 185 186 if (!smb_oplock_levelII) 187 sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS; 188 189 sr->session->capabilities = sinfo->ssi_capabilities; 190 191 rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu", 192 3, 193 sr->andx_com, 194 -1, /* andx_off */ 195 sinfo->ssi_guest ? 1 : 0, 196 VAR_BCC, 197 sr, 198 smbnative_os_str(&sr->sr_cfg->skc_version), 199 smbnative_lm_str(&sr->sr_cfg->skc_version), 200 sr->sr_cfg->skc_nbdomain); 201 202 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 203 } 204 205 static int 206 smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo) 207 { 208 int rc; 209 smb_server_t *sv = sr->sr_server; 210 211 if (smb_threshold_enter(&sv->sv_ssetup_ct) != 0) { 212 smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0); 213 return (-1); 214 } 215 216 rc = smb_authenticate_core(sr, sinfo); 217 smb_threshold_exit(&sv->sv_ssetup_ct); 218 return (rc); 219 } 220 221 /* 222 * Authenticate a user. If the user has already been authenticated on 223 * this session, we can simply dup the user and return. 224 * 225 * Otherwise, the user information is passed to smbd for authentication. 226 * If smbd can authenticate the user an access token is returned and we 227 * generate a cred and new user based on the token. 228 */ 229 static int 230 smb_authenticate_core(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo) 231 { 232 char *hostname = sr->sr_cfg->skc_hostname; 233 int security = sr->sr_cfg->skc_secmode; 234 smb_token_t *token = NULL; 235 smb_user_t *user = NULL; 236 smb_logon_t user_info; 237 boolean_t need_lookup = B_FALSE; 238 uint32_t privileges; 239 cred_t *cr; 240 char *buf = NULL; 241 char *p; 242 243 bzero(&user_info, sizeof (smb_logon_t)); 244 user_info.lg_e_domain = sinfo->ssi_domain; 245 246 if ((*sinfo->ssi_user == '\0') && 247 (sinfo->ssi_cspwlen == 0) && 248 (sinfo->ssi_cipwlen == 0 || 249 (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == '\0'))) { 250 user_info.lg_e_username = "anonymous"; 251 user_info.lg_flags |= SMB_ATF_ANON; 252 } else { 253 user_info.lg_e_username = sinfo->ssi_user; 254 } 255 256 /* 257 * Handle user@domain format. We need to retain the original 258 * data as this is important in some forms of authentication. 259 */ 260 if (*sinfo->ssi_domain == '\0') { 261 buf = smb_srm_strdup(sr, sinfo->ssi_user); 262 if ((p = strchr(buf, '@')) != NULL) { 263 *p = '\0'; 264 user_info.lg_e_username = buf; 265 user_info.lg_e_domain = p + 1; 266 } 267 } 268 269 /* 270 * If no domain name has been provided in domain mode we cannot 271 * determine if this is a local user or a domain user without 272 * obtaining an access token. So we postpone the lookup until 273 * after authentication. 274 */ 275 if (security == SMB_SECMODE_WORKGRP) { 276 user = smb_session_dup_user(sr->session, hostname, 277 user_info.lg_e_username); 278 } else if (*user_info.lg_e_domain != '\0') { 279 user = smb_session_dup_user(sr->session, user_info.lg_e_domain, 280 user_info.lg_e_username); 281 } else { 282 need_lookup = B_TRUE; 283 } 284 285 if (user != NULL) { 286 sinfo->ssi_guest = SMB_USER_IS_GUEST(user); 287 sr->user_cr = user->u_cred; 288 sr->smb_uid = user->u_uid; 289 sr->uid_user = user; 290 return (0); 291 } 292 293 user_info.lg_level = NETR_NETWORK_LOGON; 294 user_info.lg_domain = sinfo->ssi_domain; 295 user_info.lg_username = sinfo->ssi_user; 296 user_info.lg_workstation = sr->session->workstation; 297 user_info.lg_clnt_ipaddr = sr->session->ipaddr; 298 user_info.lg_local_ipaddr = sr->session->local_ipaddr; 299 user_info.lg_local_port = sr->session->s_local_port; 300 user_info.lg_challenge_key.val = sr->session->challenge_key; 301 user_info.lg_challenge_key.len = sr->session->challenge_len; 302 user_info.lg_nt_password.val = sinfo->ssi_cspwd; 303 user_info.lg_nt_password.len = sinfo->ssi_cspwlen; 304 user_info.lg_lm_password.val = sinfo->ssi_cipwd; 305 user_info.lg_lm_password.len = sinfo->ssi_cipwlen; 306 user_info.lg_native_os = sr->session->native_os; 307 user_info.lg_native_lm = sr->session->native_lm; 308 309 DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *, &user_info); 310 311 if ((token = smb_get_token(sr->session, &user_info)) == NULL) { 312 smbsr_error(sr, 0, ERRSRV, ERRbadpw); 313 return (-1); 314 } 315 316 if (need_lookup) { 317 user = smb_session_dup_user(sr->session, 318 token->tkn_domain_name, token->tkn_account_name); 319 if (user != NULL) { 320 sinfo->ssi_guest = SMB_USER_IS_GUEST(user); 321 sr->user_cr = user->u_cred; 322 sr->smb_uid = user->u_uid; 323 sr->uid_user = user; 324 smb_token_free(token); 325 return (0); 326 } 327 } 328 329 if ((cr = smb_cred_create(token)) == NULL) { 330 smb_token_free(token); 331 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE); 332 return (-1); 333 } 334 335 privileges = smb_priv_xlate(token); 336 337 user = smb_user_login(sr->session, cr, 338 token->tkn_domain_name, token->tkn_account_name, 339 token->tkn_flags, privileges, token->tkn_audit_sid); 340 crfree(cr); 341 342 /* 343 * Save the session key, and (maybe) enable signing, 344 * but only for real logon (not ANON or GUEST). 345 */ 346 if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) 347 (void) smb_sign_begin(sr, token); 348 349 smb_token_free(token); 350 351 if (user == NULL) { 352 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE); 353 return (-1); 354 } 355 356 sinfo->ssi_guest = SMB_USER_IS_GUEST(user); 357 sr->user_cr = user->u_cred; 358 sr->smb_uid = user->u_uid; 359 sr->uid_user = user; 360 return (0); 361 } 362 363 #ifdef _KERNEL 364 /* 365 * Allocate a Solaris cred and initialize it based on the access token. 366 * 367 * If the user can be mapped to a non-ephemeral ID, the cred gid is set 368 * to the Solaris user's primary group. 369 * 370 * If the mapped UID is ephemeral, or the primary group could not be 371 * obtained, the cred gid is set to whatever Solaris group is mapped 372 * to the token's primary group. 373 */ 374 cred_t * 375 smb_cred_create(smb_token_t *token) 376 { 377 ksid_t ksid; 378 ksidlist_t *ksidlist = NULL; 379 smb_posix_grps_t *posix_grps; 380 cred_t *cr; 381 gid_t gid; 382 383 ASSERT(token); 384 ASSERT(token->tkn_posix_grps); 385 posix_grps = token->tkn_posix_grps; 386 387 cr = crget(); 388 ASSERT(cr != NULL); 389 390 if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) && 391 (posix_grps->pg_ngrps != 0)) { 392 gid = posix_grps->pg_grps[0]; 393 } else { 394 gid = token->tkn_primary_grp.i_id; 395 } 396 397 if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) { 398 crfree(cr); 399 return (NULL); 400 } 401 402 if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) { 403 crfree(cr); 404 return (NULL); 405 } 406 407 smb_cred_set_sid(&token->tkn_user, &ksid); 408 crsetsid(cr, &ksid, KSID_USER); 409 smb_cred_set_sid(&token->tkn_primary_grp, &ksid); 410 crsetsid(cr, &ksid, KSID_GROUP); 411 smb_cred_set_sid(&token->tkn_owner, &ksid); 412 crsetsid(cr, &ksid, KSID_OWNER); 413 ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps); 414 crsetsidlist(cr, ksidlist); 415 416 /* 417 * In the AD world, "take ownership privilege" is very much 418 * like having Unix "root" privileges. It's normally given 419 * to members of the "Administrators" group, which normally 420 * includes the the local Administrator (like root) and when 421 * joined to a domain, "Domain Admins". 422 */ 423 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) { 424 (void) crsetpriv(cr, 425 PRIV_FILE_CHOWN, 426 PRIV_FILE_DAC_READ, 427 PRIV_FILE_DAC_SEARCH, 428 PRIV_FILE_DAC_WRITE, 429 PRIV_FILE_OWNER, 430 NULL); 431 } 432 433 return (cr); 434 } 435 436 /* 437 * Initialize the ksid based on the given smb_id_t. 438 */ 439 static void 440 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid) 441 { 442 char sidstr[SMB_SID_STRSZ]; 443 int rc; 444 445 ASSERT(id); 446 ASSERT(id->i_sid); 447 448 ksid->ks_id = id->i_id; 449 smb_sid_tostr(id->i_sid, sidstr); 450 rc = smb_sid_splitstr(sidstr, &ksid->ks_rid); 451 ASSERT(rc == 0); 452 453 ksid->ks_attr = id->i_attrs; 454 ksid->ks_domain = ksid_lookupdomain(sidstr); 455 } 456 457 /* 458 * Allocate and initialize the ksidlist based on the access token group list. 459 */ 460 static ksidlist_t * 461 smb_cred_set_sidlist(smb_ids_t *token_grps) 462 { 463 int i; 464 ksidlist_t *lp; 465 466 lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP); 467 lp->ksl_ref = 1; 468 lp->ksl_nsid = token_grps->i_cnt; 469 lp->ksl_neid = 0; 470 471 for (i = 0; i < lp->ksl_nsid; i++) { 472 smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]); 473 if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID) 474 lp->ksl_neid++; 475 } 476 477 return (lp); 478 } 479 #endif /* _KERNEL */ 480 481 /* 482 * Convert access token privileges to local definitions. 483 */ 484 static uint32_t 485 smb_priv_xlate(smb_token_t *token) 486 { 487 uint32_t privileges = 0; 488 489 if (smb_token_query_privilege(token, SE_BACKUP_LUID)) 490 privileges |= SMB_USER_PRIV_BACKUP; 491 492 if (smb_token_query_privilege(token, SE_RESTORE_LUID)) 493 privileges |= SMB_USER_PRIV_RESTORE; 494 495 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) 496 privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP; 497 498 if (smb_token_query_privilege(token, SE_SECURITY_LUID)) 499 privileges |= SMB_USER_PRIV_SECURITY; 500 501 return (privileges); 502 } 503