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 2018 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, smb_session_t *s)
  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         auditinfo_addr_t        *au;
  67 
  68         ASSERT(token);
  69         ASSERT(token->tkn_posix_grps);
  70         posix_grps = token->tkn_posix_grps;
  71 
  72         cr = crget();
  73         ASSERT(cr != NULL);
  74 
  75         if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
  76             (posix_grps->pg_ngrps != 0)) {
  77                 gid = posix_grps->pg_grps[0];
  78         } else {
  79                 gid = token->tkn_primary_grp.i_id;
  80         }
  81 
  82         if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
  83                 crfree(cr);
  84                 return (NULL);
  85         }
  86 
  87         if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
  88                 crfree(cr);
  89                 return (NULL);
  90         }
  91 
  92         smb_cred_set_sid(&token->tkn_user, &ksid);
  93         crsetsid(cr, &ksid, KSID_USER);
  94         smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
  95         crsetsid(cr, &ksid, KSID_GROUP);
  96         smb_cred_set_sid(&token->tkn_owner, &ksid);
  97         crsetsid(cr, &ksid, KSID_OWNER);
  98         ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
  99         crsetsidlist(cr, ksidlist);
 100 
 101         /*
 102          * In the AD world, "take ownership privilege" is very much
 103          * like having Unix "root" privileges.  It's normally given
 104          * to members of the "Administrators" group, which normally
 105          * includes the the local Administrator (like root) and when
 106          * joined to a domain, "Domain Admins".
 107          */
 108         if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) {
 109                 (void) crsetpriv(cr,
 110                     PRIV_FILE_CHOWN,
 111                     PRIV_FILE_DAC_READ,
 112                     PRIV_FILE_DAC_SEARCH,
 113                     PRIV_FILE_DAC_WRITE,
 114                     PRIV_FILE_OWNER,
 115                     NULL);
 116         }
 117 
 118         /*
 119          * See smb.4 bypass_traverse_checking
 120          *
 121          * For historical reasons, the Windows privilege is named
 122          * SeChangeNotifyPrivilege, though the description is
 123          * "Bypass traverse checking".
 124          */
 125         if (smb_token_query_privilege(token, SE_CHANGE_NOTIFY_LUID)) {
 126                 (void) crsetpriv(cr, PRIV_FILE_DAC_SEARCH, NULL);
 127         }
 128 
 129         au = crgetauinfo_modifiable(cr);
 130         if (au != NULL) {
 131                 au->ai_auid = token->tkn_auid;
 132                 au->ai_mask = token->tkn_amask;
 133                 au->ai_asid = token->tkn_asid;
 134                 au->ai_termid.at_port = s->s_local_port;
 135 
 136                 if (s->ipaddr.a_family == AF_INET) {
 137                         au->ai_termid.at_addr[0] = s->ipaddr.a_ipv4;
 138                         au->ai_termid.at_type = AU_IPv4;
 139                 } else {
 140                         bcopy(&s->ipaddr.a_ip, au->ai_termid.at_addr,
 141                             sizeof (in6_addr_t));
 142                         au->ai_termid.at_type = AU_IPv6;
 143                 }
 144         }
 145         return (cr);
 146 }
 147 
 148 /*
 149  * Initialize the ksid based on the given smb_id_t.
 150  */
 151 static void
 152 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
 153 {
 154         char sidstr[SMB_SID_STRSZ];
 155         int rc;
 156 
 157         ASSERT(id);
 158         ASSERT(id->i_sid);
 159 
 160         ksid->ks_id = id->i_id;
 161         smb_sid_tostr(id->i_sid, sidstr);
 162         rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
 163         ASSERT(rc == 0);
 164 
 165         ksid->ks_attr = id->i_attrs;
 166         ksid->ks_domain = ksid_lookupdomain(sidstr);
 167 }
 168 
 169 /*
 170  * Allocate and initialize the ksidlist based on the access token group list.
 171  */
 172 static ksidlist_t *
 173 smb_cred_set_sidlist(smb_ids_t *token_grps)
 174 {
 175         int i;
 176         ksidlist_t *lp;
 177 
 178         lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
 179         lp->ksl_ref = 1;
 180         lp->ksl_nsid = token_grps->i_cnt;
 181         lp->ksl_neid = 0;
 182 
 183         for (i = 0; i < lp->ksl_nsid; i++) {
 184                 smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
 185                 if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
 186                         lp->ksl_neid++;
 187         }
 188 
 189         return (lp);
 190 }
 191 
 192 /*
 193  * Special variant of smb_cred_create() used when we need an
 194  * SMB kcred (i.e. DH import).  The returned cred must be
 195  * from crget() so it can be passed to smb_user_setcred().
 196  */
 197 cred_t *
 198 smb_kcred_create(void)
 199 {
 200         cred_t  *cr;
 201 
 202         cr = crget();
 203         ASSERT(cr != NULL);
 204 
 205         return (cr);
 206 }