xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_cred.c (revision 8d94f651a44d41a7147253bb5dad1a53941e8f50)
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