1/*
2   Unix SMB/Netbios implementation.
3   Version 2.0
4
5   Printer security permission manipulation.
6
7   Copyright (C) Tim Potter 2000
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24/* This program can get or set NT printer security permissions from the
25   command line.  Usage: psec getsec|setsec printername.  You must have
26   write access to the ntdrivers.tdb file to set permissions and read
27   access to get permissions.
28
29   For this program to compile using the supplied Makefile.psec, Samba
30   must be configured with the --srcdir option
31
32   For getsec, output like the following is sent to standard output:
33
34       S-1-5-21-1067277791-1719175008-3000797951-500
35
36       1 9 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-501
37       1 2 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-501
38       0 9 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-500
39       0 2 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-500
40       0 9 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-513
41       0 2 0x00020000 S-1-5-21-1067277791-1719175008-3000797951-513
42       0 2 0xe0000000 S-1-1-0
43
44   The first two lines describe the owner user and owner group of the printer.
45   If either of these lines are blank then the respective owner property is
46   not set.  The remaining lines list the printer permissions or ACE entries,
47   one per line.  Each column describes a different property of the ACE:
48
49       Column    Description
50       -------------------------------------------------------------------
51         1       ACE type (allow/deny etc) defined in rpc_secdes.h
52         2       ACE flags defined in rpc_secdes.h
53         3       ACE mask - printer ACE masks are defined in rpc_spoolss.h
54         4       SID the ACE applies to
55
56   The above example describes the following permissions in order:
57
58       - The guest user has No Access to the printer
59       - The domain administrator has Full Access
60       - Domain Users can Manage Documents
61       - Everyone has Print access
62
63   The setsec command takes the output format but sets the security descriptor
64   appropriately. */
65
66#include "includes.h"
67
68TDB_CONTEXT *tdb;
69
70/* ACE type conversions */
71
72char *ace_type_to_str(uint ace_type)
73{
74	static fstring temp;
75
76	switch(ace_type) {
77	case SEC_ACE_TYPE_ACCESS_DENIED:
78		return "DENY";
79	case SEC_ACE_TYPE_ACCESS_ALLOWED:
80		return "ALLOW";
81	}
82
83	slprintf(temp, sizeof(temp) - 1, "0x%02x", ace_type);
84	return temp;
85}
86
87uint str_to_ace_type(char *ace_type)
88{
89	if (strcmp(ace_type, "ALLOWED") == 0)
90		return SEC_ACE_TYPE_ACCESS_ALLOWED;
91
92	if (strcmp(ace_type, "DENIED") == 0)
93		return SEC_ACE_TYPE_ACCESS_DENIED;
94
95	return -1;
96}
97
98/* ACE mask (permission) conversions */
99
100char *ace_mask_to_str(uint32 ace_mask)
101{
102	static fstring temp;
103
104	switch (ace_mask) {
105	case PRINTER_ACE_FULL_CONTROL:
106		return "Full Control";
107	case PRINTER_ACE_MANAGE_DOCUMENTS:
108		return "Manage Documents";
109	case PRINTER_ACE_PRINT:
110		return "Print";
111	}
112
113	slprintf(temp, sizeof(temp) - 1, "0x%08x", ace_mask);
114	return temp;
115}
116
117uint32 str_to_ace_mask(char *ace_mask)
118{
119	if (strcmp(ace_mask, "Full Control") == 0)
120		return PRINTER_ACE_FULL_CONTROL;
121
122	if (strcmp(ace_mask, "Manage Documents") == 0)
123		return PRINTER_ACE_MANAGE_DOCUMENTS;
124
125	if (strcmp(ace_mask, "Print") == 0)
126		return PRINTER_ACE_PRINT;
127
128	return -1;
129}
130
131/* ACE conversions */
132
133char *ace_to_str(SEC_ACE *ace)
134{
135	static pstring temp;
136	fstring sidstr;
137
138	sid_to_string(sidstr, &ace->sid);
139
140	slprintf(temp, sizeof(temp) - 1, "%s %d %s %s",
141		 ace_type_to_str(ace->type), ace->flags,
142		 ace_mask_to_str(ace->info.mask), sidstr);
143
144	return temp;
145}
146
147void str_to_ace(SEC_ACE *ace, char *ace_str)
148{
149	SEC_ACCESS sa;
150	DOM_SID sid;
151	uint32 mask;
152	uint8 type, flags;
153
154	init_sec_access(&sa, mask);
155	init_sec_ace(ace, &sid, type, sa, flags);
156}
157
158/* Get a printer security descriptor */
159
160int psec_getsec(char *printer)
161{
162	SEC_DESC_BUF *secdesc_ctr = NULL;
163	TALLOC_CTX *mem_ctx = NULL;
164	fstring keystr, sidstr, tdb_path;
165	prs_struct ps;
166	int result = 0, i;
167
168	ZERO_STRUCT(ps);
169
170	/* Open tdb for reading */
171
172	slprintf(tdb_path, sizeof(tdb_path) - 1, "%s/ntdrivers.tdb",
173		 lp_lockdir());
174
175	tdb = tdb_open(tdb_path, 0, 0, O_RDONLY, 0600);
176
177	if (!tdb) {
178		printf("psec: failed to open nt drivers database: %s\n",
179		       sys_errlist[errno]);
180		return 1;
181	}
182
183	/* Get security blob from tdb */
184
185	slprintf(keystr, sizeof(keystr) - 1, "SECDESC/%s", printer);
186
187	mem_ctx = talloc_init();
188
189	if (!mem_ctx) {
190		printf("memory allocation error\n");
191		result = 1;
192		goto done;
193	}
194
195	if (tdb_prs_fetch(tdb, keystr, &ps, mem_ctx) != 0) {
196		printf("error fetching descriptor for printer %s\n",
197		       printer);
198		/* cannot do a prs_mem_free() when tdb_prs_fetch fails */
199		/* as the prs structure has not been initialized */
200		tdb_close(tdb);
201		talloc_destroy(mem_ctx);
202		return 1;
203	}
204
205	/* Unpack into security descriptor buffer */
206
207	if (!sec_io_desc_buf("nt_printing_getsec", &secdesc_ctr, &ps, 1)) {
208		printf("error unpacking sec_desc_buf\n");
209		result = 1;
210		goto done;
211	}
212
213	/* Print owner and group sid */
214
215	if (secdesc_ctr->sec->owner_sid) {
216		sid_to_string(sidstr, secdesc_ctr->sec->owner_sid);
217	} else {
218		fstrcpy(sidstr, "");
219	}
220
221	printf("%s\n", sidstr);
222
223	if (secdesc_ctr->sec->grp_sid) {
224		sid_to_string(sidstr, secdesc_ctr->sec->grp_sid);
225	} else {
226		fstrcpy(sidstr, "");
227	}
228
229	printf("%s\n", sidstr);
230
231	/* Print aces */
232
233	if (!secdesc_ctr->sec->dacl) {
234		result = 0;
235		goto done;
236	}
237
238	for (i = 0; i < secdesc_ctr->sec->dacl->num_aces; i++) {
239		SEC_ACE *ace = &secdesc_ctr->sec->dacl->ace[i];
240
241		sid_to_string(sidstr, &ace->sid);
242
243		printf("%d %d 0x%08x %s\n", ace->type, ace->flags,
244		       ace->info.mask, sidstr);
245	}
246
247 done:
248	if (tdb) tdb_close(tdb);
249	if (mem_ctx) talloc_destroy(mem_ctx);
250	if (secdesc_ctr) free_sec_desc_buf(&secdesc_ctr);
251	prs_mem_free(&ps);
252
253	return result;
254}
255
256/* Set a printer security descriptor */
257
258int psec_setsec(char *printer)
259{
260	DOM_SID user_sid, group_sid;
261	SEC_ACE *ace_list = NULL;
262	SEC_ACL *dacl = NULL;
263	SEC_DESC *sd;
264	SEC_DESC_BUF *sdb = NULL;
265	int result = 0, num_aces = 0;
266	fstring line, keystr, tdb_path;
267	size_t size;
268	prs_struct ps;
269	TALLOC_CTX *mem_ctx = NULL;
270	BOOL has_user_sid = False, has_group_sid = False;
271
272	ZERO_STRUCT(ps);
273
274	/* Open tdb for reading */
275
276	slprintf(tdb_path, sizeof(tdb_path) - 1, "%s/ntdrivers.tdb",
277		 lp_lockdir());
278
279	tdb = tdb_open(tdb_path, 0, 0, O_RDWR, 0600);
280
281	if (!tdb) {
282		printf("psec: failed to open nt drivers database: %s\n",
283		       sys_errlist[errno]);
284		result = 1;
285		goto done;
286	}
287
288	/* Read owner and group sid */
289
290	fgets(line, sizeof(fstring), stdin);
291	if (line[0] != '\n') {
292		string_to_sid(&user_sid, line);
293		has_user_sid = True;
294	}
295
296	fgets(line, sizeof(fstring), stdin);
297	if (line[0] != '\n') {
298		string_to_sid(&group_sid, line);
299		has_group_sid = True;
300	}
301
302	/* Read ACEs from standard input for discretionary ACL */
303
304	while(fgets(line, sizeof(fstring), stdin)) {
305		int ace_type, ace_flags;
306		uint32 ace_mask;
307		fstring sidstr;
308		DOM_SID sid;
309		SEC_ACCESS sa;
310
311		if (sscanf(line, "%d %d 0x%x %s", &ace_type, &ace_flags,
312			   &ace_mask, sidstr) != 4) {
313			continue;
314		}
315
316		string_to_sid(&sid, sidstr);
317
318		ace_list = Realloc(ace_list, sizeof(SEC_ACE) *
319				   (num_aces + 1));
320
321		init_sec_access(&sa, ace_mask);
322		init_sec_ace(&ace_list[num_aces], &sid, ace_type, sa,
323			     ace_flags);
324
325		num_aces++;
326	}
327
328	dacl = make_sec_acl(ACL_REVISION, num_aces, ace_list);
329	free(ace_list);
330
331	/* Create security descriptor */
332
333	sd = make_sec_desc(SEC_DESC_REVISION,
334			   has_user_sid ? &user_sid : NULL,
335			   has_group_sid ? &group_sid : NULL,
336			   NULL, /* System ACL */
337			   dacl, /* Discretionary ACL */
338			   &size);
339
340	free_sec_acl(&dacl);
341
342	sdb = make_sec_desc_buf(size, sd);
343
344	free_sec_desc(&sd);
345
346	/* Write security descriptor to tdb */
347
348	mem_ctx = talloc_init();
349
350	if (!mem_ctx) {
351		printf("memory allocation error\n");
352		result = 1;
353		goto done;
354	}
355
356	prs_init(&ps, (uint32)sec_desc_size(sdb->sec) +
357		 sizeof(SEC_DESC_BUF), 4, mem_ctx, MARSHALL);
358
359	if (!sec_io_desc_buf("nt_printing_setsec", &sdb, &ps, 1)) {
360		printf("sec_io_desc_buf failed\n");
361		goto done;
362	}
363
364	slprintf(keystr, sizeof(keystr) - 1, "SECDESC/%s", printer);
365
366	if (!tdb_prs_store(tdb, keystr, &ps)==0) {
367		printf("Failed to store secdesc for %s\n", printer);
368		goto done;
369	}
370
371 done:
372	if (tdb) tdb_close(tdb);
373	if (sdb) free_sec_desc_buf(&sdb);
374	if (mem_ctx) talloc_destroy(mem_ctx);
375	prs_mem_free(&ps);
376
377	return result;
378}
379
380/* Help */
381
382void usage(void)
383{
384	printf("Usage: psec getsec|setsec printername\n");
385}
386
387/* Main function */
388
389int main(int argc, char **argv)
390{
391	pstring servicesf = CONFIGFILE;
392
393	/* Argument check */
394
395	if (argc == 1) {
396		usage();
397		return 1;
398	}
399
400	/* Load smb.conf file */
401
402	charset_initialise();
403
404	if (!lp_load(servicesf,False,False,True)) {
405		fprintf(stderr, "Couldn't load confiuration file %s\n",
406			servicesf);
407		return 1;
408	}
409
410	/* Do commands */
411
412	if (strcmp(argv[1], "setsec") == 0) {
413
414		if (argc != 3) {
415			usage();
416			return 1;
417		}
418
419		return psec_setsec(argv[2]);
420	}
421
422	if (strcmp(argv[1], "getsec") == 0) {
423
424		if (argc != 3) {
425			usage();
426			return 1;
427		}
428
429		return psec_getsec(argv[2]);
430	}
431
432	/* An unknown command */
433
434	printf("psec: unknown command %s\n", argv[1]);
435	return 1;
436}
437