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