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