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