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