1/*
2   Unix SMB/Netbios implementation.
3   SMB client library implementation
4   Copyright (C) Andrew Tridgell 1998
5   Copyright (C) Richard Sharpe 2000, 2002
6   Copyright (C) John Terpstra 2000
7   Copyright (C) Tom Jansen (Ninja ISD) 2002
8   Copyright (C) Derrell Lipman 2003-2008
9   Copyright (C) Jeremy Allison 2007, 2008
10
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 3 of the License, or
14   (at your option) any later version.
15
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program.  If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "includes.h"
26#include "libsmbclient.h"
27#include "libsmb_internal.h"
28
29
30/*
31 * Find an lsa pipe handle associated with a cli struct.
32 */
33static struct rpc_pipe_client *
34find_lsa_pipe_hnd(struct cli_state *ipc_cli)
35{
36	struct rpc_pipe_client *pipe_hnd;
37
38	for (pipe_hnd = ipc_cli->pipe_list;
39             pipe_hnd;
40             pipe_hnd = pipe_hnd->next) {
41
42		if (ndr_syntax_id_equal(&pipe_hnd->abstract_syntax,
43					&ndr_table_lsarpc.syntax_id)) {
44			return pipe_hnd;
45		}
46	}
47
48	return NULL;
49}
50
51/*
52 * Sort ACEs according to the documentation at
53 * http://support.microsoft.com/kb/269175, at least as far as it defines the
54 * order.
55 */
56
57static int
58ace_compare(SEC_ACE *ace1,
59            SEC_ACE *ace2)
60{
61        bool b1;
62        bool b2;
63
64        /* If the ACEs are equal, we have nothing more to do. */
65        if (sec_ace_equal(ace1, ace2)) {
66		return 0;
67        }
68
69        /* Inherited follow non-inherited */
70        b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
71        b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
72        if (b1 != b2) {
73                return (b1 ? 1 : -1);
74        }
75
76        /*
77         * What shall we do with AUDITs and ALARMs?  It's undefined.  We'll
78         * sort them after DENY and ALLOW.
79         */
80        b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
81              ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
82              ace1->type != SEC_ACE_TYPE_ACCESS_DENIED &&
83              ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
84        b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
85              ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
86              ace2->type != SEC_ACE_TYPE_ACCESS_DENIED &&
87              ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
88        if (b1 != b2) {
89                return (b1 ? 1 : -1);
90        }
91
92        /* Allowed ACEs follow denied ACEs */
93        b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
94              ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
95        b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
96              ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
97        if (b1 != b2) {
98                return (b1 ? 1 : -1);
99        }
100
101        /*
102         * ACEs applying to an entity's object follow those applying to the
103         * entity itself
104         */
105        b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
106              ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
107        b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
108              ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
109        if (b1 != b2) {
110                return (b1 ? 1 : -1);
111        }
112
113        /*
114         * If we get this far, the ACEs are similar as far as the
115         * characteristics we typically care about (those defined by the
116         * referenced MS document).  We'll now sort by characteristics that
117         * just seems reasonable.
118         */
119
120	if (ace1->type != ace2->type) {
121		return ace2->type - ace1->type;
122        }
123
124	if (sid_compare(&ace1->trustee, &ace2->trustee)) {
125		return sid_compare(&ace1->trustee, &ace2->trustee);
126        }
127
128	if (ace1->flags != ace2->flags) {
129		return ace1->flags - ace2->flags;
130        }
131
132	if (ace1->access_mask != ace2->access_mask) {
133		return ace1->access_mask - ace2->access_mask;
134        }
135
136	if (ace1->size != ace2->size) {
137		return ace1->size - ace2->size;
138        }
139
140	return memcmp(ace1, ace2, sizeof(SEC_ACE));
141}
142
143
144static void
145sort_acl(SEC_ACL *the_acl)
146{
147	uint32 i;
148	if (!the_acl) return;
149
150	qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]),
151              QSORT_CAST ace_compare);
152
153	for (i=1;i<the_acl->num_aces;) {
154		if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
155			int j;
156			for (j=i; j<the_acl->num_aces-1; j++) {
157				the_acl->aces[j] = the_acl->aces[j+1];
158			}
159			the_acl->num_aces--;
160		} else {
161			i++;
162		}
163	}
164}
165
166/* convert a SID to a string, either numeric or username/group */
167static void
168convert_sid_to_string(struct cli_state *ipc_cli,
169                      struct policy_handle *pol,
170                      fstring str,
171                      bool numeric,
172                      DOM_SID *sid)
173{
174	char **domains = NULL;
175	char **names = NULL;
176	enum lsa_SidType *types = NULL;
177	struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
178	TALLOC_CTX *ctx;
179
180	sid_to_fstring(str, sid);
181
182	if (numeric) {
183		return;     /* no lookup desired */
184	}
185
186	if (!pipe_hnd) {
187		return;
188	}
189
190	/* Ask LSA to convert the sid to a name */
191
192	ctx = talloc_stackframe();
193
194	if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx,
195                                                    pol, 1, sid, &domains,
196                                                    &names, &types)) ||
197	    !domains || !domains[0] || !names || !names[0]) {
198		TALLOC_FREE(ctx);
199		return;
200	}
201
202	/* Converted OK */
203
204	slprintf(str, sizeof(fstring) - 1, "%s%s%s",
205		 domains[0], lp_winbind_separator(),
206		 names[0]);
207
208	TALLOC_FREE(ctx);
209}
210
211/* convert a string to a SID, either numeric or username/group */
212static bool
213convert_string_to_sid(struct cli_state *ipc_cli,
214                      struct policy_handle *pol,
215                      bool numeric,
216                      DOM_SID *sid,
217                      const char *str)
218{
219	enum lsa_SidType *types = NULL;
220	DOM_SID *sids = NULL;
221	bool result = True;
222	TALLOC_CTX *ctx = NULL;
223	struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
224
225	if (!pipe_hnd) {
226		return False;
227	}
228
229        if (numeric) {
230                if (strncmp(str, "S-", 2) == 0) {
231                        return string_to_sid(sid, str);
232                }
233
234                result = False;
235                goto done;
236        }
237
238	ctx = talloc_stackframe();
239	if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx,
240                                                     pol, 1, &str,
241                                                     NULL, 1, &sids,
242                                                     &types))) {
243		result = False;
244		goto done;
245	}
246
247	sid_copy(sid, &sids[0]);
248done:
249
250	TALLOC_FREE(ctx);
251	return result;
252}
253
254
255/* parse an ACE in the same format as print_ace() */
256static bool
257parse_ace(struct cli_state *ipc_cli,
258          struct policy_handle *pol,
259          SEC_ACE *ace,
260          bool numeric,
261          char *str)
262{
263	char *p;
264	const char *cp;
265	char *tok;
266	unsigned int atype;
267        unsigned int aflags;
268        unsigned int amask;
269	DOM_SID sid;
270	uint32_t mask;
271	const struct perm_value *v;
272        struct perm_value {
273                const char perm[7];
274                uint32 mask;
275        };
276	TALLOC_CTX *frame = talloc_stackframe();
277
278        /* These values discovered by inspection */
279        static const struct perm_value special_values[] = {
280                { "R", 0x00120089 },
281                { "W", 0x00120116 },
282                { "X", 0x001200a0 },
283                { "D", 0x00010000 },
284                { "P", 0x00040000 },
285                { "O", 0x00080000 },
286                { "", 0 },
287        };
288
289        static const struct perm_value standard_values[] = {
290                { "READ",   0x001200a9 },
291                { "CHANGE", 0x001301bf },
292                { "FULL",   0x001f01ff },
293                { "", 0 },
294        };
295
296
297	ZERO_STRUCTP(ace);
298	p = strchr_m(str,':');
299	if (!p) {
300		TALLOC_FREE(frame);
301		return False;
302	}
303	*p = '\0';
304	p++;
305	/* Try to parse numeric form */
306
307	if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
308	    convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
309		goto done;
310	}
311
312	/* Try to parse text form */
313
314	if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
315		TALLOC_FREE(frame);
316		return false;
317	}
318
319	cp = p;
320	if (!next_token_talloc(frame, &cp, &tok, "/")) {
321		TALLOC_FREE(frame);
322		return false;
323	}
324
325	if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
326		atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
327	} else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) {
328		atype = SEC_ACE_TYPE_ACCESS_DENIED;
329	} else {
330		TALLOC_FREE(frame);
331		return false;
332	}
333
334	/* Only numeric form accepted for flags at present */
335
336	if (!(next_token_talloc(frame, &cp, &tok, "/") &&
337	      sscanf(tok, "%i", &aflags))) {
338		TALLOC_FREE(frame);
339		return false;
340	}
341
342	if (!next_token_talloc(frame, &cp, &tok, "/")) {
343		TALLOC_FREE(frame);
344		return false;
345	}
346
347	if (strncmp(tok, "0x", 2) == 0) {
348		if (sscanf(tok, "%i", &amask) != 1) {
349			TALLOC_FREE(frame);
350			return false;
351		}
352		goto done;
353	}
354
355	for (v = standard_values; v->perm; v++) {
356		if (strcmp(tok, v->perm) == 0) {
357			amask = v->mask;
358			goto done;
359		}
360	}
361
362	p = tok;
363
364	while(*p) {
365		bool found = False;
366
367		for (v = special_values; v->perm; v++) {
368			if (v->perm[0] == *p) {
369				amask |= v->mask;
370				found = True;
371			}
372		}
373
374		if (!found) {
375			TALLOC_FREE(frame);
376		 	return false;
377		}
378		p++;
379	}
380
381	if (*p) {
382		TALLOC_FREE(frame);
383		return false;
384	}
385
386done:
387	mask = amask;
388	init_sec_ace(ace, &sid, atype, mask, aflags);
389	TALLOC_FREE(frame);
390	return true;
391}
392
393/* add an ACE to a list of ACEs in a SEC_ACL */
394static bool
395add_ace(SEC_ACL **the_acl,
396        SEC_ACE *ace,
397        TALLOC_CTX *ctx)
398{
399	SEC_ACL *newacl;
400	SEC_ACE *aces;
401
402	if (! *the_acl) {
403		(*the_acl) = make_sec_acl(ctx, 3, 1, ace);
404		return True;
405	}
406
407	if ((aces = SMB_CALLOC_ARRAY(SEC_ACE,
408                                     1+(*the_acl)->num_aces)) == NULL) {
409		return False;
410	}
411	memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
412	memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
413	newacl = make_sec_acl(ctx, (*the_acl)->revision,
414                              1+(*the_acl)->num_aces, aces);
415	SAFE_FREE(aces);
416	(*the_acl) = newacl;
417	return True;
418}
419
420
421/* parse a ascii version of a security descriptor */
422static SEC_DESC *
423sec_desc_parse(TALLOC_CTX *ctx,
424               struct cli_state *ipc_cli,
425               struct policy_handle *pol,
426               bool numeric,
427               const char *str)
428{
429	const char *p = str;
430	char *tok;
431	SEC_DESC *ret = NULL;
432	size_t sd_size;
433	DOM_SID *group_sid=NULL;
434        DOM_SID *owner_sid=NULL;
435	SEC_ACL *dacl=NULL;
436	int revision=1;
437
438	while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
439
440		if (StrnCaseCmp(tok,"REVISION:", 9) == 0) {
441			revision = strtol(tok+9, NULL, 16);
442			continue;
443		}
444
445		if (StrnCaseCmp(tok,"OWNER:", 6) == 0) {
446			if (owner_sid) {
447				DEBUG(5,("OWNER specified more than once!\n"));
448				goto done;
449			}
450			owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
451			if (!owner_sid ||
452			    !convert_string_to_sid(ipc_cli, pol,
453                                                   numeric,
454                                                   owner_sid, tok+6)) {
455				DEBUG(5, ("Failed to parse owner sid\n"));
456				goto done;
457			}
458			continue;
459		}
460
461		if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) {
462			if (owner_sid) {
463				DEBUG(5,("OWNER specified more than once!\n"));
464				goto done;
465			}
466			owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
467			if (!owner_sid ||
468			    !convert_string_to_sid(ipc_cli, pol,
469                                                   False,
470                                                   owner_sid, tok+7)) {
471				DEBUG(5, ("Failed to parse owner sid\n"));
472				goto done;
473			}
474			continue;
475		}
476
477		if (StrnCaseCmp(tok,"GROUP:", 6) == 0) {
478			if (group_sid) {
479				DEBUG(5,("GROUP specified more than once!\n"));
480				goto done;
481			}
482			group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
483			if (!group_sid ||
484			    !convert_string_to_sid(ipc_cli, pol,
485                                                   numeric,
486                                                   group_sid, tok+6)) {
487				DEBUG(5, ("Failed to parse group sid\n"));
488				goto done;
489			}
490			continue;
491		}
492
493		if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) {
494			if (group_sid) {
495				DEBUG(5,("GROUP specified more than once!\n"));
496				goto done;
497			}
498			group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
499			if (!group_sid ||
500			    !convert_string_to_sid(ipc_cli, pol,
501                                                   False,
502                                                   group_sid, tok+6)) {
503				DEBUG(5, ("Failed to parse group sid\n"));
504				goto done;
505			}
506			continue;
507		}
508
509		if (StrnCaseCmp(tok,"ACL:", 4) == 0) {
510			SEC_ACE ace;
511			if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) {
512				DEBUG(5, ("Failed to parse ACL %s\n", tok));
513				goto done;
514			}
515			if(!add_ace(&dacl, &ace, ctx)) {
516				DEBUG(5, ("Failed to add ACL %s\n", tok));
517				goto done;
518			}
519			continue;
520		}
521
522		if (StrnCaseCmp(tok,"ACL+:", 5) == 0) {
523			SEC_ACE ace;
524			if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) {
525				DEBUG(5, ("Failed to parse ACL %s\n", tok));
526				goto done;
527			}
528			if(!add_ace(&dacl, &ace, ctx)) {
529				DEBUG(5, ("Failed to add ACL %s\n", tok));
530				goto done;
531			}
532			continue;
533		}
534
535		DEBUG(5, ("Failed to parse security descriptor\n"));
536		goto done;
537	}
538
539	ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE,
540			    owner_sid, group_sid, NULL, dacl, &sd_size);
541
542done:
543	SAFE_FREE(group_sid);
544	SAFE_FREE(owner_sid);
545
546	return ret;
547}
548
549
550/* Obtain the current dos attributes */
551static DOS_ATTR_DESC *
552dos_attr_query(SMBCCTX *context,
553               TALLOC_CTX *ctx,
554               const char *filename,
555               SMBCSRV *srv)
556{
557        struct timespec create_time_ts;
558        struct timespec write_time_ts;
559        struct timespec access_time_ts;
560        struct timespec change_time_ts;
561        SMB_OFF_T size = 0;
562        uint16 mode = 0;
563	SMB_INO_T inode = 0;
564        DOS_ATTR_DESC *ret;
565
566        ret = TALLOC_P(ctx, DOS_ATTR_DESC);
567        if (!ret) {
568                errno = ENOMEM;
569                return NULL;
570        }
571
572        /* Obtain the DOS attributes */
573        if (!SMBC_getatr(context, srv, CONST_DISCARD(char *, filename),
574                         &mode, &size,
575                         &create_time_ts,
576                         &access_time_ts,
577                         &write_time_ts,
578                         &change_time_ts,
579                         &inode)) {
580                errno = SMBC_errno(context, srv->cli);
581                DEBUG(5, ("dos_attr_query Failed to query old attributes\n"));
582                return NULL;
583        }
584
585        ret->mode = mode;
586        ret->size = size;
587        ret->create_time = convert_timespec_to_time_t(create_time_ts);
588        ret->access_time = convert_timespec_to_time_t(access_time_ts);
589        ret->write_time = convert_timespec_to_time_t(write_time_ts);
590        ret->change_time = convert_timespec_to_time_t(change_time_ts);
591        ret->inode = inode;
592
593        return ret;
594}
595
596
597/* parse a ascii version of a security descriptor */
598static void
599dos_attr_parse(SMBCCTX *context,
600               DOS_ATTR_DESC *dad,
601               SMBCSRV *srv,
602               char *str)
603{
604        int n;
605        const char *p = str;
606	char *tok = NULL;
607	TALLOC_CTX *frame = NULL;
608        struct {
609                const char * create_time_attr;
610                const char * access_time_attr;
611                const char * write_time_attr;
612                const char * change_time_attr;
613        } attr_strings;
614
615        /* Determine whether to use old-style or new-style attribute names */
616        if (context->internal->full_time_names) {
617                /* new-style names */
618                attr_strings.create_time_attr = "CREATE_TIME";
619                attr_strings.access_time_attr = "ACCESS_TIME";
620                attr_strings.write_time_attr = "WRITE_TIME";
621                attr_strings.change_time_attr = "CHANGE_TIME";
622        } else {
623                /* old-style names */
624                attr_strings.create_time_attr = NULL;
625                attr_strings.access_time_attr = "A_TIME";
626                attr_strings.write_time_attr = "M_TIME";
627                attr_strings.change_time_attr = "C_TIME";
628        }
629
630        /* if this is to set the entire ACL... */
631        if (*str == '*') {
632                /* ... then increment past the first colon if there is one */
633                if ((p = strchr(str, ':')) != NULL) {
634                        ++p;
635                } else {
636                        p = str;
637                }
638        }
639
640	frame = talloc_stackframe();
641	while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) {
642		if (StrnCaseCmp(tok, "MODE:", 5) == 0) {
643                        long request = strtol(tok+5, NULL, 16);
644                        if (request == 0) {
645                                dad->mode = (request |
646                                             (IS_DOS_DIR(dad->mode)
647                                              ? FILE_ATTRIBUTE_DIRECTORY
648                                              : FILE_ATTRIBUTE_NORMAL));
649                        } else {
650                                dad->mode = request;
651                        }
652			continue;
653		}
654
655		if (StrnCaseCmp(tok, "SIZE:", 5) == 0) {
656                        dad->size = (SMB_OFF_T)atof(tok+5);
657			continue;
658		}
659
660                n = strlen(attr_strings.access_time_attr);
661                if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) {
662                        dad->access_time = (time_t)strtol(tok+n+1, NULL, 10);
663			continue;
664		}
665
666                n = strlen(attr_strings.change_time_attr);
667                if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) {
668                        dad->change_time = (time_t)strtol(tok+n+1, NULL, 10);
669			continue;
670		}
671
672                n = strlen(attr_strings.write_time_attr);
673                if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) {
674                        dad->write_time = (time_t)strtol(tok+n+1, NULL, 10);
675			continue;
676		}
677
678		if (attr_strings.create_time_attr != NULL) {
679			n = strlen(attr_strings.create_time_attr);
680			if (StrnCaseCmp(tok, attr_strings.create_time_attr,
681					n) == 0) {
682				dad->create_time = (time_t)strtol(tok+n+1,
683								  NULL, 10);
684				continue;
685			}
686		}
687
688		if (StrnCaseCmp(tok, "INODE:", 6) == 0) {
689                        dad->inode = (SMB_INO_T)atof(tok+6);
690			continue;
691		}
692	}
693	TALLOC_FREE(frame);
694}
695
696/*****************************************************
697 Retrieve the acls for a file.
698*******************************************************/
699
700static int
701cacl_get(SMBCCTX *context,
702         TALLOC_CTX *ctx,
703         SMBCSRV *srv,
704         struct cli_state *ipc_cli,
705         struct policy_handle *pol,
706         char *filename,
707         char *attr_name,
708         char *buf,
709         int bufsize)
710{
711	uint32 i;
712        int n = 0;
713        int n_used;
714        bool all;
715        bool all_nt;
716        bool all_nt_acls;
717        bool all_dos;
718        bool some_nt;
719        bool some_dos;
720        bool exclude_nt_revision = False;
721        bool exclude_nt_owner = False;
722        bool exclude_nt_group = False;
723        bool exclude_nt_acl = False;
724        bool exclude_dos_mode = False;
725        bool exclude_dos_size = False;
726        bool exclude_dos_create_time = False;
727        bool exclude_dos_access_time = False;
728        bool exclude_dos_write_time = False;
729        bool exclude_dos_change_time = False;
730        bool exclude_dos_inode = False;
731        bool numeric = True;
732        bool determine_size = (bufsize == 0);
733	uint16_t fnum;
734	SEC_DESC *sd;
735	fstring sidstr;
736        fstring name_sandbox;
737        char *name;
738        char *pExclude;
739        char *p;
740        struct timespec create_time_ts;
741	struct timespec write_time_ts;
742        struct timespec access_time_ts;
743        struct timespec change_time_ts;
744	time_t create_time = (time_t)0;
745	time_t write_time = (time_t)0;
746        time_t access_time = (time_t)0;
747        time_t change_time = (time_t)0;
748	SMB_OFF_T size = 0;
749	uint16 mode = 0;
750	SMB_INO_T ino = 0;
751	struct cli_state *cli = srv->cli;
752        struct {
753                const char * create_time_attr;
754                const char * access_time_attr;
755                const char * write_time_attr;
756                const char * change_time_attr;
757        } attr_strings;
758        struct {
759                const char * create_time_attr;
760                const char * access_time_attr;
761                const char * write_time_attr;
762                const char * change_time_attr;
763        } excl_attr_strings;
764
765        /* Determine whether to use old-style or new-style attribute names */
766        if (context->internal->full_time_names) {
767                /* new-style names */
768                attr_strings.create_time_attr = "CREATE_TIME";
769                attr_strings.access_time_attr = "ACCESS_TIME";
770                attr_strings.write_time_attr = "WRITE_TIME";
771                attr_strings.change_time_attr = "CHANGE_TIME";
772
773                excl_attr_strings.create_time_attr = "CREATE_TIME";
774                excl_attr_strings.access_time_attr = "ACCESS_TIME";
775                excl_attr_strings.write_time_attr = "WRITE_TIME";
776                excl_attr_strings.change_time_attr = "CHANGE_TIME";
777        } else {
778                /* old-style names */
779                attr_strings.create_time_attr = NULL;
780                attr_strings.access_time_attr = "A_TIME";
781                attr_strings.write_time_attr = "M_TIME";
782                attr_strings.change_time_attr = "C_TIME";
783
784                excl_attr_strings.create_time_attr = NULL;
785                excl_attr_strings.access_time_attr = "dos_attr.A_TIME";
786                excl_attr_strings.write_time_attr = "dos_attr.M_TIME";
787                excl_attr_strings.change_time_attr = "dos_attr.C_TIME";
788        }
789
790        /* Copy name so we can strip off exclusions (if any are specified) */
791        strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1);
792
793        /* Ensure name is null terminated */
794        name_sandbox[sizeof(name_sandbox) - 1] = '\0';
795
796        /* Play in the sandbox */
797        name = name_sandbox;
798
799        /* If there are any exclusions, point to them and mask them from name */
800        if ((pExclude = strchr(name, '!')) != NULL)
801        {
802                *pExclude++ = '\0';
803        }
804
805        all = (StrnCaseCmp(name, "system.*", 8) == 0);
806        all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0);
807        all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0);
808        all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0);
809        some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0);
810        some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0);
811        numeric = (* (name + strlen(name) - 1) != '+');
812
813        /* Look for exclusions from "all" requests */
814        if (all || all_nt || all_dos) {
815
816                /* Exclusions are delimited by '!' */
817                for (;
818                     pExclude != NULL;
819                     pExclude = (p == NULL ? NULL : p + 1)) {
820
821                        /* Find end of this exclusion name */
822                        if ((p = strchr(pExclude, '!')) != NULL)
823                        {
824                                *p = '\0';
825                        }
826
827                        /* Which exclusion name is this? */
828                        if (StrCaseCmp(pExclude,
829                                       "nt_sec_desc.revision") == 0) {
830                                exclude_nt_revision = True;
831                        }
832                        else if (StrCaseCmp(pExclude,
833                                            "nt_sec_desc.owner") == 0) {
834                                exclude_nt_owner = True;
835                        }
836                        else if (StrCaseCmp(pExclude,
837                                            "nt_sec_desc.group") == 0) {
838                                exclude_nt_group = True;
839                        }
840                        else if (StrCaseCmp(pExclude,
841                                            "nt_sec_desc.acl") == 0) {
842                                exclude_nt_acl = True;
843                        }
844                        else if (StrCaseCmp(pExclude,
845                                            "dos_attr.mode") == 0) {
846                                exclude_dos_mode = True;
847                        }
848                        else if (StrCaseCmp(pExclude,
849                                            "dos_attr.size") == 0) {
850                                exclude_dos_size = True;
851                        }
852                        else if (excl_attr_strings.create_time_attr != NULL &&
853                                 StrCaseCmp(pExclude,
854                                            excl_attr_strings.change_time_attr) == 0) {
855                                exclude_dos_create_time = True;
856                        }
857                        else if (StrCaseCmp(pExclude,
858                                            excl_attr_strings.access_time_attr) == 0) {
859                                exclude_dos_access_time = True;
860                        }
861                        else if (StrCaseCmp(pExclude,
862                                            excl_attr_strings.write_time_attr) == 0) {
863                                exclude_dos_write_time = True;
864                        }
865                        else if (StrCaseCmp(pExclude,
866                                            excl_attr_strings.change_time_attr) == 0) {
867                                exclude_dos_change_time = True;
868                        }
869                        else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) {
870                                exclude_dos_inode = True;
871                        }
872                        else {
873                                DEBUG(5, ("cacl_get received unknown exclusion: %s\n",
874                                          pExclude));
875                                errno = ENOATTR;
876                                return -1;
877                        }
878                }
879        }
880
881        n_used = 0;
882
883        /*
884         * If we are (possibly) talking to an NT or new system and some NT
885         * attributes have been requested...
886         */
887        if (ipc_cli && (all || some_nt || all_nt_acls)) {
888		char *targetpath = NULL;
889	        struct cli_state *targetcli = NULL;
890
891                /* Point to the portion after "system.nt_sec_desc." */
892                name += 19;     /* if (all) this will be invalid but unused */
893
894		if (!cli_resolve_path(ctx, "", context->internal->auth_info,
895				cli, filename,
896				&targetcli, &targetpath)) {
897			DEBUG(5, ("cacl_get Could not resolve %s\n",
898				filename));
899                        errno = ENOENT;
900                        return -1;
901		}
902
903                /* ... then obtain any NT attributes which were requested */
904                if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetpath, 0, CREATE_ACCESS_READ, 0,
905				FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
906			DEBUG(5, ("cacl_get failed to open %s: %s\n",
907				targetpath, cli_errstr(targetcli)));
908			errno = 0;
909			return -1;
910		}
911
912		sd = cli_query_secdesc(targetcli, fnum, ctx);
913
914                if (!sd) {
915                        DEBUG(5,
916                              ("cacl_get Failed to query old descriptor\n"));
917                        errno = 0;
918                        return -1;
919                }
920
921                cli_close(targetcli, fnum);
922
923                if (! exclude_nt_revision) {
924                        if (all || all_nt) {
925                                if (determine_size) {
926                                        p = talloc_asprintf(ctx,
927                                                            "REVISION:%d",
928                                                            sd->revision);
929                                        if (!p) {
930                                                errno = ENOMEM;
931                                                return -1;
932                                        }
933                                        n = strlen(p);
934                                } else {
935                                        n = snprintf(buf, bufsize,
936                                                     "REVISION:%d",
937                                                     sd->revision);
938                                }
939                        } else if (StrCaseCmp(name, "revision") == 0) {
940                                if (determine_size) {
941                                        p = talloc_asprintf(ctx, "%d",
942                                                            sd->revision);
943                                        if (!p) {
944                                                errno = ENOMEM;
945                                                return -1;
946                                        }
947                                        n = strlen(p);
948                                } else {
949                                        n = snprintf(buf, bufsize, "%d",
950                                                     sd->revision);
951                                }
952                        }
953
954                        if (!determine_size && n > bufsize) {
955                                errno = ERANGE;
956                                return -1;
957                        }
958                        buf += n;
959                        n_used += n;
960                        bufsize -= n;
961                        n = 0;
962                }
963
964                if (! exclude_nt_owner) {
965                        /* Get owner and group sid */
966                        if (sd->owner_sid) {
967                                convert_sid_to_string(ipc_cli, pol,
968                                                      sidstr,
969                                                      numeric,
970                                                      sd->owner_sid);
971                        } else {
972                                fstrcpy(sidstr, "");
973                        }
974
975                        if (all || all_nt) {
976                                if (determine_size) {
977                                        p = talloc_asprintf(ctx, ",OWNER:%s",
978                                                            sidstr);
979                                        if (!p) {
980                                                errno = ENOMEM;
981                                                return -1;
982                                        }
983                                        n = strlen(p);
984                                } else if (sidstr[0] != '\0') {
985                                        n = snprintf(buf, bufsize,
986                                                     ",OWNER:%s", sidstr);
987                                }
988                        } else if (StrnCaseCmp(name, "owner", 5) == 0) {
989                                if (determine_size) {
990                                        p = talloc_asprintf(ctx, "%s", sidstr);
991                                        if (!p) {
992                                                errno = ENOMEM;
993                                                return -1;
994                                        }
995                                        n = strlen(p);
996                                } else {
997                                        n = snprintf(buf, bufsize, "%s",
998                                                     sidstr);
999                                }
1000                        }
1001
1002                        if (!determine_size && n > bufsize) {
1003                                errno = ERANGE;
1004                                return -1;
1005                        }
1006                        buf += n;
1007                        n_used += n;
1008                        bufsize -= n;
1009                        n = 0;
1010                }
1011
1012                if (! exclude_nt_group) {
1013                        if (sd->group_sid) {
1014                                convert_sid_to_string(ipc_cli, pol,
1015                                                      sidstr, numeric,
1016                                                      sd->group_sid);
1017                        } else {
1018                                fstrcpy(sidstr, "");
1019                        }
1020
1021                        if (all || all_nt) {
1022                                if (determine_size) {
1023                                        p = talloc_asprintf(ctx, ",GROUP:%s",
1024                                                            sidstr);
1025                                        if (!p) {
1026                                                errno = ENOMEM;
1027                                                return -1;
1028                                        }
1029                                        n = strlen(p);
1030                                } else if (sidstr[0] != '\0') {
1031                                        n = snprintf(buf, bufsize,
1032                                                     ",GROUP:%s", sidstr);
1033                                }
1034                        } else if (StrnCaseCmp(name, "group", 5) == 0) {
1035                                if (determine_size) {
1036                                        p = talloc_asprintf(ctx, "%s", sidstr);
1037                                        if (!p) {
1038                                                errno = ENOMEM;
1039                                                return -1;
1040                                        }
1041                                        n = strlen(p);
1042                                } else {
1043                                        n = snprintf(buf, bufsize,
1044                                                     "%s", sidstr);
1045                                }
1046                        }
1047
1048                        if (!determine_size && n > bufsize) {
1049                                errno = ERANGE;
1050                                return -1;
1051                        }
1052                        buf += n;
1053                        n_used += n;
1054                        bufsize -= n;
1055                        n = 0;
1056                }
1057
1058                if (! exclude_nt_acl) {
1059                        /* Add aces to value buffer  */
1060                        for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1061
1062                                SEC_ACE *ace = &sd->dacl->aces[i];
1063                                convert_sid_to_string(ipc_cli, pol,
1064                                                      sidstr, numeric,
1065                                                      &ace->trustee);
1066
1067                                if (all || all_nt) {
1068                                        if (determine_size) {
1069                                                p = talloc_asprintf(
1070                                                        ctx,
1071                                                        ",ACL:"
1072                                                        "%s:%d/%d/0x%08x",
1073                                                        sidstr,
1074                                                        ace->type,
1075                                                        ace->flags,
1076                                                        ace->access_mask);
1077                                                if (!p) {
1078                                                        errno = ENOMEM;
1079                                                        return -1;
1080                                                }
1081                                                n = strlen(p);
1082                                        } else {
1083                                                n = snprintf(
1084                                                        buf, bufsize,
1085                                                        ",ACL:%s:%d/%d/0x%08x",
1086                                                        sidstr,
1087                                                        ace->type,
1088                                                        ace->flags,
1089                                                        ace->access_mask);
1090                                        }
1091                                } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
1092                                            StrCaseCmp(name+3, sidstr) == 0) ||
1093                                           (StrnCaseCmp(name, "acl+", 4) == 0 &&
1094                                            StrCaseCmp(name+4, sidstr) == 0)) {
1095                                        if (determine_size) {
1096                                                p = talloc_asprintf(
1097                                                        ctx,
1098                                                        "%d/%d/0x%08x",
1099                                                        ace->type,
1100                                                        ace->flags,
1101                                                        ace->access_mask);
1102                                                if (!p) {
1103                                                        errno = ENOMEM;
1104                                                        return -1;
1105                                                }
1106                                                n = strlen(p);
1107                                        } else {
1108                                                n = snprintf(buf, bufsize,
1109                                                             "%d/%d/0x%08x",
1110                                                             ace->type,
1111                                                             ace->flags,
1112                                                             ace->access_mask);
1113                                        }
1114                                } else if (all_nt_acls) {
1115                                        if (determine_size) {
1116                                                p = talloc_asprintf(
1117                                                        ctx,
1118                                                        "%s%s:%d/%d/0x%08x",
1119                                                        i ? "," : "",
1120                                                        sidstr,
1121                                                        ace->type,
1122                                                        ace->flags,
1123                                                        ace->access_mask);
1124                                                if (!p) {
1125                                                        errno = ENOMEM;
1126                                                        return -1;
1127                                                }
1128                                                n = strlen(p);
1129                                        } else {
1130                                                n = snprintf(buf, bufsize,
1131                                                             "%s%s:%d/%d/0x%08x",
1132                                                             i ? "," : "",
1133                                                             sidstr,
1134                                                             ace->type,
1135                                                             ace->flags,
1136                                                             ace->access_mask);
1137                                        }
1138                                }
1139                                if (!determine_size && n > bufsize) {
1140                                        errno = ERANGE;
1141                                        return -1;
1142                                }
1143                                buf += n;
1144                                n_used += n;
1145                                bufsize -= n;
1146                                n = 0;
1147                        }
1148                }
1149
1150                /* Restore name pointer to its original value */
1151                name -= 19;
1152        }
1153
1154        if (all || some_dos) {
1155                /* Point to the portion after "system.dos_attr." */
1156                name += 16;     /* if (all) this will be invalid but unused */
1157
1158                /* Obtain the DOS attributes */
1159                if (!SMBC_getatr(context, srv, filename, &mode, &size,
1160                                 &create_time_ts,
1161                                 &access_time_ts,
1162                                 &write_time_ts,
1163                                 &change_time_ts,
1164                                 &ino)) {
1165
1166                        errno = SMBC_errno(context, srv->cli);
1167                        return -1;
1168
1169                }
1170
1171                create_time = convert_timespec_to_time_t(create_time_ts);
1172                access_time = convert_timespec_to_time_t(access_time_ts);
1173                write_time = convert_timespec_to_time_t(write_time_ts);
1174                change_time = convert_timespec_to_time_t(change_time_ts);
1175
1176                if (! exclude_dos_mode) {
1177                        if (all || all_dos) {
1178                                if (determine_size) {
1179                                        p = talloc_asprintf(ctx,
1180                                                            "%sMODE:0x%x",
1181                                                            (ipc_cli &&
1182                                                             (all || some_nt)
1183                                                             ? ","
1184                                                             : ""),
1185                                                            mode);
1186                                        if (!p) {
1187                                                errno = ENOMEM;
1188                                                return -1;
1189                                        }
1190                                        n = strlen(p);
1191                                } else {
1192                                        n = snprintf(buf, bufsize,
1193                                                     "%sMODE:0x%x",
1194                                                     (ipc_cli &&
1195                                                      (all || some_nt)
1196                                                      ? ","
1197                                                      : ""),
1198                                                     mode);
1199                                }
1200                        } else if (StrCaseCmp(name, "mode") == 0) {
1201                                if (determine_size) {
1202                                        p = talloc_asprintf(ctx, "0x%x", mode);
1203                                        if (!p) {
1204                                                errno = ENOMEM;
1205                                                return -1;
1206                                        }
1207                                        n = strlen(p);
1208                                } else {
1209                                        n = snprintf(buf, bufsize,
1210                                                     "0x%x", mode);
1211                                }
1212                        }
1213
1214                        if (!determine_size && n > bufsize) {
1215                                errno = ERANGE;
1216                                return -1;
1217                        }
1218                        buf += n;
1219                        n_used += n;
1220                        bufsize -= n;
1221                        n = 0;
1222                }
1223
1224                if (! exclude_dos_size) {
1225                        if (all || all_dos) {
1226                                if (determine_size) {
1227                                        p = talloc_asprintf(
1228                                                ctx,
1229                                                ",SIZE:%.0f",
1230                                                (double)size);
1231                                        if (!p) {
1232                                                errno = ENOMEM;
1233                                                return -1;
1234                                        }
1235                                        n = strlen(p);
1236                                } else {
1237                                        n = snprintf(buf, bufsize,
1238                                                     ",SIZE:%.0f",
1239                                                     (double)size);
1240                                }
1241                        } else if (StrCaseCmp(name, "size") == 0) {
1242                                if (determine_size) {
1243                                        p = talloc_asprintf(
1244                                                ctx,
1245                                                "%.0f",
1246                                                (double)size);
1247                                        if (!p) {
1248                                                errno = ENOMEM;
1249                                                return -1;
1250                                        }
1251                                        n = strlen(p);
1252                                } else {
1253                                        n = snprintf(buf, bufsize,
1254                                                     "%.0f",
1255                                                     (double)size);
1256                                }
1257                        }
1258
1259                        if (!determine_size && n > bufsize) {
1260                                errno = ERANGE;
1261                                return -1;
1262                        }
1263                        buf += n;
1264                        n_used += n;
1265                        bufsize -= n;
1266                        n = 0;
1267                }
1268
1269                if (! exclude_dos_create_time &&
1270                    attr_strings.create_time_attr != NULL) {
1271                        if (all || all_dos) {
1272                                if (determine_size) {
1273                                        p = talloc_asprintf(ctx,
1274                                                            ",%s:%lu",
1275                                                            attr_strings.create_time_attr,
1276                                                            (unsigned long) create_time);
1277                                        if (!p) {
1278                                                errno = ENOMEM;
1279                                                return -1;
1280                                        }
1281                                        n = strlen(p);
1282                                } else {
1283                                        n = snprintf(buf, bufsize,
1284                                                     ",%s:%lu",
1285                                                     attr_strings.create_time_attr,
1286                                                     (unsigned long) create_time);
1287                                }
1288                        } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) {
1289                                if (determine_size) {
1290                                        p = talloc_asprintf(ctx, "%lu", (unsigned long) create_time);
1291                                        if (!p) {
1292                                                errno = ENOMEM;
1293                                                return -1;
1294                                        }
1295                                        n = strlen(p);
1296                                } else {
1297                                        n = snprintf(buf, bufsize,
1298                                                     "%lu", (unsigned long) create_time);
1299                                }
1300                        }
1301
1302                        if (!determine_size && n > bufsize) {
1303                                errno = ERANGE;
1304                                return -1;
1305                        }
1306                        buf += n;
1307                        n_used += n;
1308                        bufsize -= n;
1309                        n = 0;
1310                }
1311
1312                if (! exclude_dos_access_time) {
1313                        if (all || all_dos) {
1314                                if (determine_size) {
1315                                        p = talloc_asprintf(ctx,
1316                                                            ",%s:%lu",
1317                                                            attr_strings.access_time_attr,
1318                                                            (unsigned long) access_time);
1319                                        if (!p) {
1320                                                errno = ENOMEM;
1321                                                return -1;
1322                                        }
1323                                        n = strlen(p);
1324                                } else {
1325                                        n = snprintf(buf, bufsize,
1326                                                     ",%s:%lu",
1327                                                     attr_strings.access_time_attr,
1328                                                     (unsigned long) access_time);
1329                                }
1330                        } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) {
1331                                if (determine_size) {
1332                                        p = talloc_asprintf(ctx, "%lu", (unsigned long) access_time);
1333                                        if (!p) {
1334                                                errno = ENOMEM;
1335                                                return -1;
1336                                        }
1337                                        n = strlen(p);
1338                                } else {
1339                                        n = snprintf(buf, bufsize,
1340                                                     "%lu", (unsigned long) access_time);
1341                                }
1342                        }
1343
1344                        if (!determine_size && n > bufsize) {
1345                                errno = ERANGE;
1346                                return -1;
1347                        }
1348                        buf += n;
1349                        n_used += n;
1350                        bufsize -= n;
1351                        n = 0;
1352                }
1353
1354                if (! exclude_dos_write_time) {
1355                        if (all || all_dos) {
1356                                if (determine_size) {
1357                                        p = talloc_asprintf(ctx,
1358                                                            ",%s:%lu",
1359                                                            attr_strings.write_time_attr,
1360                                                            (unsigned long) write_time);
1361                                        if (!p) {
1362                                                errno = ENOMEM;
1363                                                return -1;
1364                                        }
1365                                        n = strlen(p);
1366                                } else {
1367                                        n = snprintf(buf, bufsize,
1368                                                     ",%s:%lu",
1369                                                     attr_strings.write_time_attr,
1370                                                     (unsigned long) write_time);
1371                                }
1372                        } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) {
1373                                if (determine_size) {
1374                                        p = talloc_asprintf(ctx, "%lu", (unsigned long) write_time);
1375                                        if (!p) {
1376                                                errno = ENOMEM;
1377                                                return -1;
1378                                        }
1379                                        n = strlen(p);
1380                                } else {
1381                                        n = snprintf(buf, bufsize,
1382                                                     "%lu", (unsigned long) write_time);
1383                                }
1384                        }
1385
1386                        if (!determine_size && n > bufsize) {
1387                                errno = ERANGE;
1388                                return -1;
1389                        }
1390                        buf += n;
1391                        n_used += n;
1392                        bufsize -= n;
1393                        n = 0;
1394                }
1395
1396                if (! exclude_dos_change_time) {
1397                        if (all || all_dos) {
1398                                if (determine_size) {
1399                                        p = talloc_asprintf(ctx,
1400                                                            ",%s:%lu",
1401                                                            attr_strings.change_time_attr,
1402                                                            (unsigned long) change_time);
1403                                        if (!p) {
1404                                                errno = ENOMEM;
1405                                                return -1;
1406                                        }
1407                                        n = strlen(p);
1408                                } else {
1409                                        n = snprintf(buf, bufsize,
1410                                                     ",%s:%lu",
1411                                                     attr_strings.change_time_attr,
1412                                                     (unsigned long) change_time);
1413                                }
1414                        } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
1415                                if (determine_size) {
1416                                        p = talloc_asprintf(ctx, "%lu", (unsigned long) change_time);
1417                                        if (!p) {
1418                                                errno = ENOMEM;
1419                                                return -1;
1420                                        }
1421                                        n = strlen(p);
1422                                } else {
1423                                        n = snprintf(buf, bufsize,
1424                                                     "%lu", (unsigned long) change_time);
1425                                }
1426                        }
1427
1428                        if (!determine_size && n > bufsize) {
1429                                errno = ERANGE;
1430                                return -1;
1431                        }
1432                        buf += n;
1433                        n_used += n;
1434                        bufsize -= n;
1435                        n = 0;
1436                }
1437
1438                if (! exclude_dos_inode) {
1439                        if (all || all_dos) {
1440                                if (determine_size) {
1441                                        p = talloc_asprintf(
1442                                                ctx,
1443                                                ",INODE:%.0f",
1444                                                (double)ino);
1445                                        if (!p) {
1446                                                errno = ENOMEM;
1447                                                return -1;
1448                                        }
1449                                        n = strlen(p);
1450                                } else {
1451                                        n = snprintf(buf, bufsize,
1452                                                     ",INODE:%.0f",
1453                                                     (double) ino);
1454                                }
1455                        } else if (StrCaseCmp(name, "inode") == 0) {
1456                                if (determine_size) {
1457                                        p = talloc_asprintf(
1458                                                ctx,
1459                                                "%.0f",
1460                                                (double) ino);
1461                                        if (!p) {
1462                                                errno = ENOMEM;
1463                                                return -1;
1464                                        }
1465                                        n = strlen(p);
1466                                } else {
1467                                        n = snprintf(buf, bufsize,
1468                                                     "%.0f",
1469                                                     (double) ino);
1470                                }
1471                        }
1472
1473                        if (!determine_size && n > bufsize) {
1474                                errno = ERANGE;
1475                                return -1;
1476                        }
1477                        buf += n;
1478                        n_used += n;
1479                        bufsize -= n;
1480                        n = 0;
1481                }
1482
1483                /* Restore name pointer to its original value */
1484                name -= 16;
1485        }
1486
1487        if (n_used == 0) {
1488                errno = ENOATTR;
1489                return -1;
1490        }
1491
1492	return n_used;
1493}
1494
1495/*****************************************************
1496set the ACLs on a file given an ascii description
1497*******************************************************/
1498static int
1499cacl_set(SMBCCTX *context,
1500	TALLOC_CTX *ctx,
1501	struct cli_state *cli,
1502	struct cli_state *ipc_cli,
1503	struct policy_handle *pol,
1504	const char *filename,
1505	char *the_acl,
1506	int mode,
1507	int flags)
1508{
1509	uint16_t fnum = (uint16_t)-1;
1510        int err = 0;
1511	SEC_DESC *sd = NULL, *old;
1512        SEC_ACL *dacl = NULL;
1513	DOM_SID *owner_sid = NULL;
1514	DOM_SID *group_sid = NULL;
1515	uint32 i, j;
1516	size_t sd_size;
1517	int ret = 0;
1518        char *p;
1519        bool numeric = True;
1520	char *targetpath = NULL;
1521	struct cli_state *targetcli = NULL;
1522
1523        /* the_acl will be null for REMOVE_ALL operations */
1524        if (the_acl) {
1525                numeric = ((p = strchr(the_acl, ':')) != NULL &&
1526                           p > the_acl &&
1527                           p[-1] != '+');
1528
1529                /* if this is to set the entire ACL... */
1530                if (*the_acl == '*') {
1531                        /* ... then increment past the first colon */
1532                        the_acl = p + 1;
1533                }
1534
1535                sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, the_acl);
1536
1537                if (!sd) {
1538			errno = EINVAL;
1539			return -1;
1540                }
1541        }
1542
1543	/* SMBC_XATTR_MODE_REMOVE_ALL is the only caller
1544	   that doesn't deref sd */
1545
1546	if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) {
1547		errno = EINVAL;
1548		return -1;
1549	}
1550
1551	if (!cli_resolve_path(ctx, "", context->internal->auth_info,
1552			cli, filename,
1553			&targetcli, &targetpath)) {
1554		DEBUG(5,("cacl_set: Could not resolve %s\n", filename));
1555		errno = ENOENT;
1556		return -1;
1557	}
1558
1559	/* The desired access below is the only one I could find that works
1560	   with NT4, W2KP and Samba */
1561
1562	if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetpath, 0, CREATE_ACCESS_READ, 0,
1563				FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
1564                DEBUG(5, ("cacl_set failed to open %s: %s\n",
1565                          targetpath, cli_errstr(targetcli)));
1566                errno = 0;
1567		return -1;
1568	}
1569
1570	old = cli_query_secdesc(targetcli, fnum, ctx);
1571
1572	if (!old) {
1573                DEBUG(5, ("cacl_set Failed to query old descriptor\n"));
1574                errno = 0;
1575		return -1;
1576	}
1577
1578	cli_close(targetcli, fnum);
1579
1580	switch (mode) {
1581	case SMBC_XATTR_MODE_REMOVE_ALL:
1582                old->dacl->num_aces = 0;
1583                dacl = old->dacl;
1584                break;
1585
1586        case SMBC_XATTR_MODE_REMOVE:
1587		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1588			bool found = False;
1589
1590			for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
1591                                if (sec_ace_equal(&sd->dacl->aces[i],
1592                                                  &old->dacl->aces[j])) {
1593					uint32 k;
1594					for (k=j; k<old->dacl->num_aces-1;k++) {
1595						old->dacl->aces[k] =
1596                                                        old->dacl->aces[k+1];
1597					}
1598					old->dacl->num_aces--;
1599					found = True;
1600                                        dacl = old->dacl;
1601					break;
1602				}
1603			}
1604
1605			if (!found) {
1606                                err = ENOATTR;
1607                                ret = -1;
1608                                goto failed;
1609			}
1610		}
1611		break;
1612
1613	case SMBC_XATTR_MODE_ADD:
1614		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1615			bool found = False;
1616
1617			for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
1618				if (sid_equal(&sd->dacl->aces[i].trustee,
1619					      &old->dacl->aces[j].trustee)) {
1620                                        if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
1621                                                err = EEXIST;
1622                                                ret = -1;
1623                                                goto failed;
1624                                        }
1625                                        old->dacl->aces[j] = sd->dacl->aces[i];
1626                                        ret = -1;
1627					found = True;
1628				}
1629			}
1630
1631			if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) {
1632                                err = ENOATTR;
1633                                ret = -1;
1634                                goto failed;
1635			}
1636
1637                        for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1638                                add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
1639                        }
1640		}
1641                dacl = old->dacl;
1642		break;
1643
1644	case SMBC_XATTR_MODE_SET:
1645 		old = sd;
1646                owner_sid = old->owner_sid;
1647                group_sid = old->group_sid;
1648                dacl = old->dacl;
1649		break;
1650
1651        case SMBC_XATTR_MODE_CHOWN:
1652                owner_sid = sd->owner_sid;
1653                break;
1654
1655        case SMBC_XATTR_MODE_CHGRP:
1656                group_sid = sd->group_sid;
1657                break;
1658	}
1659
1660	/* Denied ACE entries must come before allowed ones */
1661	sort_acl(old->dacl);
1662
1663	/* Create new security descriptor and set it */
1664	sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE,
1665			   owner_sid, group_sid, NULL, dacl, &sd_size);
1666
1667	if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetpath, 0,
1668                             WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS, 0,
1669			     FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
1670		DEBUG(5, ("cacl_set failed to open %s: %s\n",
1671                          targetpath, cli_errstr(targetcli)));
1672                errno = 0;
1673		return -1;
1674	}
1675
1676	if (!cli_set_secdesc(targetcli, fnum, sd)) {
1677		DEBUG(5, ("ERROR: secdesc set failed: %s\n",
1678			cli_errstr(targetcli)));
1679		ret = -1;
1680	}
1681
1682	/* Clean up */
1683
1684failed:
1685	cli_close(targetcli, fnum);
1686
1687        if (err != 0) {
1688                errno = err;
1689        }
1690
1691	return ret;
1692}
1693
1694
1695int
1696SMBC_setxattr_ctx(SMBCCTX *context,
1697                  const char *fname,
1698                  const char *name,
1699                  const void *value,
1700                  size_t size,
1701                  int flags)
1702{
1703        int ret;
1704        int ret2;
1705        SMBCSRV *srv = NULL;
1706        SMBCSRV *ipc_srv = NULL;
1707	char *server = NULL;
1708	char *share = NULL;
1709	char *user = NULL;
1710	char *password = NULL;
1711	char *workgroup = NULL;
1712	char *path = NULL;
1713        DOS_ATTR_DESC *dad = NULL;
1714        struct {
1715                const char * create_time_attr;
1716                const char * access_time_attr;
1717                const char * write_time_attr;
1718                const char * change_time_attr;
1719        } attr_strings;
1720        TALLOC_CTX *frame = talloc_stackframe();
1721
1722	if (!context || !context->internal->initialized) {
1723
1724		errno = EINVAL;  /* Best I can think of ... */
1725		TALLOC_FREE(frame);
1726		return -1;
1727	}
1728
1729	if (!fname) {
1730		errno = EINVAL;
1731		TALLOC_FREE(frame);
1732		return -1;
1733	}
1734
1735	DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n",
1736                  fname, name, (int) size, (const char*)value));
1737
1738	if (SMBC_parse_path(frame,
1739                            context,
1740                            fname,
1741                            &workgroup,
1742                            &server,
1743                            &share,
1744                            &path,
1745                            &user,
1746                            &password,
1747                            NULL)) {
1748		errno = EINVAL;
1749		TALLOC_FREE(frame);
1750		return -1;
1751        }
1752
1753	if (!user || user[0] == (char)0) {
1754		user = talloc_strdup(frame, smbc_getUser(context));
1755		if (!user) {
1756			errno = ENOMEM;
1757			TALLOC_FREE(frame);
1758			return -1;
1759		}
1760	}
1761
1762	srv = SMBC_server(frame, context, True,
1763                          server, share, &workgroup, &user, &password);
1764	if (!srv) {
1765		TALLOC_FREE(frame);
1766		return -1;  /* errno set by SMBC_server */
1767	}
1768
1769        if (! srv->no_nt_session) {
1770                ipc_srv = SMBC_attr_server(frame, context, server, share,
1771                                           &workgroup, &user, &password);
1772                if (! ipc_srv) {
1773                        srv->no_nt_session = True;
1774                }
1775        } else {
1776                ipc_srv = NULL;
1777        }
1778
1779        /*
1780         * Are they asking to set the entire set of known attributes?
1781         */
1782        if (StrCaseCmp(name, "system.*") == 0 ||
1783            StrCaseCmp(name, "system.*+") == 0) {
1784                /* Yup. */
1785                char *namevalue =
1786                        talloc_asprintf(talloc_tos(), "%s:%s",
1787                                        name+7, (const char *) value);
1788                if (! namevalue) {
1789                        errno = ENOMEM;
1790                        ret = -1;
1791			TALLOC_FREE(frame);
1792                        return -1;
1793                }
1794
1795                if (ipc_srv) {
1796                        ret = cacl_set(context, talloc_tos(), srv->cli,
1797                                       ipc_srv->cli, &ipc_srv->pol, path,
1798                                       namevalue,
1799                                       (*namevalue == '*'
1800                                        ? SMBC_XATTR_MODE_SET
1801                                        : SMBC_XATTR_MODE_ADD),
1802                                       flags);
1803                } else {
1804                        ret = 0;
1805                }
1806
1807                /* get a DOS Attribute Descriptor with current attributes */
1808                dad = dos_attr_query(context, talloc_tos(), path, srv);
1809                if (dad) {
1810                        /* Overwrite old with new, using what was provided */
1811                        dos_attr_parse(context, dad, srv, namevalue);
1812
1813                        /* Set the new DOS attributes */
1814                        if (! SMBC_setatr(context, srv, path,
1815                                          dad->create_time,
1816                                          dad->access_time,
1817                                          dad->write_time,
1818                                          dad->change_time,
1819                                          dad->mode)) {
1820
1821                                /* cause failure if NT failed too */
1822                                dad = NULL;
1823                        }
1824                }
1825
1826                /* we only fail if both NT and DOS sets failed */
1827                if (ret < 0 && ! dad) {
1828                        ret = -1; /* in case dad was null */
1829                }
1830                else {
1831                        ret = 0;
1832                }
1833
1834		TALLOC_FREE(frame);
1835                return ret;
1836        }
1837
1838        /*
1839         * Are they asking to set an access control element or to set
1840         * the entire access control list?
1841         */
1842        if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
1843            StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
1844            StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
1845            StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
1846            StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
1847
1848                /* Yup. */
1849                char *namevalue =
1850                        talloc_asprintf(talloc_tos(), "%s:%s",
1851                                        name+19, (const char *) value);
1852
1853                if (! ipc_srv) {
1854                        ret = -1; /* errno set by SMBC_server() */
1855                }
1856                else if (! namevalue) {
1857                        errno = ENOMEM;
1858                        ret = -1;
1859                } else {
1860                        ret = cacl_set(context, talloc_tos(), srv->cli,
1861                                       ipc_srv->cli, &ipc_srv->pol, path,
1862                                       namevalue,
1863                                       (*namevalue == '*'
1864                                        ? SMBC_XATTR_MODE_SET
1865                                        : SMBC_XATTR_MODE_ADD),
1866                                       flags);
1867                }
1868		TALLOC_FREE(frame);
1869                return ret;
1870        }
1871
1872        /*
1873         * Are they asking to set the owner?
1874         */
1875        if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
1876            StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) {
1877
1878                /* Yup. */
1879                char *namevalue =
1880                        talloc_asprintf(talloc_tos(), "%s:%s",
1881                                        name+19, (const char *) value);
1882
1883                if (! ipc_srv) {
1884                        ret = -1; /* errno set by SMBC_server() */
1885                }
1886                else if (! namevalue) {
1887                        errno = ENOMEM;
1888                        ret = -1;
1889                } else {
1890                        ret = cacl_set(context, talloc_tos(), srv->cli,
1891                                       ipc_srv->cli, &ipc_srv->pol, path,
1892                                       namevalue, SMBC_XATTR_MODE_CHOWN, 0);
1893                }
1894		TALLOC_FREE(frame);
1895                return ret;
1896        }
1897
1898        /*
1899         * Are they asking to set the group?
1900         */
1901        if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
1902            StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) {
1903
1904                /* Yup. */
1905                char *namevalue =
1906                        talloc_asprintf(talloc_tos(), "%s:%s",
1907                                        name+19, (const char *) value);
1908
1909                if (! ipc_srv) {
1910                        /* errno set by SMBC_server() */
1911                        ret = -1;
1912                }
1913                else if (! namevalue) {
1914                        errno = ENOMEM;
1915                        ret = -1;
1916                } else {
1917                        ret = cacl_set(context, talloc_tos(), srv->cli,
1918                                       ipc_srv->cli, &ipc_srv->pol, path,
1919                                       namevalue, SMBC_XATTR_MODE_CHGRP, 0);
1920                }
1921		TALLOC_FREE(frame);
1922                return ret;
1923        }
1924
1925        /* Determine whether to use old-style or new-style attribute names */
1926        if (context->internal->full_time_names) {
1927                /* new-style names */
1928                attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
1929                attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
1930                attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
1931                attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
1932        } else {
1933                /* old-style names */
1934                attr_strings.create_time_attr = NULL;
1935                attr_strings.access_time_attr = "system.dos_attr.A_TIME";
1936                attr_strings.write_time_attr = "system.dos_attr.M_TIME";
1937                attr_strings.change_time_attr = "system.dos_attr.C_TIME";
1938        }
1939
1940        /*
1941         * Are they asking to set a DOS attribute?
1942         */
1943        if (StrCaseCmp(name, "system.dos_attr.*") == 0 ||
1944            StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
1945            (attr_strings.create_time_attr != NULL &&
1946             StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
1947            StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
1948            StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
1949            StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
1950
1951                /* get a DOS Attribute Descriptor with current attributes */
1952                dad = dos_attr_query(context, talloc_tos(), path, srv);
1953                if (dad) {
1954                        char *namevalue =
1955                                talloc_asprintf(talloc_tos(), "%s:%s",
1956                                                name+16, (const char *) value);
1957                        if (! namevalue) {
1958                                errno = ENOMEM;
1959                                ret = -1;
1960                        } else {
1961                                /* Overwrite old with provided new params */
1962                                dos_attr_parse(context, dad, srv, namevalue);
1963
1964                                /* Set the new DOS attributes */
1965                                ret2 = SMBC_setatr(context, srv, path,
1966                                                   dad->create_time,
1967                                                   dad->access_time,
1968                                                   dad->write_time,
1969                                                   dad->change_time,
1970                                                   dad->mode);
1971
1972                                /* ret2 has True (success) / False (failure) */
1973                                if (ret2) {
1974                                        ret = 0;
1975                                } else {
1976                                        ret = -1;
1977                                }
1978                        }
1979                } else {
1980                        ret = -1;
1981                }
1982
1983		TALLOC_FREE(frame);
1984                return ret;
1985        }
1986
1987        /* Unsupported attribute name */
1988        errno = EINVAL;
1989	TALLOC_FREE(frame);
1990        return -1;
1991}
1992
1993int
1994SMBC_getxattr_ctx(SMBCCTX *context,
1995                  const char *fname,
1996                  const char *name,
1997                  const void *value,
1998                  size_t size)
1999{
2000        int ret;
2001        SMBCSRV *srv = NULL;
2002        SMBCSRV *ipc_srv = NULL;
2003	char *server = NULL;
2004	char *share = NULL;
2005	char *user = NULL;
2006	char *password = NULL;
2007	char *workgroup = NULL;
2008	char *path = NULL;
2009        struct {
2010                const char * create_time_attr;
2011                const char * access_time_attr;
2012                const char * write_time_attr;
2013                const char * change_time_attr;
2014        } attr_strings;
2015	TALLOC_CTX *frame = talloc_stackframe();
2016
2017	if (!context || !context->internal->initialized) {
2018
2019                errno = EINVAL;  /* Best I can think of ... */
2020		TALLOC_FREE(frame);
2021                return -1;
2022        }
2023
2024        if (!fname) {
2025                errno = EINVAL;
2026		TALLOC_FREE(frame);
2027                return -1;
2028        }
2029
2030        DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name));
2031
2032        if (SMBC_parse_path(frame,
2033                            context,
2034                            fname,
2035                            &workgroup,
2036                            &server,
2037                            &share,
2038                            &path,
2039                            &user,
2040                            &password,
2041                            NULL)) {
2042		errno = EINVAL;
2043		TALLOC_FREE(frame);
2044		return -1;
2045        }
2046
2047        if (!user || user[0] == (char)0) {
2048		user = talloc_strdup(frame, smbc_getUser(context));
2049		if (!user) {
2050			errno = ENOMEM;
2051			TALLOC_FREE(frame);
2052			return -1;
2053		}
2054	}
2055
2056        srv = SMBC_server(frame, context, True,
2057                          server, share, &workgroup, &user, &password);
2058        if (!srv) {
2059		TALLOC_FREE(frame);
2060                return -1;  /* errno set by SMBC_server */
2061        }
2062
2063        if (! srv->no_nt_session) {
2064                ipc_srv = SMBC_attr_server(frame, context, server, share,
2065                                           &workgroup, &user, &password);
2066                if (! ipc_srv) {
2067                        srv->no_nt_session = True;
2068                }
2069        } else {
2070                ipc_srv = NULL;
2071        }
2072
2073        /* Determine whether to use old-style or new-style attribute names */
2074        if (context->internal->full_time_names) {
2075                /* new-style names */
2076                attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
2077                attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
2078                attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
2079                attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
2080        } else {
2081                /* old-style names */
2082                attr_strings.create_time_attr = NULL;
2083                attr_strings.access_time_attr = "system.dos_attr.A_TIME";
2084                attr_strings.write_time_attr = "system.dos_attr.M_TIME";
2085                attr_strings.change_time_attr = "system.dos_attr.C_TIME";
2086        }
2087
2088        /* Are they requesting a supported attribute? */
2089        if (StrCaseCmp(name, "system.*") == 0 ||
2090            StrnCaseCmp(name, "system.*!", 9) == 0 ||
2091            StrCaseCmp(name, "system.*+") == 0 ||
2092            StrnCaseCmp(name, "system.*+!", 10) == 0 ||
2093            StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
2094            StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 ||
2095            StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
2096            StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 ||
2097            StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
2098            StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
2099            StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
2100            StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
2101            StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
2102            StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
2103            StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 ||
2104            StrCaseCmp(name, "system.dos_attr.*") == 0 ||
2105            StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 ||
2106            StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
2107            StrCaseCmp(name, "system.dos_attr.size") == 0 ||
2108            (attr_strings.create_time_attr != NULL &&
2109             StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
2110            StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
2111            StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
2112            StrCaseCmp(name, attr_strings.change_time_attr) == 0 ||
2113            StrCaseCmp(name, "system.dos_attr.inode") == 0) {
2114
2115                /* Yup. */
2116                char *filename = (char *) name;
2117                ret = cacl_get(context, talloc_tos(), srv,
2118                               ipc_srv == NULL ? NULL : ipc_srv->cli,
2119                               &ipc_srv->pol, path,
2120                               filename,
2121                               CONST_DISCARD(char *, value),
2122                               size);
2123                if (ret < 0 && errno == 0) {
2124                        errno = SMBC_errno(context, srv->cli);
2125                }
2126		TALLOC_FREE(frame);
2127                return ret;
2128        }
2129
2130        /* Unsupported attribute name */
2131        errno = EINVAL;
2132	TALLOC_FREE(frame);
2133        return -1;
2134}
2135
2136
2137int
2138SMBC_removexattr_ctx(SMBCCTX *context,
2139                     const char *fname,
2140                     const char *name)
2141{
2142        int ret;
2143        SMBCSRV *srv = NULL;
2144        SMBCSRV *ipc_srv = NULL;
2145	char *server = NULL;
2146	char *share = NULL;
2147	char *user = NULL;
2148	char *password = NULL;
2149	char *workgroup = NULL;
2150	char *path = NULL;
2151	TALLOC_CTX *frame = talloc_stackframe();
2152
2153	if (!context || !context->internal->initialized) {
2154
2155                errno = EINVAL;  /* Best I can think of ... */
2156		TALLOC_FREE(frame);
2157                return -1;
2158        }
2159
2160        if (!fname) {
2161                errno = EINVAL;
2162		TALLOC_FREE(frame);
2163                return -1;
2164        }
2165
2166        DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name));
2167
2168	if (SMBC_parse_path(frame,
2169                            context,
2170                            fname,
2171                            &workgroup,
2172                            &server,
2173                            &share,
2174                            &path,
2175                            &user,
2176                            &password,
2177                            NULL)) {
2178		errno = EINVAL;
2179		TALLOC_FREE(frame);
2180		return -1;
2181        }
2182
2183        if (!user || user[0] == (char)0) {
2184		user = talloc_strdup(frame, smbc_getUser(context));
2185		if (!user) {
2186			errno = ENOMEM;
2187			TALLOC_FREE(frame);
2188			return -1;
2189		}
2190	}
2191
2192        srv = SMBC_server(frame, context, True,
2193                          server, share, &workgroup, &user, &password);
2194        if (!srv) {
2195		TALLOC_FREE(frame);
2196                return -1;  /* errno set by SMBC_server */
2197        }
2198
2199        if (! srv->no_nt_session) {
2200                ipc_srv = SMBC_attr_server(frame, context, server, share,
2201                                           &workgroup, &user, &password);
2202                if (! ipc_srv) {
2203                        srv->no_nt_session = True;
2204                }
2205        } else {
2206                ipc_srv = NULL;
2207        }
2208
2209        if (! ipc_srv) {
2210		TALLOC_FREE(frame);
2211                return -1; /* errno set by SMBC_attr_server */
2212        }
2213
2214        /* Are they asking to set the entire ACL? */
2215        if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
2216            StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) {
2217
2218                /* Yup. */
2219                ret = cacl_set(context, talloc_tos(), srv->cli,
2220                               ipc_srv->cli, &ipc_srv->pol, path,
2221                               NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
2222		TALLOC_FREE(frame);
2223                return ret;
2224        }
2225
2226        /*
2227         * Are they asking to remove one or more spceific security descriptor
2228         * attributes?
2229         */
2230        if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
2231            StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
2232            StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
2233            StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
2234            StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
2235            StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
2236            StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
2237
2238                /* Yup. */
2239                ret = cacl_set(context, talloc_tos(), srv->cli,
2240                               ipc_srv->cli, &ipc_srv->pol, path,
2241                               CONST_DISCARD(char *, name) + 19,
2242                               SMBC_XATTR_MODE_REMOVE, 0);
2243		TALLOC_FREE(frame);
2244                return ret;
2245        }
2246
2247        /* Unsupported attribute name */
2248        errno = EINVAL;
2249	TALLOC_FREE(frame);
2250        return -1;
2251}
2252
2253int
2254SMBC_listxattr_ctx(SMBCCTX *context,
2255                   const char *fname,
2256                   char *list,
2257                   size_t size)
2258{
2259        /*
2260         * This isn't quite what listxattr() is supposed to do.  This returns
2261         * the complete set of attribute names, always, rather than only those
2262         * attribute names which actually exist for a file.  Hmmm...
2263         */
2264        size_t retsize;
2265        const char supported_old[] =
2266                "system.*\0"
2267                "system.*+\0"
2268                "system.nt_sec_desc.revision\0"
2269                "system.nt_sec_desc.owner\0"
2270                "system.nt_sec_desc.owner+\0"
2271                "system.nt_sec_desc.group\0"
2272                "system.nt_sec_desc.group+\0"
2273                "system.nt_sec_desc.acl.*\0"
2274                "system.nt_sec_desc.acl\0"
2275                "system.nt_sec_desc.acl+\0"
2276                "system.nt_sec_desc.*\0"
2277                "system.nt_sec_desc.*+\0"
2278                "system.dos_attr.*\0"
2279                "system.dos_attr.mode\0"
2280                "system.dos_attr.c_time\0"
2281                "system.dos_attr.a_time\0"
2282                "system.dos_attr.m_time\0"
2283                ;
2284        const char supported_new[] =
2285                "system.*\0"
2286                "system.*+\0"
2287                "system.nt_sec_desc.revision\0"
2288                "system.nt_sec_desc.owner\0"
2289                "system.nt_sec_desc.owner+\0"
2290                "system.nt_sec_desc.group\0"
2291                "system.nt_sec_desc.group+\0"
2292                "system.nt_sec_desc.acl.*\0"
2293                "system.nt_sec_desc.acl\0"
2294                "system.nt_sec_desc.acl+\0"
2295                "system.nt_sec_desc.*\0"
2296                "system.nt_sec_desc.*+\0"
2297                "system.dos_attr.*\0"
2298                "system.dos_attr.mode\0"
2299                "system.dos_attr.create_time\0"
2300                "system.dos_attr.access_time\0"
2301                "system.dos_attr.write_time\0"
2302                "system.dos_attr.change_time\0"
2303                ;
2304        const char * supported;
2305
2306        if (context->internal->full_time_names) {
2307                supported = supported_new;
2308                retsize = sizeof(supported_new);
2309        } else {
2310                supported = supported_old;
2311                retsize = sizeof(supported_old);
2312        }
2313
2314        if (size == 0) {
2315                return retsize;
2316        }
2317
2318        if (retsize > size) {
2319                errno = ERANGE;
2320                return -1;
2321        }
2322
2323        /* this can't be strcpy() because there are embedded null characters */
2324        memcpy(list, supported, retsize);
2325        return retsize;
2326}
2327