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 2019 Nexenta by DDN, 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
40static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid);
41static 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 */
58cred_t *
59smb_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	return (cr);
101}
102
103/*
104 * Initialize the ksid based on the given smb_id_t.
105 */
106static void
107smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
108{
109	char sidstr[SMB_SID_STRSZ];
110	int rc;
111
112	ASSERT(id);
113	ASSERT(id->i_sid);
114
115	ksid->ks_id = id->i_id;
116	smb_sid_tostr(id->i_sid, sidstr);
117	rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
118	ASSERT(rc == 0);
119
120	ksid->ks_attr = id->i_attrs;
121	ksid->ks_domain = ksid_lookupdomain(sidstr);
122}
123
124/*
125 * Allocate and initialize the ksidlist based on the access token group list.
126 */
127static ksidlist_t *
128smb_cred_set_sidlist(smb_ids_t *token_grps)
129{
130	int i;
131	ksidlist_t *lp;
132
133	lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
134	lp->ksl_ref = 1;
135	lp->ksl_nsid = token_grps->i_cnt;
136	lp->ksl_neid = 0;
137
138	for (i = 0; i < lp->ksl_nsid; i++) {
139		smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
140		if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
141			lp->ksl_neid++;
142	}
143
144	return (lp);
145}
146
147/*
148 * Special variant of smb_cred_create() used when we need an
149 * SMB kcred (e.g. DH import).  The returned cred must be
150 * from crget() so it can be passed to smb_user_setcred().
151 */
152cred_t *
153smb_kcred_create(void)
154{
155	cred_t	*cr;
156
157	cr = crget();
158	ASSERT(cr != NULL);
159
160	return (cr);
161}
162