• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.0.25b/source/utils/
1/*
2   Unix SMB/CIFS implementation.
3   ACL get/set utility
4
5   Copyright (C) Andrew Tridgell 2000
6   Copyright (C) Tim Potter      2000
7   Copyright (C) Jeremy Allison  2000
8   Copyright (C) Jelmer Vernooij 2003
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23*/
24
25#include "includes.h"
26
27static pstring owner_username;
28static fstring server;
29static int test_args = False;
30static TALLOC_CTX *ctx;
31
32#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
33
34/* numeric is set when the user wants numeric SIDs and ACEs rather
35   than going via LSA calls to resolve them */
36static BOOL numeric = False;
37
38enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD };
39enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP};
40enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
41
42struct perm_value {
43	const char *perm;
44	uint32 mask;
45};
46
47/* These values discovered by inspection */
48
49static const struct perm_value special_values[] = {
50	{ "R", 0x00120089 },
51	{ "W", 0x00120116 },
52	{ "X", 0x001200a0 },
53	{ "D", 0x00010000 },
54	{ "P", 0x00040000 },
55	{ "O", 0x00080000 },
56	{ NULL, 0 },
57};
58
59static const struct perm_value standard_values[] = {
60	{ "READ",   0x001200a9 },
61	{ "CHANGE", 0x001301bf },
62	{ "FULL",   0x001f01ff },
63	{ NULL, 0 },
64};
65
66static struct cli_state *global_hack_cli;
67static struct rpc_pipe_client *global_pipe_hnd;
68static POLICY_HND pol;
69static BOOL got_policy_hnd;
70
71static struct cli_state *connect_one(const char *share);
72
73/* Open cli connection and policy handle */
74
75static BOOL cacls_open_policy_hnd(void)
76{
77	/* Initialise cli LSA connection */
78
79	if (!global_hack_cli) {
80		NTSTATUS ret;
81		global_hack_cli = connect_one("IPC$");
82		global_pipe_hnd = cli_rpc_pipe_open_noauth(global_hack_cli, PI_LSARPC, &ret);
83		if (!global_pipe_hnd) {
84				return False;
85		}
86	}
87
88	/* Open policy handle */
89
90	if (!got_policy_hnd) {
91
92		/* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
93		   but NT sends 0x2000000 so we might as well do it too. */
94
95		if (!NT_STATUS_IS_OK(rpccli_lsa_open_policy(global_pipe_hnd, global_hack_cli->mem_ctx, True,
96							 GENERIC_EXECUTE_ACCESS, &pol))) {
97			return False;
98		}
99
100		got_policy_hnd = True;
101	}
102
103	return True;
104}
105
106/* convert a SID to a string, either numeric or username/group */
107static void SidToString(fstring str, DOM_SID *sid)
108{
109	char **domains = NULL;
110	char **names = NULL;
111	enum lsa_SidType *types = NULL;
112
113	sid_to_string(str, sid);
114
115	if (numeric) return;
116
117	/* Ask LSA to convert the sid to a name */
118
119	if (!cacls_open_policy_hnd() ||
120	    !NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(global_pipe_hnd, global_hack_cli->mem_ctx,
121						 &pol, 1, sid, &domains,
122						 &names, &types)) ||
123	    !domains || !domains[0] || !names || !names[0]) {
124		return;
125	}
126
127	/* Converted OK */
128
129	slprintf(str, sizeof(fstring) - 1, "%s%s%s",
130		 domains[0], lp_winbind_separator(),
131		 names[0]);
132
133}
134
135/* convert a string to a SID, either numeric or username/group */
136static BOOL StringToSid(DOM_SID *sid, const char *str)
137{
138	enum lsa_SidType *types = NULL;
139	DOM_SID *sids = NULL;
140	BOOL result = True;
141
142	if (strncmp(str, "S-", 2) == 0) {
143		return string_to_sid(sid, str);
144	}
145
146	if (!cacls_open_policy_hnd() ||
147	    !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, global_hack_cli->mem_ctx,
148						  &pol, 1, &str, NULL, &sids,
149						  &types))) {
150		result = False;
151		goto done;
152	}
153
154	sid_copy(sid, &sids[0]);
155 done:
156
157	return result;
158}
159
160
161/* print an ACE on a FILE, using either numeric or ascii representation */
162static void print_ace(FILE *f, SEC_ACE *ace)
163{
164	const struct perm_value *v;
165	fstring sidstr;
166	int do_print = 0;
167	uint32 got_mask;
168
169	SidToString(sidstr, &ace->trustee);
170
171	fprintf(f, "%s:", sidstr);
172
173	if (numeric) {
174		fprintf(f, "%d/%d/0x%08x",
175			ace->type, ace->flags, ace->access_mask);
176		return;
177	}
178
179	/* Ace type */
180
181	if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
182		fprintf(f, "ALLOWED");
183	} else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
184		fprintf(f, "DENIED");
185	} else {
186		fprintf(f, "%d", ace->type);
187	}
188
189	/* Not sure what flags can be set in a file ACL */
190
191	fprintf(f, "/%d/", ace->flags);
192
193	/* Standard permissions */
194
195	for (v = standard_values; v->perm; v++) {
196		if (ace->access_mask == v->mask) {
197			fprintf(f, "%s", v->perm);
198			return;
199		}
200	}
201
202	/* Special permissions.  Print out a hex value if we have
203	   leftover bits in the mask. */
204
205	got_mask = ace->access_mask;
206
207 again:
208	for (v = special_values; v->perm; v++) {
209		if ((ace->access_mask & v->mask) == v->mask) {
210			if (do_print) {
211				fprintf(f, "%s", v->perm);
212			}
213			got_mask &= ~v->mask;
214		}
215	}
216
217	if (!do_print) {
218		if (got_mask != 0) {
219			fprintf(f, "0x%08x", ace->access_mask);
220		} else {
221			do_print = 1;
222			goto again;
223		}
224	}
225}
226
227
228/* parse an ACE in the same format as print_ace() */
229static BOOL parse_ace(SEC_ACE *ace, const char *orig_str)
230{
231	char *p;
232	const char *cp;
233	fstring tok;
234	unsigned int atype = 0;
235	unsigned int aflags = 0;
236	unsigned int amask = 0;
237	DOM_SID sid;
238	SEC_ACCESS mask;
239	const struct perm_value *v;
240	char *str = SMB_STRDUP(orig_str);
241
242	if (!str) {
243		return False;
244	}
245
246	ZERO_STRUCTP(ace);
247	p = strchr_m(str,':');
248	if (!p) {
249		printf("ACE '%s': missing ':'.\n", orig_str);
250		SAFE_FREE(str);
251		return False;
252	}
253	*p = '\0';
254	p++;
255	/* Try to parse numeric form */
256
257	if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
258	    StringToSid(&sid, str)) {
259		goto done;
260	}
261
262	/* Try to parse text form */
263
264	if (!StringToSid(&sid, str)) {
265		printf("ACE '%s': failed to convert '%s' to SID\n",
266			orig_str, str);
267		SAFE_FREE(str);
268		return False;
269	}
270
271	cp = p;
272	if (!next_token(&cp, tok, "/", sizeof(fstring))) {
273		printf("ACE '%s': failed to find '/' character.\n",
274			orig_str);
275		SAFE_FREE(str);
276		return False;
277	}
278
279	if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
280		atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
281	} else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
282		atype = SEC_ACE_TYPE_ACCESS_DENIED;
283	} else {
284		printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
285			orig_str, tok);
286		SAFE_FREE(str);
287		return False;
288	}
289
290	/* Only numeric form accepted for flags at present */
291
292	if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
293	      sscanf(tok, "%i", &aflags))) {
294		printf("ACE '%s': bad integer flags entry at '%s'\n",
295			orig_str, tok);
296		SAFE_FREE(str);
297		return False;
298	}
299
300	if (!next_token(&cp, tok, "/", sizeof(fstring))) {
301		printf("ACE '%s': missing / at '%s'\n",
302			orig_str, tok);
303		SAFE_FREE(str);
304		return False;
305	}
306
307	if (strncmp(tok, "0x", 2) == 0) {
308		if (sscanf(tok, "%i", &amask) != 1) {
309			printf("ACE '%s': bad hex number at '%s'\n",
310				orig_str, tok);
311			SAFE_FREE(str);
312			return False;
313		}
314		goto done;
315	}
316
317	for (v = standard_values; v->perm; v++) {
318		if (strcmp(tok, v->perm) == 0) {
319			amask = v->mask;
320			goto done;
321		}
322	}
323
324	p = tok;
325
326	while(*p) {
327		BOOL found = False;
328
329		for (v = special_values; v->perm; v++) {
330			if (v->perm[0] == *p) {
331				amask |= v->mask;
332				found = True;
333			}
334		}
335
336		if (!found) {
337			printf("ACE '%s': bad permission value at '%s'\n",
338				orig_str, p);
339			SAFE_FREE(str);
340		 	return False;
341		}
342		p++;
343	}
344
345	if (*p) {
346		SAFE_FREE(str);
347		return False;
348	}
349
350 done:
351	mask = amask;
352	init_sec_ace(ace, &sid, atype, mask, aflags);
353	SAFE_FREE(str);
354	return True;
355}
356
357/* add an ACE to a list of ACEs in a SEC_ACL */
358static BOOL add_ace(SEC_ACL **the_acl, SEC_ACE *ace)
359{
360	SEC_ACL *new_ace;
361	SEC_ACE *aces;
362	if (! *the_acl) {
363		return (((*the_acl) = make_sec_acl(ctx, 3, 1, ace)) != NULL);
364	}
365
366	if (!(aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces))) {
367		return False;
368	}
369	memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
370	memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
371	new_ace = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
372	SAFE_FREE(aces);
373	(*the_acl) = new_ace;
374	return True;
375}
376
377/* parse a ascii version of a security descriptor */
378static SEC_DESC *sec_desc_parse(char *str)
379{
380	const char *p = str;
381	fstring tok;
382	SEC_DESC *ret = NULL;
383	size_t sd_size;
384	DOM_SID *group_sid=NULL, *owner_sid=NULL;
385	SEC_ACL *dacl=NULL;
386	int revision=1;
387
388	while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
389
390		if (strncmp(tok,"REVISION:", 9) == 0) {
391			revision = strtol(tok+9, NULL, 16);
392			continue;
393		}
394
395		if (strncmp(tok,"OWNER:", 6) == 0) {
396			if (owner_sid) {
397				printf("Only specify owner once\n");
398				goto done;
399			}
400			owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
401			if (!owner_sid ||
402			    !StringToSid(owner_sid, tok+6)) {
403				printf("Failed to parse owner sid\n");
404				goto done;
405			}
406			continue;
407		}
408
409		if (strncmp(tok,"GROUP:", 6) == 0) {
410			if (group_sid) {
411				printf("Only specify group once\n");
412				goto done;
413			}
414			group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
415			if (!group_sid ||
416			    !StringToSid(group_sid, tok+6)) {
417				printf("Failed to parse group sid\n");
418				goto done;
419			}
420			continue;
421		}
422
423		if (strncmp(tok,"ACL:", 4) == 0) {
424			SEC_ACE ace;
425			if (!parse_ace(&ace, tok+4)) {
426				goto done;
427			}
428			if(!add_ace(&dacl, &ace)) {
429				printf("Failed to add ACL %s\n", tok);
430				goto done;
431			}
432			continue;
433		}
434
435		printf("Failed to parse token '%s' in security descriptor,\n", tok);
436		goto done;
437	}
438
439	ret = make_sec_desc(ctx,revision, SEC_DESC_SELF_RELATIVE, owner_sid, group_sid,
440			    NULL, dacl, &sd_size);
441
442  done:
443	SAFE_FREE(group_sid);
444	SAFE_FREE(owner_sid);
445
446	return ret;
447}
448
449
450/* print a ascii version of a security descriptor on a FILE handle */
451static void sec_desc_print(FILE *f, SEC_DESC *sd)
452{
453	fstring sidstr;
454	uint32 i;
455
456	fprintf(f, "REVISION:%d\n", sd->revision);
457
458	/* Print owner and group sid */
459
460	if (sd->owner_sid) {
461		SidToString(sidstr, sd->owner_sid);
462	} else {
463		fstrcpy(sidstr, "");
464	}
465
466	fprintf(f, "OWNER:%s\n", sidstr);
467
468	if (sd->group_sid) {
469		SidToString(sidstr, sd->group_sid);
470	} else {
471		fstrcpy(sidstr, "");
472	}
473
474	fprintf(f, "GROUP:%s\n", sidstr);
475
476	/* Print aces */
477	for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
478		SEC_ACE *ace = &sd->dacl->aces[i];
479		fprintf(f, "ACL:");
480		print_ace(f, ace);
481		fprintf(f, "\n");
482	}
483
484}
485
486/*****************************************************
487dump the acls for a file
488*******************************************************/
489static int cacl_dump(struct cli_state *cli, char *filename)
490{
491	int result = EXIT_FAILED;
492	int fnum = -1;
493	SEC_DESC *sd;
494
495	if (test_args)
496		return EXIT_OK;
497
498	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
499
500	if (fnum == -1) {
501		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
502		goto done;
503	}
504
505	sd = cli_query_secdesc(cli, fnum, ctx);
506
507	if (!sd) {
508		printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
509		goto done;
510	}
511
512	sec_desc_print(stdout, sd);
513
514	result = EXIT_OK;
515
516done:
517	if (fnum != -1)
518		cli_close(cli, fnum);
519
520	return result;
521}
522
523/*****************************************************
524Change the ownership or group ownership of a file. Just
525because the NT docs say this can't be done :-). JRA.
526*******************************************************/
527
528static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
529		     char *filename, char *new_username)
530{
531	int fnum;
532	DOM_SID sid;
533	SEC_DESC *sd, *old;
534	size_t sd_size;
535
536	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
537
538	if (fnum == -1) {
539		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
540		return EXIT_FAILED;
541	}
542
543	if (!StringToSid(&sid, new_username))
544		return EXIT_PARSE_ERROR;
545
546	old = cli_query_secdesc(cli, fnum, ctx);
547
548	cli_close(cli, fnum);
549
550	if (!old) {
551		printf("owner_set: Failed to query old descriptor\n");
552		return EXIT_FAILED;
553	}
554
555	sd = make_sec_desc(ctx,old->revision, old->type,
556				(change_mode == REQUEST_CHOWN) ? &sid : NULL,
557				(change_mode == REQUEST_CHGRP) ? &sid : NULL,
558			   NULL, NULL, &sd_size);
559
560	fnum = cli_nt_create(cli, filename, WRITE_OWNER_ACCESS);
561
562	if (fnum == -1) {
563		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
564		return EXIT_FAILED;
565	}
566
567	if (!cli_set_secdesc(cli, fnum, sd)) {
568		printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
569	}
570
571	cli_close(cli, fnum);
572
573	return EXIT_OK;
574}
575
576
577/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
578   However NT4 gives a "The information may have been modified by a
579   computer running Windows NT 5.0" if denied ACEs do not appear before
580   allowed ACEs. */
581
582static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
583{
584	if (sec_ace_equal(ace1, ace2))
585		return 0;
586
587	if (ace1->type != ace2->type)
588		return ace2->type - ace1->type;
589
590	if (sid_compare(&ace1->trustee, &ace2->trustee))
591		return sid_compare(&ace1->trustee, &ace2->trustee);
592
593	if (ace1->flags != ace2->flags)
594		return ace1->flags - ace2->flags;
595
596	if (ace1->access_mask != ace2->access_mask)
597		return ace1->access_mask - ace2->access_mask;
598
599	if (ace1->size != ace2->size)
600		return ace1->size - ace2->size;
601
602	return memcmp(ace1, ace2, sizeof(SEC_ACE));
603}
604
605static void sort_acl(SEC_ACL *the_acl)
606{
607	uint32 i;
608	if (!the_acl) return;
609
610	qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), QSORT_CAST ace_compare);
611
612	for (i=1;i<the_acl->num_aces;) {
613		if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
614			int j;
615			for (j=i; j<the_acl->num_aces-1; j++) {
616				the_acl->aces[j] = the_acl->aces[j+1];
617			}
618			the_acl->num_aces--;
619		} else {
620			i++;
621		}
622	}
623}
624
625/*****************************************************
626set the ACLs on a file given an ascii description
627*******************************************************/
628static int cacl_set(struct cli_state *cli, char *filename,
629		    char *the_acl, enum acl_mode mode)
630{
631	int fnum;
632	SEC_DESC *sd, *old;
633	uint32 i, j;
634	size_t sd_size;
635	int result = EXIT_OK;
636
637	sd = sec_desc_parse(the_acl);
638
639	if (!sd) return EXIT_PARSE_ERROR;
640	if (test_args) return EXIT_OK;
641
642	/* The desired access below is the only one I could find that works
643	   with NT4, W2KP and Samba */
644
645	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
646
647	if (fnum == -1) {
648		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
649		return EXIT_FAILED;
650	}
651
652	old = cli_query_secdesc(cli, fnum, ctx);
653
654	if (!old) {
655		printf("calc_set: Failed to query old descriptor\n");
656		return EXIT_FAILED;
657	}
658
659	cli_close(cli, fnum);
660
661	/* the logic here is rather more complex than I would like */
662	switch (mode) {
663	case SMB_ACL_DELETE:
664		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
665			BOOL found = False;
666
667			for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
668				if (sec_ace_equal(&sd->dacl->aces[i],
669						  &old->dacl->aces[j])) {
670					uint32 k;
671					for (k=j; k<old->dacl->num_aces-1;k++) {
672						old->dacl->aces[k] = old->dacl->aces[k+1];
673					}
674					old->dacl->num_aces--;
675					found = True;
676					break;
677				}
678			}
679
680			if (!found) {
681				printf("ACL for ACE:");
682				print_ace(stdout, &sd->dacl->aces[i]);
683				printf(" not found\n");
684			}
685		}
686		break;
687
688	case SMB_ACL_MODIFY:
689		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
690			BOOL found = False;
691
692			for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
693				if (sid_equal(&sd->dacl->aces[i].trustee,
694					      &old->dacl->aces[j].trustee)) {
695					old->dacl->aces[j] = sd->dacl->aces[i];
696					found = True;
697				}
698			}
699
700			if (!found) {
701				fstring str;
702
703				SidToString(str, &sd->dacl->aces[i].trustee);
704				printf("ACL for SID %s not found\n", str);
705			}
706		}
707
708		if (sd->owner_sid) {
709			old->owner_sid = sd->owner_sid;
710		}
711
712		if (sd->group_sid) {
713			old->group_sid = sd->group_sid;
714		}
715
716		break;
717
718	case SMB_ACL_ADD:
719		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
720			add_ace(&old->dacl, &sd->dacl->aces[i]);
721		}
722		break;
723
724	case SMB_ACL_SET:
725 		old = sd;
726		break;
727	}
728
729	/* Denied ACE entries must come before allowed ones */
730	sort_acl(old->dacl);
731
732	/* Create new security descriptor and set it */
733#if 0
734	/* We used to just have "WRITE_DAC_ACCESS" without WRITE_OWNER.
735	   But if we're sending an owner, even if it's the same as the one
736	   that already exists then W2K3 insists we open with WRITE_OWNER access.
737	   I need to check that setting a SD with no owner set works against WNT
738	   and W2K. JRA.
739	*/
740
741	sd = make_sec_desc(ctx,old->revision, old->type, old->owner_sid, old->group_sid,
742			   NULL, old->dacl, &sd_size);
743
744	fnum = cli_nt_create(cli, filename, WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS);
745#else
746	sd = make_sec_desc(ctx,old->revision, old->type, NULL, NULL,
747			   NULL, old->dacl, &sd_size);
748
749	fnum = cli_nt_create(cli, filename, WRITE_DAC_ACCESS);
750#endif
751	if (fnum == -1) {
752		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
753		return EXIT_FAILED;
754	}
755
756	if (!cli_set_secdesc(cli, fnum, sd)) {
757		printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
758		result = EXIT_FAILED;
759	}
760
761	/* Clean up */
762
763	cli_close(cli, fnum);
764
765	return result;
766}
767
768
769/*****************************************************
770return a connection to a server
771*******************************************************/
772static struct cli_state *connect_one(const char *share)
773{
774	struct cli_state *c;
775	struct in_addr ip;
776	NTSTATUS nt_status;
777	zero_ip(&ip);
778
779	if (!cmdline_auth_info.got_pass) {
780		char *pass = getpass("Password: ");
781		if (pass) {
782			pstrcpy(cmdline_auth_info.password, pass);
783			cmdline_auth_info.got_pass = True;
784		}
785	}
786
787	if (NT_STATUS_IS_OK(nt_status = cli_full_connection(&c, global_myname(), server,
788							    &ip, 0,
789							    share, "?????",
790							    cmdline_auth_info.username, lp_workgroup(),
791							    cmdline_auth_info.password, 0,
792							    cmdline_auth_info.signing_state, NULL))) {
793		return c;
794	} else {
795		DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
796		return NULL;
797	}
798}
799
800/****************************************************************************
801  main program
802****************************************************************************/
803 int main(int argc, const char *argv[])
804{
805	char *share;
806	int opt;
807	enum acl_mode mode = SMB_ACL_SET;
808	static char *the_acl = NULL;
809	enum chown_mode change_mode = REQUEST_NONE;
810	int result;
811	fstring path;
812	pstring filename;
813	poptContext pc;
814	struct poptOption long_options[] = {
815		POPT_AUTOHELP
816		{ "delete", 'D', POPT_ARG_STRING, NULL, 'D', "Delete an acl", "ACL" },
817		{ "modify", 'M', POPT_ARG_STRING, NULL, 'M', "Modify an acl", "ACL" },
818		{ "add", 'a', POPT_ARG_STRING, NULL, 'a', "Add an acl", "ACL" },
819		{ "set", 'S', POPT_ARG_STRING, NULL, 'S', "Set acls", "ACLS" },
820		{ "chown", 'C', POPT_ARG_STRING, NULL, 'C', "Change ownership of a file", "USERNAME" },
821		{ "chgrp", 'G', POPT_ARG_STRING, NULL, 'G', "Change group ownership of a file", "GROUPNAME" },
822		{ "numeric", 0, POPT_ARG_NONE, &numeric, True, "Don't resolve sids or masks to names" },
823		{ "test-args", 't', POPT_ARG_NONE, &test_args, True, "Test arguments"},
824		POPT_COMMON_SAMBA
825		POPT_COMMON_CREDENTIALS
826		{ NULL }
827	};
828
829	struct cli_state *cli;
830
831	load_case_tables();
832
833	ctx=talloc_init("main");
834
835	/* set default debug level to 1 regardless of what smb.conf sets */
836	setup_logging( "smbcacls", True );
837	DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
838	dbf = x_stderr;
839	x_setbuf( x_stderr, NULL );
840
841	setlinebuf(stdout);
842
843	lp_load(dyn_CONFIGFILE,True,False,False,True);
844	load_interfaces();
845
846	pc = poptGetContext("smbcacls", argc, argv, long_options, 0);
847
848	poptSetOtherOptionHelp(pc, "//server1/share1 filename\nACLs look like: "
849		"'ACL:user:[ALLOWED|DENIED]/flags/permissions'");
850
851	while ((opt = poptGetNextOpt(pc)) != -1) {
852		switch (opt) {
853		case 'S':
854			the_acl = smb_xstrdup(poptGetOptArg(pc));
855			mode = SMB_ACL_SET;
856			break;
857
858		case 'D':
859			the_acl = smb_xstrdup(poptGetOptArg(pc));
860			mode = SMB_ACL_DELETE;
861			break;
862
863		case 'M':
864			the_acl = smb_xstrdup(poptGetOptArg(pc));
865			mode = SMB_ACL_MODIFY;
866			break;
867
868		case 'a':
869			the_acl = smb_xstrdup(poptGetOptArg(pc));
870			mode = SMB_ACL_ADD;
871			break;
872
873		case 'C':
874			pstrcpy(owner_username,poptGetOptArg(pc));
875			change_mode = REQUEST_CHOWN;
876			break;
877
878		case 'G':
879			pstrcpy(owner_username,poptGetOptArg(pc));
880			change_mode = REQUEST_CHGRP;
881			break;
882		}
883	}
884
885	/* Make connection to server */
886	if(!poptPeekArg(pc)) {
887		poptPrintUsage(pc, stderr, 0);
888		return -1;
889	}
890
891	fstrcpy(path, poptGetArg(pc));
892
893	if(!poptPeekArg(pc)) {
894		poptPrintUsage(pc, stderr, 0);
895		return -1;
896	}
897
898	pstrcpy(filename, poptGetArg(pc));
899
900	all_string_sub(path,"/","\\",0);
901
902	fstrcpy(server,path+2);
903	share = strchr_m(server,'\\');
904	if (!share) {
905		share = strchr_m(server,'/');
906		if (!share) {
907			printf("Invalid argument: %s\n", share);
908			return -1;
909		}
910	}
911
912	*share = 0;
913	share++;
914
915	if (!test_args) {
916		cli = connect_one(share);
917		if (!cli) {
918			talloc_destroy(ctx);
919			exit(EXIT_FAILED);
920		}
921	} else {
922		exit(0);
923	}
924
925	all_string_sub(filename, "/", "\\", 0);
926	if (filename[0] != '\\') {
927		pstring s;
928		s[0] = '\\';
929		safe_strcpy(&s[1], filename, sizeof(pstring)-2);
930		pstrcpy(filename, s);
931	}
932
933	/* Perform requested action */
934
935	if (change_mode != REQUEST_NONE) {
936		result = owner_set(cli, change_mode, filename, owner_username);
937	} else if (the_acl) {
938		result = cacl_set(cli, filename, the_acl, mode);
939	} else {
940		result = cacl_dump(cli, filename);
941	}
942
943	talloc_destroy(ctx);
944
945	return result;
946}
947