xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_privilege.c (revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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 };
86 
87 /*
88  * smb_priv_presentable_num
89  *
90  * Returns number of presentable privileges
91  */
92 int
93 smb_priv_presentable_num()
94 {
95 	int i, num;
96 
97 	num = 0;
98 	for (i = SE_MIN_LUID; i <= SE_MAX_LUID; i++)
99 		if (priv_table[i].flags == PF_PRESENTABLE)
100 			num++;
101 
102 	return (num);
103 }
104 
105 /*
106  * smb_priv_presentable_ids
107  *
108  * Returns IDs of presentable privileges
109  * Returns 0 in case of invalid parameter and 1 on success.
110  */
111 int
112 smb_priv_presentable_ids(uint32_t *ids, int num)
113 {
114 	int i, j;
115 
116 	if (ids == NULL || num <= 0)
117 		return (0);
118 
119 	for (i = SE_MIN_LUID, j = 0; i <= SE_MAX_LUID; i++)
120 		if (priv_table[i].flags == PF_PRESENTABLE)
121 			ids[j++] = priv_table[i].id;
122 
123 	return (1);
124 }
125 
126 /*
127  * smb_priv_getbyvalue
128  *
129  * Return the privilege info for the specified id (low part of the LUID).
130  * Returns a null pointer if id is out-of-range.
131  */
132 smb_privinfo_t *
133 smb_priv_getbyvalue(uint32_t id)
134 {
135 	if (id < SE_MIN_LUID || id > SE_MAX_LUID)
136 		return (0);
137 
138 	return (&priv_table[id]);
139 }
140 
141 
142 /*
143  * smb_priv_getbyname
144  *
145  * Return the privilege info for the specified name. Returns a null
146  * pointer if we can't find a matching name in the table.
147  */
148 smb_privinfo_t *
149 smb_priv_getbyname(char *name)
150 {
151 	smb_privinfo_t *entry;
152 	int i;
153 
154 	if (name == 0)
155 		return (0);
156 
157 	for (i = SE_MIN_LUID; i <= SE_MAX_LUID; ++i) {
158 		entry = &priv_table[i];
159 
160 		if (utf8_strcasecmp(name, entry->name) == 0)
161 			return (entry);
162 	}
163 
164 	return (0);
165 }
166 
167 /*
168  * smb_privset_size
169  *
170  * Returns the memory block size needed to keep a complete
171  * set of privileges in a smb_privset_t structure.
172  */
173 int
174 smb_privset_size()
175 {
176 	int pcnt = SE_MAX_LUID - SE_MIN_LUID + 1;
177 
178 	return (2 * sizeof (uint32_t) +
179 	    pcnt * sizeof (smb_luid_attrs_t));
180 }
181 
182 /*
183  * smb_privset_validate
184  *
185  * Validates the given privilege set structure
186  * Returns 1 if the structure is Ok, otherwise returns 0.
187  */
188 int
189 smb_privset_validate(smb_privset_t *privset)
190 {
191 	int count;
192 	uint32_t i;
193 
194 	if (privset == 0) {
195 		return (0);
196 	}
197 
198 	count = SE_MAX_LUID - SE_MIN_LUID + 1;
199 
200 	if (privset->priv_cnt != count) {
201 		return (0);
202 	}
203 
204 	for (i = 0; i < count; i++) {
205 		if (privset->priv[i].luid.hi_part != 0) {
206 			return (0);
207 		}
208 
209 		if (privset->priv[i].luid.lo_part !=
210 		    i + SE_MIN_LUID) {
211 			return (0);
212 		}
213 	}
214 
215 	return (1);
216 }
217 
218 /*
219  * smb_privset_init
220  *
221  * initialize all privileges in disable state.
222  */
223 void
224 smb_privset_init(smb_privset_t *privset)
225 {
226 	int count;
227 	uint32_t i;
228 
229 	if (privset == 0)
230 		return;
231 
232 	count = SE_MAX_LUID - SE_MIN_LUID + 1;
233 
234 	privset->priv_cnt = count;
235 	privset->control = 0;
236 	for (i = 0; i < count; i++) {
237 		privset->priv[i].luid.hi_part = 0;
238 		privset->priv[i].luid.lo_part = i + SE_MIN_LUID;
239 		privset->priv[i].attrs = 0;
240 	}
241 }
242 
243 /*
244  * smb_privset_new
245  *
246  * Allocate memory and initialize all privileges in disable state.
247  * Returns pointer to allocated space or NULL if there is not
248  * enough memory.
249  */
250 smb_privset_t *
251 smb_privset_new()
252 {
253 	smb_privset_t *privset;
254 
255 	privset = malloc(smb_privset_size());
256 	if (privset == NULL)
257 		return (NULL);
258 
259 	smb_privset_init(privset);
260 
261 	return (privset);
262 }
263 
264 /*
265  * smb_privset_copy
266  *
267  * Copy privleges information specified by 'src' to the
268  * buffer specified by dst.
269  */
270 void
271 smb_privset_copy(smb_privset_t *dst, smb_privset_t *src)
272 {
273 	if (src == 0 || dst == 0)
274 		return;
275 
276 	(void) memcpy(dst, src, smb_privset_size());
277 }
278 
279 /*
280  * smb_privset_merge
281  *
282  * Enable the privileges that are enabled in src in dst
283  */
284 void
285 smb_privset_merge(smb_privset_t *dst, smb_privset_t *src)
286 {
287 	int i;
288 
289 	if (src == NULL || dst == NULL)
290 		return;
291 
292 	for (i = 0; i < src->priv_cnt; i++) {
293 		if (src->priv[i].attrs == SE_PRIVILEGE_ENABLED)
294 			smb_privset_enable(dst, src->priv[i].luid.lo_part);
295 	}
296 }
297 
298 /*
299  * smb_privset_free
300  *
301  * This will free the memory allocated by the 'privset'.
302  */
303 void
304 smb_privset_free(smb_privset_t *privset)
305 {
306 	free(privset);
307 }
308 
309 void
310 smb_privset_enable(smb_privset_t *privset, uint32_t id)
311 {
312 	int i;
313 
314 	if (privset == NULL)
315 		return;
316 
317 	for (i = 0; i < privset->priv_cnt; i++) {
318 		if (privset->priv[i].luid.lo_part == id)
319 			privset->priv[i].attrs = SE_PRIVILEGE_ENABLED;
320 	}
321 }
322 
323 void
324 smb_privset_log(smb_privset_t *privset)
325 {
326 	smb_luid_t *luid;
327 	int i, ecnt;
328 
329 	if (privset == NULL)
330 		return;
331 
332 	for (i = 0, ecnt = 0; i < privset->priv_cnt; ++i) {
333 		if (privset->priv[i].attrs != 0) {
334 			ecnt++;
335 		}
336 	}
337 
338 	syslog(LOG_DEBUG, "   Privilege Count: %d (Enable=%d)",
339 	    privset->priv_cnt, ecnt);
340 
341 	for (i = 0; i < privset->priv_cnt; ++i) {
342 		if (privset->priv[i].attrs != 0) {
343 			luid = &privset->priv[i].luid;
344 			syslog(LOG_DEBUG, "    %s",
345 			    smb_priv_getname(luid->lo_part));
346 		}
347 	}
348 }
349 
350 int
351 smb_privset_query(smb_privset_t *privset, uint32_t id)
352 {
353 	int i;
354 
355 	if (privset == NULL)
356 		return (0);
357 
358 	for (i = 0; privset->priv_cnt; i++) {
359 		if (privset->priv[i].luid.lo_part == id) {
360 			if (privset->priv[i].attrs == SE_PRIVILEGE_ENABLED)
361 				return (1);
362 			else
363 				return (0);
364 		}
365 	}
366 
367 	return (0);
368 }
369 
370 static char *
371 smb_priv_getname(uint32_t id)
372 {
373 	if (id < SE_MIN_LUID || id > SE_MAX_LUID)
374 		return ("Unknown Privilege");
375 
376 	return (priv_table[id].name);
377 }
378