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 2017 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Authentication helpers for building credentials 28 */ 29 30 #include <sys/types.h> 31 #include <sys/sid.h> 32 #include <sys/priv_names.h> 33 #include <sys/socket.h> 34 #include <sys/un.h> 35 #include <netinet/in.h> 36 #include <smbsrv/smb_idmap.h> 37 #include <smbsrv/smb_kproto.h> 38 #include <smbsrv/smb_token.h> 39 40 static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid); 41 static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps); 42 43 /* 44 * Allocate a Solaris cred and initialize it based on the access token. 45 * 46 * If the user can be mapped to a non-ephemeral ID, the cred gid is set 47 * to the Solaris user's primary group. 48 * 49 * If the mapped UID is ephemeral, or the primary group could not be 50 * obtained, the cred gid is set to whatever Solaris group is mapped 51 * to the token's primary group. 52 * 53 * Also add any privileges that should always be in effect for this user. 54 * Note that an SMB user object also gets a u_privcred which is used 55 * when the client opens an object with "backup/restore intent". 56 * That cred is setup later, in smb_user_setcred(). 57 */ 58 cred_t * 59 smb_cred_create(smb_token_t *token) 60 { 61 ksid_t ksid; 62 ksidlist_t *ksidlist = NULL; 63 smb_posix_grps_t *posix_grps; 64 cred_t *cr; 65 gid_t gid; 66 67 ASSERT(token); 68 ASSERT(token->tkn_posix_grps); 69 posix_grps = token->tkn_posix_grps; 70 71 cr = crget(); 72 ASSERT(cr != NULL); 73 74 if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) && 75 (posix_grps->pg_ngrps != 0)) { 76 gid = posix_grps->pg_grps[0]; 77 } else { 78 gid = token->tkn_primary_grp.i_id; 79 } 80 81 if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) { 82 crfree(cr); 83 return (NULL); 84 } 85 86 if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) { 87 crfree(cr); 88 return (NULL); 89 } 90 91 smb_cred_set_sid(&token->tkn_user, &ksid); 92 crsetsid(cr, &ksid, KSID_USER); 93 smb_cred_set_sid(&token->tkn_primary_grp, &ksid); 94 crsetsid(cr, &ksid, KSID_GROUP); 95 smb_cred_set_sid(&token->tkn_owner, &ksid); 96 crsetsid(cr, &ksid, KSID_OWNER); 97 ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps); 98 crsetsidlist(cr, ksidlist); 99 100 /* 101 * In the AD world, "take ownership privilege" is very much 102 * like having Unix "root" privileges. It's normally given 103 * to members of the "Administrators" group, which normally 104 * includes the the local Administrator (like root) and when 105 * joined to a domain, "Domain Admins". 106 */ 107 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) { 108 (void) crsetpriv(cr, 109 PRIV_FILE_CHOWN, 110 PRIV_FILE_DAC_READ, 111 PRIV_FILE_DAC_SEARCH, 112 PRIV_FILE_DAC_WRITE, 113 PRIV_FILE_OWNER, 114 NULL); 115 } 116 117 /* 118 * See smb.4 bypass_traverse_checking 119 * 120 * For historical reasons, the Windows privilege is named 121 * SeChangeNotifyPrivilege, though the description is 122 * "Bypass traverse checking". 123 */ 124 if (smb_token_query_privilege(token, SE_CHANGE_NOTIFY_LUID)) { 125 (void) crsetpriv(cr, PRIV_FILE_DAC_SEARCH, NULL); 126 } 127 128 129 return (cr); 130 } 131 132 /* 133 * Initialize the ksid based on the given smb_id_t. 134 */ 135 static void 136 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid) 137 { 138 char sidstr[SMB_SID_STRSZ]; 139 int rc; 140 141 ASSERT(id); 142 ASSERT(id->i_sid); 143 144 ksid->ks_id = id->i_id; 145 smb_sid_tostr(id->i_sid, sidstr); 146 rc = smb_sid_splitstr(sidstr, &ksid->ks_rid); 147 ASSERT(rc == 0); 148 149 ksid->ks_attr = id->i_attrs; 150 ksid->ks_domain = ksid_lookupdomain(sidstr); 151 } 152 153 /* 154 * Allocate and initialize the ksidlist based on the access token group list. 155 */ 156 static ksidlist_t * 157 smb_cred_set_sidlist(smb_ids_t *token_grps) 158 { 159 int i; 160 ksidlist_t *lp; 161 162 lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP); 163 lp->ksl_ref = 1; 164 lp->ksl_nsid = token_grps->i_cnt; 165 lp->ksl_neid = 0; 166 167 for (i = 0; i < lp->ksl_nsid; i++) { 168 smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]); 169 if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID) 170 lp->ksl_neid++; 171 } 172 173 return (lp); 174 } 175 176 /* 177 * Special variant of smb_cred_create() used when we need an 178 * SMB kcred (e.g. DH import). The returned cred must be 179 * from crget() so it can be passed to smb_user_setcred(). 180 */ 181 cred_t * 182 smb_kcred_create(void) 183 { 184 cred_t *cr; 185 186 cr = crget(); 187 ASSERT(cr != NULL); 188 189 return (cr); 190 } 191