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