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 }