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 *
smb_cred_create(smb_token_t * token)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
smb_cred_set_sid(smb_id_t * id,ksid_t * ksid)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 *
smb_cred_set_sidlist(smb_ids_t * token_grps)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 *
smb_kcred_create(void)162 smb_kcred_create(void)
163 {
164 cred_t *cr;
165
166 cr = crget();
167 ASSERT(cr != NULL);
168
169 return (cr);
170 }
171