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 2014 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 cred_t * 54 smb_cred_create(smb_token_t *token) 55 { 56 ksid_t ksid; 57 ksidlist_t *ksidlist = NULL; 58 smb_posix_grps_t *posix_grps; 59 cred_t *cr; 60 gid_t gid; 61 62 ASSERT(token); 63 ASSERT(token->tkn_posix_grps); 64 posix_grps = token->tkn_posix_grps; 65 66 cr = crget(); 67 ASSERT(cr != NULL); 68 69 if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) && 70 (posix_grps->pg_ngrps != 0)) { 71 gid = posix_grps->pg_grps[0]; 72 } else { 73 gid = token->tkn_primary_grp.i_id; 74 } 75 76 if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) { 77 crfree(cr); 78 return (NULL); 79 } 80 81 if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) { 82 crfree(cr); 83 return (NULL); 84 } 85 86 smb_cred_set_sid(&token->tkn_user, &ksid); 87 crsetsid(cr, &ksid, KSID_USER); 88 smb_cred_set_sid(&token->tkn_primary_grp, &ksid); 89 crsetsid(cr, &ksid, KSID_GROUP); 90 smb_cred_set_sid(&token->tkn_owner, &ksid); 91 crsetsid(cr, &ksid, KSID_OWNER); 92 ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps); 93 crsetsidlist(cr, ksidlist); 94 95 /* 96 * In the AD world, "take ownership privilege" is very much 97 * like having Unix "root" privileges. It's normally given 98 * to members of the "Administrators" group, which normally 99 * includes the the local Administrator (like root) and when 100 * joined to a domain, "Domain Admins". 101 */ 102 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) { 103 (void) crsetpriv(cr, 104 PRIV_FILE_CHOWN, 105 PRIV_FILE_DAC_READ, 106 PRIV_FILE_DAC_SEARCH, 107 PRIV_FILE_DAC_WRITE, 108 PRIV_FILE_OWNER, 109 NULL); 110 } 111 112 return (cr); 113 } 114 115 /* 116 * Initialize the ksid based on the given smb_id_t. 117 */ 118 static void 119 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid) 120 { 121 char sidstr[SMB_SID_STRSZ]; 122 int rc; 123 124 ASSERT(id); 125 ASSERT(id->i_sid); 126 127 ksid->ks_id = id->i_id; 128 smb_sid_tostr(id->i_sid, sidstr); 129 rc = smb_sid_splitstr(sidstr, &ksid->ks_rid); 130 ASSERT(rc == 0); 131 132 ksid->ks_attr = id->i_attrs; 133 ksid->ks_domain = ksid_lookupdomain(sidstr); 134 } 135 136 /* 137 * Allocate and initialize the ksidlist based on the access token group list. 138 */ 139 static ksidlist_t * 140 smb_cred_set_sidlist(smb_ids_t *token_grps) 141 { 142 int i; 143 ksidlist_t *lp; 144 145 lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP); 146 lp->ksl_ref = 1; 147 lp->ksl_nsid = token_grps->i_cnt; 148 lp->ksl_neid = 0; 149 150 for (i = 0; i < lp->ksl_nsid; i++) { 151 smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]); 152 if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID) 153 lp->ksl_neid++; 154 } 155 156 return (lp); 157 } 158