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 2010 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <stdlib.h>
27#include <string.h>
28#include <synch.h>
29#include <smbsrv/libsmb.h>
30
31static char *wka_nbdomain[] = {
32	"",
33	"NT Pseudo Domain",
34	"NT Authority",
35	"Builtin",
36	"Internet$"
37};
38
39/*
40 * Predefined well known accounts table
41 */
42static smb_wka_t wka_tbl[] = {
43	{ 0, "S-1-0-0",		"Null",
44		SidTypeWellKnownGroup, 0, NULL, NULL },
45	{ 0, "S-1-1-0",		"Everyone",
46		SidTypeWellKnownGroup, 0, NULL, NULL },
47	{ 0, "S-1-2-0",		"Local",
48		SidTypeWellKnownGroup, 0, NULL, NULL },
49	{ 0, "S-1-3-0",		"Creator Owner",
50		SidTypeWellKnownGroup, 0, NULL, NULL },
51	{ 0, "S-1-3-1",		"Creator Group",
52		SidTypeWellKnownGroup, 0, NULL, NULL },
53	{ 0, "S-1-3-2",		"Creator Owner Server",
54		SidTypeWellKnownGroup, 0, NULL, NULL },
55	{ 0, "S-1-3-3",		"Creator Group Server",
56		SidTypeWellKnownGroup, 0, NULL, NULL },
57	{ 0, "S-1-3-4",		"Owner Rights",
58		SidTypeWellKnownGroup, 0, NULL, NULL },
59	{ 0, "S-1-3-5",		"Group Rights",
60		SidTypeWellKnownGroup, 0, NULL, NULL },
61	{ 1, "S-1-5",		"NT Pseudo Domain",
62		SidTypeDomain, 0, NULL, NULL },
63	{ 2, "S-1-5-1",		"Dialup",
64		SidTypeWellKnownGroup, 0, NULL, NULL },
65	{ 2, "S-1-5-2",		"Network",
66		SidTypeWellKnownGroup, 0, NULL, NULL },
67	{ 2, "S-1-5-3",		"Batch",
68		SidTypeWellKnownGroup, 0, NULL, NULL },
69	{ 2, "S-1-5-4",		"Interactive",
70		SidTypeWellKnownGroup, 0, NULL, NULL },
71	{ 2, "S-1-5-6",		"Service",
72		SidTypeWellKnownGroup, 0, NULL, NULL },
73	{ 2, "S-1-5-7",		"Anonymous",
74		SidTypeWellKnownGroup, 0, NULL, NULL },
75	{ 2, "S-1-5-8",		"Proxy",
76		SidTypeWellKnownGroup, 0, NULL, NULL },
77	{ 2, "S-1-5-9",		"Enterprise Domain Controllers",
78		SidTypeWellKnownGroup, 0, NULL, NULL },
79	{ 2, "S-1-5-10",	"Self",
80		SidTypeWellKnownGroup, 0, NULL, NULL },
81	{ 2, "S-1-5-11",	"Authenticated Users",
82		SidTypeWellKnownGroup, 0, NULL, NULL },
83	{ 2, "S-1-5-12",	"Restricted",
84		SidTypeWellKnownGroup, 0, NULL, NULL },
85	{ 2, "S-1-5-13",	"Terminal Server User",
86		SidTypeWellKnownGroup, 0, NULL, NULL },
87	{ 2, "S-1-5-14",	"Remote Interactive Logon",
88		SidTypeWellKnownGroup, 0, NULL, NULL },
89	{ 2, "S-1-5-15",	"This Organization",
90		SidTypeWellKnownGroup, 0, NULL, NULL },
91	{ 2, "S-1-5-18",	"System",
92		SidTypeWellKnownGroup, 0, NULL, NULL },
93	{ 2, "S-1-5-19",	"Local Service",
94		SidTypeWellKnownGroup, 0, NULL, NULL },
95	{ 2, "S-1-5-20",	"Network Service",
96		SidTypeWellKnownGroup, 0, NULL, NULL },
97	{ 2, "S-1-5-33",	"Write Restricted",
98		SidTypeWellKnownGroup, 0, NULL, NULL },
99	{ 2, "S-1-5-1000",	"Other Organization",
100		SidTypeWellKnownGroup, 0, NULL, NULL },
101	{ 3, "S-1-5-32",	"Builtin",
102		SidTypeDomain, 0, NULL, NULL },
103	{ 4, "S-1-7",		"Internet$",
104		SidTypeDomain, 0, NULL, NULL },
105
106	{ 3, "S-1-5-32-544",	"Administrators", SidTypeAlias,
107	    SMB_WKAFLG_LGRP_ENABLE,
108	    "Members can fully administer the computer/domain", NULL },
109	{ 3, "S-1-5-32-545",	"Users",
110		SidTypeAlias, 0, NULL, NULL },
111	{ 3, "S-1-5-32-546",	"Guests",
112		SidTypeAlias, 0, NULL, NULL },
113	{ 3, "S-1-5-32-547",	"Power Users", SidTypeAlias,
114	    SMB_WKAFLG_LGRP_ENABLE, "Members can share directories", NULL },
115	{ 3, "S-1-5-32-548",	"Account Operators",
116		SidTypeAlias, 0, NULL, NULL },
117	{ 3, "S-1-5-32-549",	"Server Operators",
118		SidTypeAlias, 0, NULL, NULL },
119	{ 3, "S-1-5-32-550",	"Print Operators",
120		SidTypeAlias, 0, NULL, NULL },
121	{ 3, "S-1-5-32-551",	"Backup Operators", SidTypeAlias,
122	    SMB_WKAFLG_LGRP_ENABLE,
123	    "Members can bypass file security to back up files", NULL },
124	{ 3, "S-1-5-32-552",	"Replicator",
125		SidTypeAlias, 0, NULL, NULL },
126	{ 3, "S-1-5-32-766",	"Current Owner",
127		SidTypeAlias, 0, NULL, NULL },
128	{ 3, "S-1-5-32-767",	"Current Group",
129		SidTypeAlias, 0, NULL, NULL },
130};
131
132#define	SMB_WKA_NUM	(sizeof (wka_tbl)/sizeof (wka_tbl[0]))
133
134static int smb_wka_init(void);
135static void smb_wka_fini(void);
136
137/*
138 * Looks up well known accounts table for the given SID.
139 * Upon success returns a pointer to the account entry in
140 * the table, otherwise returns NULL.
141 */
142smb_wka_t *
143smb_wka_lookup_sid(smb_sid_t *sid)
144{
145	smb_wka_t *entry;
146	int i;
147
148	if (!smb_wka_init())
149		return (NULL);
150
151	for (i = 0; i < SMB_WKA_NUM; ++i) {
152		entry = &wka_tbl[i];
153
154		if (entry->wka_binsid == NULL)
155			return (NULL);
156
157		if (smb_sid_cmp(sid, entry->wka_binsid))
158			return (entry);
159	}
160
161	return (NULL);
162}
163
164/*
165 * Looks up well known accounts table for the given name.
166 * Upon success returns a pointer to the binary SID of the
167 * entry, otherwise returns NULL.
168 */
169smb_sid_t *
170smb_wka_get_sid(const char *name)
171{
172	smb_wka_t *entry;
173	smb_sid_t *sid = NULL;
174
175	if (!smb_wka_init())
176		return (NULL);
177
178	if ((entry = smb_wka_lookup_name(name)) != NULL)
179		sid = entry->wka_binsid;
180
181	return (sid);
182}
183
184/*
185 * Looks up well known accounts table for the given name.
186 * Upon success returns a pointer to the account entry in
187 * the table, otherwise returns NULL.
188 */
189smb_wka_t *
190smb_wka_lookup_name(const char *name)
191{
192	smb_wka_t *entry;
193	int i;
194
195	for (i = 0; i < SMB_WKA_NUM; ++i) {
196		entry = &wka_tbl[i];
197
198		if (!smb_strcasecmp(name, entry->wka_name, 0))
199			return (entry);
200	}
201
202	return (NULL);
203}
204
205/*
206 * Lookup a name in the BUILTIN domain.
207 */
208smb_wka_t *
209smb_wka_lookup_builtin(const char *name)
210{
211	smb_wka_t	*entry;
212	int		i;
213
214	for (i = 0; i < SMB_WKA_NUM; ++i) {
215		entry = &wka_tbl[i];
216
217		if (entry->wka_domidx != 3)
218			continue;
219
220		if (!smb_strcasecmp(name, entry->wka_name, 0))
221			return (entry);
222	}
223
224	return (NULL);
225}
226
227/*
228 * Returns the Netbios domain name for the given index
229 */
230char *
231smb_wka_get_domain(int idx)
232{
233	if ((idx >= 0) && (idx < SMB_WKA_NUM))
234		return (wka_nbdomain[idx]);
235
236	return (NULL);
237}
238
239/*
240 * This function adds well known groups to groups in a user's
241 * access token (gids).
242 *
243 * "Network" SID is added for all users connecting over CIFS.
244 *
245 * "Authenticated Users" SID is added for all users except Guest
246 * and Anonymous.
247 *
248 * "Guests" SID is added for guest users and Administrators SID
249 * is added for admin users.
250 */
251uint32_t
252smb_wka_token_groups(uint32_t flags, smb_ids_t *gids)
253{
254	smb_id_t *id;
255	int total_cnt;
256
257	total_cnt = gids->i_cnt + 3;
258
259	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
260	if (gids->i_ids == NULL)
261		return (NT_STATUS_NO_MEMORY);
262
263	id = gids->i_ids + gids->i_cnt;
264	id->i_sid = smb_sid_dup(smb_wka_get_sid("Network"));
265	id->i_attrs = 0x7;
266	if (id->i_sid == NULL)
267		return (NT_STATUS_NO_MEMORY);
268	id++;
269	gids->i_cnt++;
270
271	if ((flags & SMB_ATF_ANON) == 0) {
272		if (flags & SMB_ATF_GUEST)
273			id->i_sid = smb_sid_dup(smb_wka_get_sid("Guests"));
274		else
275			id->i_sid =
276			    smb_sid_dup(smb_wka_get_sid("Authenticated Users"));
277		id->i_attrs = 0x7;
278		if (id->i_sid == NULL)
279			return (NT_STATUS_NO_MEMORY);
280		id++;
281		gids->i_cnt++;
282	}
283
284	if (flags & SMB_ATF_ADMIN) {
285		id->i_sid = smb_sid_dup(smb_wka_get_sid("Administrators"));
286		id->i_attrs = 0x7;
287		if (id->i_sid == NULL)
288			return (NT_STATUS_NO_MEMORY);
289		gids->i_cnt++;
290	}
291
292	return (NT_STATUS_SUCCESS);
293}
294
295/*
296 * Generate binary SIDs from the string SIDs for the well-known
297 * accounts table.  Callers MUST not free the binary SID pointer.
298 */
299static int
300smb_wka_init(void)
301{
302	static boolean_t wka_init = B_FALSE;
303	static mutex_t	wka_mutex;
304	smb_wka_t	*entry;
305	int		i;
306
307	(void) mutex_lock(&wka_mutex);
308	if (wka_init) {
309		(void) mutex_unlock(&wka_mutex);
310		return (B_TRUE);
311	}
312
313	for (i = 0; i < SMB_WKA_NUM; ++i) {
314		entry = &wka_tbl[i];
315
316		entry->wka_binsid = smb_sid_fromstr(entry->wka_sid);
317		if (entry->wka_binsid == NULL) {
318			smb_wka_fini();
319			(void) mutex_unlock(&wka_mutex);
320			return (B_FALSE);
321		}
322	}
323
324	wka_init = B_TRUE;
325	(void) mutex_unlock(&wka_mutex);
326	return (B_TRUE);
327}
328
329/*
330 * Private cleanup for smb_wka_init.
331 */
332static void
333smb_wka_fini(void)
334{
335	int i;
336
337	for (i = 0; i < SMB_WKA_NUM; ++i) {
338		if (wka_tbl[i].wka_binsid) {
339			free(wka_tbl[i].wka_binsid);
340			wka_tbl[i].wka_binsid = NULL;
341		}
342	}
343}
344