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
smb_priv_presentable_num()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
smb_priv_presentable_ids(uint32_t * ids,int num)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 *
smb_priv_getbyvalue(uint32_t id)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 *
smb_priv_getbyname(char * name)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
smb_privset_size()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
smb_privset_validate(smb_privset_t * privset)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
smb_privset_init(smb_privset_t * privset)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 *
smb_privset_new()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
smb_privset_copy(smb_privset_t * dst,smb_privset_t * src)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
smb_privset_merge(smb_privset_t * dst,smb_privset_t * src)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
smb_privset_free(smb_privset_t * privset)308 smb_privset_free(smb_privset_t *privset)
309 {
310 free(privset);
311 }
312
313 void
smb_privset_enable(smb_privset_t * privset,uint32_t id)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
smb_privset_log(smb_privset_t * privset)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
smb_privset_query(smb_privset_t * privset,uint32_t id)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 *
smb_priv_getname(uint32_t id)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