1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22bbf6f00cSJordan Brown  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24*0292c176SMatt Barden  *
25*0292c176SMatt Barden  * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * This module provides the interface to the built-in privilege names
30da6c28aaSamw  * and id's. NT privileges are known on the network using strings. Each
31da6c28aaSamw  * system assigns locally unique identifiers (LUID) for use within the
32da6c28aaSamw  * system. Each built-in privilege also has a display-name, which is a
33da6c28aaSamw  * short description of the privilege. The functions here provide an
34da6c28aaSamw  * interface to map between LUIDs, names and display names.
35da6c28aaSamw  */
36da6c28aaSamw 
37da6c28aaSamw #include <string.h>
38da6c28aaSamw #include <syslog.h>
39da6c28aaSamw 
40da6c28aaSamw #include <smbsrv/string.h>
41da6c28aaSamw #include <smbsrv/libsmb.h>
42da6c28aaSamw #include <smbsrv/smb_privilege.h>
43da6c28aaSamw 
44da6c28aaSamw static char *smb_priv_getname(uint32_t id);
45da6c28aaSamw 
46da6c28aaSamw /*
47da6c28aaSamw  * Table of built-in privilege id's, names and display strings. This
48da6c28aaSamw  * table matches the response from an NT4.0 PDC LSARPC service.
49da6c28aaSamw  * Requests for values 0 and 1 return STATUS_NO_SUCH_PRIVILEGE.
50da6c28aaSamw  *
51da6c28aaSamw  * SE_UNSOLICITED_INPUT_NAME/SeUnsolicitedInputPrivilege is defined in
52da6c28aaSamw  * winnt.h but doesn't appear in the list reported by the NT4.0 LSA.
53da6c28aaSamw  */
54da6c28aaSamw static smb_privinfo_t priv_table[] = {
55da6c28aaSamw 	{  0, "", "", 0 },
56da6c28aaSamw 	{  1, "", "", 0 },
57da6c28aaSamw 	{  2, SE_CREATE_TOKEN_NAME, "Create a token object", 0 },
58da6c28aaSamw 	{  3, SE_ASSIGNPRIMARYTOKEN_NAME, "Replace a process level token", 0 },
59da6c28aaSamw 	{  4, SE_LOCK_MEMORY_NAME, "Lock pages in memory", 0 },
60da6c28aaSamw 	{  5, SE_INCREASE_QUOTA_NAME, "Increase quotas", 0 },
61da6c28aaSamw 	{  6, SE_MACHINE_ACCOUNT_NAME, "Add workstations to domain", 0 },
62da6c28aaSamw 	{  7, SE_TCB_NAME, "Act as part of the operating system", 0 },
63da6c28aaSamw 	{  8, SE_SECURITY_NAME, "Manage auditing and security log", 0 },
64da6c28aaSamw 	{  9, SE_TAKE_OWNERSHIP_NAME,
65da6c28aaSamw 	    "Take ownership of files or other objects", PF_PRESENTABLE },
66da6c28aaSamw 	{ 10, SE_LOAD_DRIVER_NAME, "Load and unload device drivers", 0 },
67da6c28aaSamw 	{ 11, SE_SYSTEM_PROFILE_NAME, "Profile system performance", 0 },
68da6c28aaSamw 	{ 12, SE_SYSTEMTIME_NAME, "Change the system time", 0 },
69da6c28aaSamw 	{ 13, SE_PROF_SINGLE_PROCESS_NAME, "Profile single process", 0 },
70da6c28aaSamw 	{ 14, SE_INC_BASE_PRIORITY_NAME, "Increase scheduling priority", 0 },
71da6c28aaSamw 	{ 15, SE_CREATE_PAGEFILE_NAME, "Create a pagefile", 0 },
72da6c28aaSamw 	{ 16, SE_CREATE_PERMANENT_NAME, "Create permanent shared objects", 0 },
73da6c28aaSamw 	{ 17, SE_BACKUP_NAME, "Back up files and directories",
74da6c28aaSamw 	    PF_PRESENTABLE },
75da6c28aaSamw 	{ 18, SE_RESTORE_NAME, "Restore files and directories",
76da6c28aaSamw 	    PF_PRESENTABLE },
77da6c28aaSamw 	{ 19, SE_SHUTDOWN_NAME, "Shut down the system", 0 },
78da6c28aaSamw 	{ 20, SE_DEBUG_NAME, "Debug programs", 0 },
79da6c28aaSamw 	{ 21, SE_AUDIT_NAME, "Generate security audits", 0 },
80da6c28aaSamw 	{ 22, SE_SYSTEM_ENVIRONMENT_NAME,
81da6c28aaSamw 	    "Modify firmware environment values", 0 },
82da6c28aaSamw 	{ 23, SE_CHANGE_NOTIFY_NAME, "Bypass traverse checking", 0 },
83da6c28aaSamw 	{ 24, SE_REMOTE_SHUTDOWN_NAME,
84*0292c176SMatt Barden 	    "Force shutdown from a remote system", 0 },
85*0292c176SMatt Barden 	{ 25, SE_READ_FILE_NAME,
86*0292c176SMatt Barden 	    "Bypass ACL for READ access", PF_PRESENTABLE },
87*0292c176SMatt Barden 	{ 26, SE_WRITE_FILE_NAME,
88*0292c176SMatt Barden 	    "Bypass ACL for WRITE and DELETE access", PF_PRESENTABLE },
89da6c28aaSamw };
90da6c28aaSamw 
91da6c28aaSamw /*
92da6c28aaSamw  * smb_priv_presentable_num
93da6c28aaSamw  *
94da6c28aaSamw  * Returns number of presentable privileges
95da6c28aaSamw  */
96da6c28aaSamw int
smb_priv_presentable_num()97da6c28aaSamw smb_priv_presentable_num()
98da6c28aaSamw {
99da6c28aaSamw 	int i, num;
100da6c28aaSamw 
101da6c28aaSamw 	num = 0;
102dc20a302Sas 	for (i = SE_MIN_LUID; i <= SE_MAX_LUID; i++)
103da6c28aaSamw 		if (priv_table[i].flags == PF_PRESENTABLE)
104da6c28aaSamw 			num++;
105da6c28aaSamw 
106da6c28aaSamw 	return (num);
107da6c28aaSamw }
108da6c28aaSamw 
109da6c28aaSamw /*
110da6c28aaSamw  * smb_priv_presentable_ids
111da6c28aaSamw  *
112da6c28aaSamw  * Returns IDs of presentable privileges
113da6c28aaSamw  * Returns 0 in case of invalid parameter and 1 on success.
114da6c28aaSamw  */
115da6c28aaSamw int
smb_priv_presentable_ids(uint32_t * ids,int num)116da6c28aaSamw smb_priv_presentable_ids(uint32_t *ids, int num)
117da6c28aaSamw {
118da6c28aaSamw 	int i, j;
119da6c28aaSamw 
120da6c28aaSamw 	if (ids == NULL || num <= 0)
121da6c28aaSamw 		return (0);
122da6c28aaSamw 
123dc20a302Sas 	for (i = SE_MIN_LUID, j = 0; i <= SE_MAX_LUID; i++)
124da6c28aaSamw 		if (priv_table[i].flags == PF_PRESENTABLE)
125da6c28aaSamw 			ids[j++] = priv_table[i].id;
126da6c28aaSamw 
127da6c28aaSamw 	return (1);
128da6c28aaSamw }
129da6c28aaSamw 
130da6c28aaSamw /*
131da6c28aaSamw  * smb_priv_getbyvalue
132da6c28aaSamw  *
133da6c28aaSamw  * Return the privilege info for the specified id (low part of the LUID).
134da6c28aaSamw  * Returns a null pointer if id is out-of-range.
135da6c28aaSamw  */
136da6c28aaSamw smb_privinfo_t *
smb_priv_getbyvalue(uint32_t id)137da6c28aaSamw smb_priv_getbyvalue(uint32_t id)
138da6c28aaSamw {
139dc20a302Sas 	if (id < SE_MIN_LUID || id > SE_MAX_LUID)
140da6c28aaSamw 		return (0);
141da6c28aaSamw 
142da6c28aaSamw 	return (&priv_table[id]);
143da6c28aaSamw }
144da6c28aaSamw 
145da6c28aaSamw 
146da6c28aaSamw /*
147da6c28aaSamw  * smb_priv_getbyname
148da6c28aaSamw  *
149da6c28aaSamw  * Return the privilege info for the specified name. Returns a null
150da6c28aaSamw  * pointer if we can't find a matching name in the table.
151da6c28aaSamw  */
152da6c28aaSamw smb_privinfo_t *
smb_priv_getbyname(char * name)153da6c28aaSamw smb_priv_getbyname(char *name)
154da6c28aaSamw {
155da6c28aaSamw 	smb_privinfo_t *entry;
156da6c28aaSamw 	int i;
157da6c28aaSamw 
158da6c28aaSamw 	if (name == 0)
159da6c28aaSamw 		return (0);
160da6c28aaSamw 
161dc20a302Sas 	for (i = SE_MIN_LUID; i <= SE_MAX_LUID; ++i) {
162da6c28aaSamw 		entry = &priv_table[i];
163da6c28aaSamw 
164bbf6f00cSJordan Brown 		if (smb_strcasecmp(name, entry->name, 0) == 0)
165da6c28aaSamw 			return (entry);
166da6c28aaSamw 	}
167da6c28aaSamw 
168da6c28aaSamw 	return (0);
169da6c28aaSamw }
170da6c28aaSamw 
171da6c28aaSamw /*
172da6c28aaSamw  * smb_privset_size
173da6c28aaSamw  *
174da6c28aaSamw  * Returns the memory block size needed to keep a complete
175da6c28aaSamw  * set of privileges in a smb_privset_t structure.
176da6c28aaSamw  */
177da6c28aaSamw int
smb_privset_size()178da6c28aaSamw smb_privset_size()
179da6c28aaSamw {
180dc20a302Sas 	int pcnt = SE_MAX_LUID - SE_MIN_LUID + 1;
181da6c28aaSamw 
182da6c28aaSamw 	return (2 * sizeof (uint32_t) +
183da6c28aaSamw 	    pcnt * sizeof (smb_luid_attrs_t));
184da6c28aaSamw }
185da6c28aaSamw 
186da6c28aaSamw /*
187da6c28aaSamw  * smb_privset_validate
188da6c28aaSamw  *
189da6c28aaSamw  * Validates the given privilege set structure
190da6c28aaSamw  * Returns 1 if the structure is Ok, otherwise returns 0.
191da6c28aaSamw  */
192da6c28aaSamw int
smb_privset_validate(smb_privset_t * privset)193da6c28aaSamw smb_privset_validate(smb_privset_t *privset)
194da6c28aaSamw {
195da6c28aaSamw 	int count;
196da6c28aaSamw 	uint32_t i;
197da6c28aaSamw 
198da6c28aaSamw 	if (privset == 0) {
199da6c28aaSamw 		return (0);
200da6c28aaSamw 	}
201da6c28aaSamw 
202dc20a302Sas 	count = SE_MAX_LUID - SE_MIN_LUID + 1;
203da6c28aaSamw 
204da6c28aaSamw 	if (privset->priv_cnt != count) {
205da6c28aaSamw 		return (0);
206da6c28aaSamw 	}
207da6c28aaSamw 
208da6c28aaSamw 	for (i = 0; i < count; i++) {
209da6c28aaSamw 		if (privset->priv[i].luid.hi_part != 0) {
210da6c28aaSamw 			return (0);
211da6c28aaSamw 		}
212da6c28aaSamw 
213da6c28aaSamw 		if (privset->priv[i].luid.lo_part !=
214dc20a302Sas 		    i + SE_MIN_LUID) {
215da6c28aaSamw 			return (0);
216da6c28aaSamw 		}
217da6c28aaSamw 	}
218da6c28aaSamw 
219da6c28aaSamw 	return (1);
220da6c28aaSamw }
221da6c28aaSamw 
222da6c28aaSamw /*
223da6c28aaSamw  * smb_privset_init
224da6c28aaSamw  *
225da6c28aaSamw  * initialize all privileges in disable state.
226da6c28aaSamw  */
227da6c28aaSamw void
smb_privset_init(smb_privset_t * privset)228da6c28aaSamw smb_privset_init(smb_privset_t *privset)
229da6c28aaSamw {
230da6c28aaSamw 	int count;
231da6c28aaSamw 	uint32_t i;
232da6c28aaSamw 
233da6c28aaSamw 	if (privset == 0)
234da6c28aaSamw 		return;
235da6c28aaSamw 
236dc20a302Sas 	count = SE_MAX_LUID - SE_MIN_LUID + 1;
237da6c28aaSamw 
238da6c28aaSamw 	privset->priv_cnt = count;
239da6c28aaSamw 	privset->control = 0;
240da6c28aaSamw 	for (i = 0; i < count; i++) {
241da6c28aaSamw 		privset->priv[i].luid.hi_part = 0;
242dc20a302Sas 		privset->priv[i].luid.lo_part = i + SE_MIN_LUID;
243da6c28aaSamw 		privset->priv[i].attrs = 0;
244da6c28aaSamw 	}
245da6c28aaSamw }
246da6c28aaSamw 
247da6c28aaSamw /*
248da6c28aaSamw  * smb_privset_new
249da6c28aaSamw  *
250da6c28aaSamw  * Allocate memory and initialize all privileges in disable state.
251da6c28aaSamw  * Returns pointer to allocated space or NULL if there is not
252da6c28aaSamw  * enough memory.
253da6c28aaSamw  */
254da6c28aaSamw smb_privset_t *
smb_privset_new()255da6c28aaSamw smb_privset_new()
256da6c28aaSamw {
257da6c28aaSamw 	smb_privset_t *privset;
258da6c28aaSamw 
259da6c28aaSamw 	privset = malloc(smb_privset_size());
260da6c28aaSamw 	if (privset == NULL)
261da6c28aaSamw 		return (NULL);
262da6c28aaSamw 
263da6c28aaSamw 	smb_privset_init(privset);
264da6c28aaSamw 
265da6c28aaSamw 	return (privset);
266da6c28aaSamw }
267da6c28aaSamw 
268da6c28aaSamw /*
269da6c28aaSamw  * smb_privset_copy
270da6c28aaSamw  *
271da6c28aaSamw  * Copy privleges information specified by 'src' to the
272da6c28aaSamw  * buffer specified by dst.
273da6c28aaSamw  */
274da6c28aaSamw void
smb_privset_copy(smb_privset_t * dst,smb_privset_t * src)275da6c28aaSamw smb_privset_copy(smb_privset_t *dst, smb_privset_t *src)
276da6c28aaSamw {
277da6c28aaSamw 	if (src == 0 || dst == 0)
278da6c28aaSamw 		return;
279da6c28aaSamw 
280da6c28aaSamw 	(void) memcpy(dst, src, smb_privset_size());
281da6c28aaSamw }
282da6c28aaSamw 
283dc20a302Sas /*
284dc20a302Sas  * smb_privset_merge
285dc20a302Sas  *
286dc20a302Sas  * Enable the privileges that are enabled in src in dst
287dc20a302Sas  */
288dc20a302Sas void
smb_privset_merge(smb_privset_t * dst,smb_privset_t * src)289dc20a302Sas smb_privset_merge(smb_privset_t *dst, smb_privset_t *src)
290dc20a302Sas {
291dc20a302Sas 	int i;
292dc20a302Sas 
293dc20a302Sas 	if (src == NULL || dst == NULL)
294dc20a302Sas 		return;
295dc20a302Sas 
296dc20a302Sas 	for (i = 0; i < src->priv_cnt; i++) {
297dc20a302Sas 		if (src->priv[i].attrs == SE_PRIVILEGE_ENABLED)
298dc20a302Sas 			smb_privset_enable(dst, src->priv[i].luid.lo_part);
299dc20a302Sas 	}
300dc20a302Sas }
301dc20a302Sas 
302da6c28aaSamw /*
303da6c28aaSamw  * smb_privset_free
304da6c28aaSamw  *
305da6c28aaSamw  * This will free the memory allocated by the 'privset'.
306da6c28aaSamw  */
307da6c28aaSamw void
smb_privset_free(smb_privset_t * privset)308da6c28aaSamw smb_privset_free(smb_privset_t *privset)
309da6c28aaSamw {
310da6c28aaSamw 	free(privset);
311da6c28aaSamw }
312da6c28aaSamw 
313da6c28aaSamw void
smb_privset_enable(smb_privset_t * privset,uint32_t id)314da6c28aaSamw smb_privset_enable(smb_privset_t *privset, uint32_t id)
315da6c28aaSamw {
316da6c28aaSamw 	int i;
317da6c28aaSamw 
318da6c28aaSamw 	if (privset == NULL)
319da6c28aaSamw 		return;
320da6c28aaSamw 
321da6c28aaSamw 	for (i = 0; i < privset->priv_cnt; i++) {
322da6c28aaSamw 		if (privset->priv[i].luid.lo_part == id)
323da6c28aaSamw 			privset->priv[i].attrs = SE_PRIVILEGE_ENABLED;
324da6c28aaSamw 	}
325da6c28aaSamw }
326da6c28aaSamw 
327da6c28aaSamw void
smb_privset_log(smb_privset_t * privset)328da6c28aaSamw smb_privset_log(smb_privset_t *privset)
329da6c28aaSamw {
330da6c28aaSamw 	smb_luid_t *luid;
331da6c28aaSamw 	int i, ecnt;
332da6c28aaSamw 
333da6c28aaSamw 	if (privset == NULL)
334da6c28aaSamw 		return;
335da6c28aaSamw 
336da6c28aaSamw 	for (i = 0, ecnt = 0; i < privset->priv_cnt; ++i) {
337da6c28aaSamw 		if (privset->priv[i].attrs != 0) {
338da6c28aaSamw 			ecnt++;
339da6c28aaSamw 		}
340da6c28aaSamw 	}
341da6c28aaSamw 
342da6c28aaSamw 	syslog(LOG_DEBUG, "   Privilege Count: %d (Enable=%d)",
343da6c28aaSamw 	    privset->priv_cnt, ecnt);
344da6c28aaSamw 
345da6c28aaSamw 	for (i = 0; i < privset->priv_cnt; ++i) {
346da6c28aaSamw 		if (privset->priv[i].attrs != 0) {
347da6c28aaSamw 			luid = &privset->priv[i].luid;
348da6c28aaSamw 			syslog(LOG_DEBUG, "    %s",
349da6c28aaSamw 			    smb_priv_getname(luid->lo_part));
350da6c28aaSamw 		}
351da6c28aaSamw 	}
352da6c28aaSamw }
353da6c28aaSamw 
354da6c28aaSamw int
smb_privset_query(smb_privset_t * privset,uint32_t id)355da6c28aaSamw smb_privset_query(smb_privset_t *privset, uint32_t id)
356da6c28aaSamw {
357da6c28aaSamw 	int i;
358da6c28aaSamw 
359da6c28aaSamw 	if (privset == NULL)
360da6c28aaSamw 		return (0);
361da6c28aaSamw 
362da6c28aaSamw 	for (i = 0; privset->priv_cnt; i++) {
363da6c28aaSamw 		if (privset->priv[i].luid.lo_part == id) {
364da6c28aaSamw 			if (privset->priv[i].attrs == SE_PRIVILEGE_ENABLED)
365da6c28aaSamw 				return (1);
366da6c28aaSamw 			else
367da6c28aaSamw 				return (0);
368da6c28aaSamw 		}
369da6c28aaSamw 	}
370da6c28aaSamw 
371da6c28aaSamw 	return (0);
372da6c28aaSamw }
373da6c28aaSamw 
374da6c28aaSamw static char *
smb_priv_getname(uint32_t id)375da6c28aaSamw smb_priv_getname(uint32_t id)
376da6c28aaSamw {
377dc20a302Sas 	if (id < SE_MIN_LUID || id > SE_MAX_LUID)
378da6c28aaSamw 		return ("Unknown Privilege");
379da6c28aaSamw 
380da6c28aaSamw 	return (priv_table[id].name);
381da6c28aaSamw }
382