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 */ 24 25 #include <sys/types.h> 26 #include <sys/sid.h> 27 #include <sys/priv_names.h> 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 #include <smbsrv/smb_idmap.h> 31 #include <smbsrv/smb_kproto.h> 32 #include <smbsrv/smb_token.h> 33 34 static int smb_authenticate(smb_request_t *, smb_arg_sessionsetup_t *, 35 smb_session_key_t **); 36 static cred_t *smb_cred_create(smb_token_t *); 37 static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid); 38 static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps); 39 static uint32_t smb_priv_xlate(smb_token_t *); 40 41 /* 42 * In NTLM 0.12, the padding between the Native OS and Native LM is a bit 43 * strange. On NT4.0, there is a 2 byte pad between the OS (Windows NT 1381) 44 * and LM (Windows NT 4.0). On Windows 2000, there is no padding between 45 * the OS (Windows 2000 2195) and LM (Windows 2000 5.0). 46 * If the padding is removed from the decode string the NT4.0 LM comes out 47 * as an empty string. So if the client's native OS is Win NT we consider 48 * the padding otherwise we don't. 49 * 50 * For Pre-NTLM 0.12, despite the CIFS/1.0 spec, the user and domain are 51 * not always present in the message. We try to get the account name and 52 * the primary domain but we don't care about the the native OS or native 53 * LM fields. 54 * 55 * If the Native LM cannot be determined, default to Windows NT. 56 */ 57 smb_sdrc_t 58 smb_pre_session_setup_andx(smb_request_t *sr) 59 { 60 smb_arg_sessionsetup_t *sinfo; 61 char *native_os; 62 char *native_lm; 63 uint16_t maxbufsize; 64 uint16_t vcnumber; 65 int rc = 0; 66 67 sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t)); 68 sr->sr_ssetup = sinfo; 69 70 if (sr->session->dialect >= NT_LM_0_12) { 71 rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com, 72 &sr->andx_off, &maxbufsize, 73 &sinfo->ssi_maxmpxcount, &vcnumber, 74 &sinfo->ssi_sesskey, &sinfo->ssi_cipwlen, 75 &sinfo->ssi_cspwlen, &sinfo->ssi_capabilities); 76 if (rc != 0) 77 goto pre_session_setup_andx_done; 78 79 sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1); 80 sinfo->ssi_cspwd = smb_srm_zalloc(sr, sinfo->ssi_cspwlen + 1); 81 82 rc = smbsr_decode_data(sr, "%#c#cuuu", 83 sr, 84 sinfo->ssi_cipwlen, sinfo->ssi_cipwd, 85 sinfo->ssi_cspwlen, sinfo->ssi_cspwd, 86 &sinfo->ssi_user, 87 &sinfo->ssi_domain, 88 &native_os); 89 if (rc != 0) 90 goto pre_session_setup_andx_done; 91 92 sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0; 93 sinfo->ssi_cspwd[sinfo->ssi_cspwlen] = 0; 94 95 sr->session->native_os = smbnative_os_value(native_os); 96 97 if (sr->session->native_os == NATIVE_OS_WINNT) 98 rc = smbsr_decode_data(sr, "%,u", sr, &native_lm); 99 else 100 rc = smbsr_decode_data(sr, "%u", sr, &native_lm); 101 102 if (rc != 0 || native_lm == NULL) 103 native_lm = "NT LAN Manager 4.0"; 104 105 sr->session->native_lm = smbnative_lm_value(native_lm); 106 } else { 107 rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com, 108 &sr->andx_off, &maxbufsize, 109 &sinfo->ssi_maxmpxcount, &vcnumber, 110 &sinfo->ssi_sesskey, &sinfo->ssi_cipwlen); 111 if (rc != 0) 112 goto pre_session_setup_andx_done; 113 114 sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1); 115 rc = smbsr_decode_data(sr, "%#c", sr, sinfo->ssi_cipwlen, 116 sinfo->ssi_cipwd); 117 if (rc != 0) 118 goto pre_session_setup_andx_done; 119 120 sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0; 121 122 if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_user) != 0) 123 sinfo->ssi_user = ""; 124 125 if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_domain) != 0) 126 sinfo->ssi_domain = ""; 127 128 native_lm = "NT LAN Manager 4.0"; 129 sr->session->native_os = NATIVE_OS_WINNT; 130 sr->session->native_lm = smbnative_lm_value(native_lm); 131 } 132 133 sr->session->vcnumber = vcnumber; 134 sr->session->smb_msg_size = maxbufsize; 135 136 pre_session_setup_andx_done: 137 DTRACE_SMB_2(op__SessionSetupX__start, smb_request_t *, sr, 138 smb_arg_sessionsetup_t, sinfo); 139 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 140 } 141 142 void 143 smb_post_session_setup_andx(smb_request_t *sr) 144 { 145 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; 146 147 DTRACE_SMB_2(op__SessionSetupX__done, smb_request_t *, sr, 148 smb_arg_sessionsetup_t, sinfo); 149 150 if (sinfo->ssi_cipwd != NULL) 151 bzero(sinfo->ssi_cipwd, sinfo->ssi_cipwlen + 1); 152 153 if (sinfo->ssi_cspwd != NULL) 154 bzero(sinfo->ssi_cspwd, sinfo->ssi_cspwlen + 1); 155 } 156 157 /* 158 * If the vcnumber is zero, discard any other connections associated with 159 * this client. 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 smb_session_key_t *session_key = NULL; 178 char ipaddr_buf[INET6_ADDRSTRLEN]; 179 int rc; 180 181 if (sr->session->vcnumber == 0) 182 smb_server_reconnection_check(sr->sr_server, sr->session); 183 184 if (smb_authenticate(sr, sinfo, &session_key) != 0) 185 return (SDRC_ERROR); 186 187 if (sr->session->native_lm == NATIVE_LM_WIN2000) 188 sinfo->ssi_capabilities |= CAP_LARGE_FILES | 189 CAP_LARGE_READX | CAP_LARGE_WRITEX; 190 191 sr->session->capabilities = sinfo->ssi_capabilities; 192 193 if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) && 194 (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && 195 (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) && 196 session_key) 197 smb_sign_init(sr, session_key, (char *)sinfo->ssi_cspwd, 198 sinfo->ssi_cspwlen); 199 200 if (!(sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) && 201 (sr->sr_cfg->skc_signing_required)) { 202 (void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf, 203 SMB_IPSTRLEN(sr->session->ipaddr.a_family)); 204 cmn_err(CE_NOTE, 205 "SmbSessonSetupX: client %s does not support signing", 206 ipaddr_buf); 207 smbsr_error(sr, NT_STATUS_LOGON_FAILURE, 208 ERRDOS, ERROR_LOGON_FAILURE); 209 return (SDRC_ERROR); 210 } 211 212 rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu", 213 3, 214 sr->andx_com, 215 -1, /* andx_off */ 216 sinfo->ssi_guest ? 1 : 0, 217 VAR_BCC, 218 sr, 219 smbnative_os_str(&sr->sr_cfg->skc_version), 220 smbnative_lm_str(&sr->sr_cfg->skc_version), 221 sr->sr_cfg->skc_nbdomain); 222 223 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 224 } 225 226 /* 227 * Authenticate a user. If the user has already been authenticated on 228 * this session, we can simply dup the user and return. 229 * 230 * Otherwise, the user information is passed to smbd for authentication. 231 * If smbd can authenticate the user an access token is returned and we 232 * generate a cred and new user based on the token. 233 */ 234 static int 235 smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo, 236 smb_session_key_t **session_key) 237 { 238 char *hostname = sr->sr_cfg->skc_hostname; 239 int security = sr->sr_cfg->skc_secmode; 240 smb_token_t *token = NULL; 241 smb_user_t *user = NULL; 242 smb_logon_t user_info; 243 boolean_t need_lookup = B_FALSE; 244 uint32_t privileges; 245 cred_t *cr; 246 char *buf = NULL; 247 char *p; 248 249 bzero(&user_info, sizeof (smb_logon_t)); 250 user_info.lg_e_domain = sinfo->ssi_domain; 251 252 if ((*sinfo->ssi_user == '\0') && 253 (sinfo->ssi_cspwlen == 0) && 254 (sinfo->ssi_cipwlen == 0 || 255 (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == '\0'))) { 256 user_info.lg_e_username = "anonymous"; 257 user_info.lg_flags |= SMB_ATF_ANON; 258 } else { 259 user_info.lg_e_username = sinfo->ssi_user; 260 } 261 262 /* 263 * Handle user@domain format. We need to retain the original 264 * data as this is important in some forms of authentication. 265 */ 266 if (*sinfo->ssi_domain == '\0') { 267 buf = smb_srm_strdup(sr, sinfo->ssi_user); 268 if ((p = strchr(buf, '@')) != NULL) { 269 *p = '\0'; 270 user_info.lg_e_username = buf; 271 user_info.lg_e_domain = p + 1; 272 } 273 } 274 275 /* 276 * If no domain name has been provided in domain mode we cannot 277 * determine if this is a local user or a domain user without 278 * obtaining an access token. So we postpone the lookup until 279 * after authentication. 280 */ 281 if (security == SMB_SECMODE_WORKGRP) { 282 user = smb_session_dup_user(sr->session, hostname, 283 user_info.lg_e_username); 284 } else if (*user_info.lg_e_domain != '\0') { 285 user = smb_session_dup_user(sr->session, user_info.lg_e_domain, 286 user_info.lg_e_username); 287 } else { 288 need_lookup = B_TRUE; 289 } 290 291 if (user != NULL) { 292 sinfo->ssi_guest = SMB_USER_IS_GUEST(user); 293 sr->user_cr = user->u_cred; 294 sr->smb_uid = user->u_uid; 295 sr->uid_user = user; 296 return (0); 297 } 298 299 user_info.lg_level = NETR_NETWORK_LOGON; 300 user_info.lg_domain = sinfo->ssi_domain; 301 user_info.lg_username = sinfo->ssi_user; 302 user_info.lg_workstation = sr->session->workstation; 303 user_info.lg_clnt_ipaddr = sr->session->ipaddr; 304 user_info.lg_local_ipaddr = sr->session->local_ipaddr; 305 user_info.lg_local_port = sr->session->s_local_port; 306 user_info.lg_challenge_key.val = sr->session->challenge_key; 307 user_info.lg_challenge_key.len = sr->session->challenge_len; 308 user_info.lg_nt_password.val = sinfo->ssi_cspwd; 309 user_info.lg_nt_password.len = sinfo->ssi_cspwlen; 310 user_info.lg_lm_password.val = sinfo->ssi_cipwd; 311 user_info.lg_lm_password.len = sinfo->ssi_cipwlen; 312 user_info.lg_native_os = sr->session->native_os; 313 user_info.lg_native_lm = sr->session->native_lm; 314 315 DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *, &user_info); 316 317 if ((token = smb_get_token(&user_info)) == NULL) { 318 smbsr_error(sr, 0, ERRSRV, ERRbadpw); 319 return (-1); 320 } 321 322 if (need_lookup) { 323 user = smb_session_dup_user(sr->session, 324 token->tkn_domain_name, token->tkn_account_name); 325 if (user != NULL) { 326 sinfo->ssi_guest = SMB_USER_IS_GUEST(user); 327 sr->user_cr = user->u_cred; 328 sr->smb_uid = user->u_uid; 329 sr->uid_user = user; 330 smb_token_free(token); 331 return (0); 332 } 333 } 334 335 if (token->tkn_session_key) { 336 *session_key = smb_srm_zalloc(sr, sizeof (smb_session_key_t)); 337 bcopy(token->tkn_session_key, *session_key, 338 sizeof (smb_session_key_t)); 339 } 340 341 if ((cr = smb_cred_create(token)) == NULL) { 342 smb_token_free(token); 343 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE); 344 return (-1); 345 } 346 347 privileges = smb_priv_xlate(token); 348 349 user = smb_user_login(sr->session, cr, 350 token->tkn_domain_name, token->tkn_account_name, 351 token->tkn_flags, privileges, token->tkn_audit_sid); 352 353 crfree(cr); 354 smb_token_free(token); 355 356 if (user == NULL) { 357 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE); 358 return (-1); 359 } 360 361 sinfo->ssi_guest = SMB_USER_IS_GUEST(user); 362 sr->user_cr = user->u_cred; 363 sr->smb_uid = user->u_uid; 364 sr->uid_user = user; 365 return (0); 366 } 367 368 /* 369 * Allocate a Solaris cred and initialize it based on the access token. 370 * 371 * If the user can be mapped to a non-ephemeral ID, the cred gid is set 372 * to the Solaris user's primary group. 373 * 374 * If the mapped UID is ephemeral, or the primary group could not be 375 * obtained, the cred gid is set to whatever Solaris group is mapped 376 * to the token's primary group. 377 */ 378 static cred_t * 379 smb_cred_create(smb_token_t *token) 380 { 381 ksid_t ksid; 382 ksidlist_t *ksidlist = NULL; 383 smb_posix_grps_t *posix_grps; 384 cred_t *cr; 385 gid_t gid; 386 387 ASSERT(token); 388 ASSERT(token->tkn_posix_grps); 389 posix_grps = token->tkn_posix_grps; 390 391 cr = crget(); 392 ASSERT(cr != NULL); 393 394 if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) && 395 (posix_grps->pg_ngrps != 0)) { 396 gid = posix_grps->pg_grps[0]; 397 } else { 398 gid = token->tkn_primary_grp.i_id; 399 } 400 401 if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) { 402 crfree(cr); 403 return (NULL); 404 } 405 406 if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) { 407 crfree(cr); 408 return (NULL); 409 } 410 411 smb_cred_set_sid(&token->tkn_user, &ksid); 412 crsetsid(cr, &ksid, KSID_USER); 413 smb_cred_set_sid(&token->tkn_primary_grp, &ksid); 414 crsetsid(cr, &ksid, KSID_GROUP); 415 smb_cred_set_sid(&token->tkn_owner, &ksid); 416 crsetsid(cr, &ksid, KSID_OWNER); 417 ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps); 418 crsetsidlist(cr, ksidlist); 419 420 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) 421 (void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL); 422 423 return (cr); 424 } 425 426 /* 427 * Initialize the ksid based on the given smb_id_t. 428 */ 429 static void 430 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid) 431 { 432 char sidstr[SMB_SID_STRSZ]; 433 int rc; 434 435 ASSERT(id); 436 ASSERT(id->i_sid); 437 438 ksid->ks_id = id->i_id; 439 smb_sid_tostr(id->i_sid, sidstr); 440 rc = smb_sid_splitstr(sidstr, &ksid->ks_rid); 441 ASSERT(rc == 0); 442 443 ksid->ks_attr = id->i_attrs; 444 ksid->ks_domain = ksid_lookupdomain(sidstr); 445 } 446 447 /* 448 * Allocate and initialize the ksidlist based on the access token group list. 449 */ 450 static ksidlist_t * 451 smb_cred_set_sidlist(smb_ids_t *token_grps) 452 { 453 int i; 454 ksidlist_t *lp; 455 456 lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP); 457 lp->ksl_ref = 1; 458 lp->ksl_nsid = token_grps->i_cnt; 459 lp->ksl_neid = 0; 460 461 for (i = 0; i < lp->ksl_nsid; i++) { 462 smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]); 463 if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID) 464 lp->ksl_neid++; 465 } 466 467 return (lp); 468 } 469 470 /* 471 * Convert access token privileges to local definitions. 472 */ 473 static uint32_t 474 smb_priv_xlate(smb_token_t *token) 475 { 476 uint32_t privileges = 0; 477 478 if (smb_token_query_privilege(token, SE_BACKUP_LUID)) 479 privileges |= SMB_USER_PRIV_BACKUP; 480 481 if (smb_token_query_privilege(token, SE_RESTORE_LUID)) 482 privileges |= SMB_USER_PRIV_RESTORE; 483 484 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) 485 privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP; 486 487 if (smb_token_query_privilege(token, SE_SECURITY_LUID)) 488 privileges |= SMB_USER_PRIV_SECURITY; 489 490 return (privileges); 491 } 492