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