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