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
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.
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.
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/>.
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 #include "lib/util/string_wrappers.h"
36 * Find an lsa pipe handle associated with a cli struct.
38 static struct rpc_pipe_client *
39 find_lsa_pipe_hnd(struct cli_state *ipc_cli)
41 struct rpc_pipe_client *pipe_hnd;
43 for (pipe_hnd = ipc_cli->pipe_list;
45 pipe_hnd = pipe_hnd->next) {
46 if (ndr_syntax_id_equal(&pipe_hnd->abstract_syntax,
47 &ndr_table_lsarpc.syntax_id)) {
55 * Sort ACEs according to the documentation at
56 * http://support.microsoft.com/kb/269175, at least as far as it defines the
61 ace_compare(struct security_ace *ace1,
62 struct security_ace *ace2)
67 /* If the ACEs are equal, we have nothing more to do. */
68 if (security_ace_equal(ace1, ace2)) {
72 /* Inherited follow non-inherited */
73 b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
74 b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
80 * What shall we do with AUDITs and ALARMs? It's undefined. We'll
81 * sort them after DENY and ALLOW.
83 b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
84 ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
85 ace1->type != SEC_ACE_TYPE_ACCESS_DENIED &&
86 ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
87 b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
88 ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
89 ace2->type != SEC_ACE_TYPE_ACCESS_DENIED &&
90 ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
95 /* Allowed ACEs follow denied ACEs */
96 b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
97 ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
98 b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
99 ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
101 return (b1 ? 1 : -1);
105 * ACEs applying to an entity's object follow those applying to the
108 b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
109 ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
110 b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
111 ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
113 return (b1 ? 1 : -1);
117 * If we get this far, the ACEs are similar as far as the
118 * characteristics we typically care about (those defined by the
119 * referenced MS document). We'll now sort by characteristics that
120 * just seems reasonable.
123 if (ace1->type != ace2->type) {
124 return ace2->type - ace1->type;
127 if (dom_sid_compare(&ace1->trustee, &ace2->trustee)) {
128 return dom_sid_compare(&ace1->trustee, &ace2->trustee);
131 if (ace1->flags != ace2->flags) {
132 return ace1->flags - ace2->flags;
135 if (ace1->access_mask != ace2->access_mask) {
136 return ace1->access_mask - ace2->access_mask;
139 if (ace1->size != ace2->size) {
140 return ace1->size - ace2->size;
143 return memcmp(ace1, ace2, sizeof(struct security_ace));
148 sort_acl(struct security_acl *the_acl)
151 if (!the_acl) return;
153 TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces, ace_compare);
155 for (i=1;i<the_acl->num_aces;) {
156 if (security_ace_equal(&the_acl->aces[i-1],
157 &the_acl->aces[i])) {
159 the_acl->aces, i, the_acl->num_aces);
167 /* convert a SID to a string, either numeric or username/group */
169 convert_sid_to_string(struct cli_state *ipc_cli,
170 struct policy_handle *pol,
175 char **domains = NULL;
177 enum lsa_SidType *types = NULL;
178 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
181 sid_to_fstring(str, sid);
184 return; /* no lookup desired */
191 /* Ask LSA to convert the sid to a name */
193 ctx = talloc_stackframe();
195 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx,
196 pol, 1, sid, &domains,
198 !domains || !domains[0] || !names || !names[0]) {
205 fstr_sprintf(str, "%s%s%s",
206 domains[0], lp_winbind_separator(), names[0]);
211 /* convert a string to a SID, either numeric or username/group */
213 convert_string_to_sid(struct cli_state *ipc_cli,
214 struct policy_handle *pol,
219 enum lsa_SidType *types = NULL;
220 struct dom_sid *sids = NULL;
222 TALLOC_CTX *ctx = NULL;
223 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
230 if (strncmp(str, "S-", 2) == 0) {
231 return string_to_sid(sid, str);
238 ctx = talloc_stackframe();
239 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx,
247 sid_copy(sid, &sids[0]);
254 /* parse an struct security_ace in the same format as print_ace() */
256 parse_ace(struct cli_state *ipc_cli,
257 struct policy_handle *pol,
258 struct security_ace *ace,
275 TALLOC_CTX *frame = talloc_stackframe();
277 /* These values discovered by inspection */
278 static const struct perm_value special_values[] = {
287 static const struct perm_value standard_values[] = {
288 { "READ", 0x001200a9 },
289 { "CHANGE", 0x001301bf },
290 { "FULL", 0x001f01ff },
294 p = strchr_m(str,':');
301 /* Try to parse numeric form */
303 if (sscanf(p, "%u/%u/%u", &atype, &aflags, &amask) == 3 &&
304 convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
308 /* Try to parse text form */
310 if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
316 if (!next_token_talloc(frame, &cp, &tok, "/")) {
321 if (strncasecmp_m(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
322 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
323 } else if (strncasecmp_m(tok, "DENIED", strlen("DENIED")) == 0) {
324 atype = SEC_ACE_TYPE_ACCESS_DENIED;
330 /* Only numeric form accepted for flags at present */
332 if (!(next_token_talloc(frame, &cp, &tok, "/") &&
333 sscanf(tok, "%u", &aflags))) {
338 if (!next_token_talloc(frame, &cp, &tok, "/")) {
343 if (strncmp(tok, "0x", 2) == 0) {
344 if (sscanf(tok, "%u", &amask) != 1) {
351 for (i = 0; i < ARRAY_SIZE(standard_values); i++) {
352 const struct perm_value *v = &standard_values[i];
353 if (strcmp(tok, v->perm) == 0) {
364 for (i = 0; i < ARRAY_SIZE(special_values); i++) {
365 const struct perm_value *v = &special_values[i];
366 if (v->perm[0] == *p) {
386 init_sec_ace(ace, &sid, atype, mask, aflags);
391 /* add an struct security_ace to a list of struct security_aces in a struct security_acl */
393 add_ace(struct security_acl **the_acl,
394 const struct security_ace *ace,
397 struct security_acl *acl = *the_acl;
400 acl = make_sec_acl(ctx, 3, 0, NULL);
406 if (acl->num_aces == UINT32_MAX) {
410 acl, struct security_ace, *ace, &acl->aces, &acl->num_aces);
416 /* parse a ascii version of a security descriptor */
417 static struct security_descriptor *
418 sec_desc_parse(TALLOC_CTX *ctx,
419 struct cli_state *ipc_cli,
420 struct policy_handle *pol,
426 struct security_descriptor *ret = NULL;
428 struct dom_sid owner_sid = { .num_auths = 0 };
429 struct dom_sid group_sid = { .num_auths = 0 };
430 bool have_owner = false, have_group = false;
431 struct security_acl *dacl=NULL;
434 while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
436 if (strncasecmp_m(tok,"REVISION:", 9) == 0) {
437 revision = strtol(tok+9, NULL, 16);
441 if (strncasecmp_m(tok,"OWNER:", 6) == 0) {
443 DEBUG(5,("OWNER specified more than once!\n"));
446 if (!convert_string_to_sid(ipc_cli, pol,
448 &owner_sid, tok+6)) {
449 DEBUG(5, ("Failed to parse owner sid\n"));
456 if (strncasecmp_m(tok,"OWNER+:", 7) == 0) {
458 DEBUG(5,("OWNER specified more than once!\n"));
461 if (!convert_string_to_sid(ipc_cli, pol,
463 &owner_sid, tok+7)) {
464 DEBUG(5, ("Failed to parse owner sid\n"));
471 if (strncasecmp_m(tok,"GROUP:", 6) == 0) {
473 DEBUG(5,("GROUP specified more than once!\n"));
476 if (!convert_string_to_sid(ipc_cli, pol,
478 &group_sid, tok+6)) {
479 DEBUG(5, ("Failed to parse group sid\n"));
486 if (strncasecmp_m(tok,"GROUP+:", 7) == 0) {
488 DEBUG(5,("GROUP specified more than once!\n"));
491 if (!convert_string_to_sid(ipc_cli, pol,
493 &group_sid, tok+6)) {
494 DEBUG(5, ("Failed to parse group sid\n"));
501 if (strncasecmp_m(tok,"ACL:", 4) == 0) {
502 struct security_ace ace;
503 if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) {
504 DEBUG(5, ("Failed to parse ACL %s\n", tok));
507 if(!add_ace(&dacl, &ace, ctx)) {
508 DEBUG(5, ("Failed to add ACL %s\n", tok));
514 if (strncasecmp_m(tok,"ACL+:", 5) == 0) {
515 struct security_ace ace;
516 if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) {
517 DEBUG(5, ("Failed to parse ACL %s\n", tok));
520 if(!add_ace(&dacl, &ace, ctx)) {
521 DEBUG(5, ("Failed to add ACL %s\n", tok));
527 DEBUG(5, ("Failed to parse security descriptor\n"));
534 SEC_DESC_SELF_RELATIVE,
535 have_owner ? &owner_sid : NULL,
536 have_group ? &group_sid : NULL,
546 /* Obtain the current dos attributes */
547 static struct DOS_ATTR_DESC *
548 dos_attr_query(SMBCCTX *context,
550 const char *filename,
553 struct stat sb = {0};
554 struct DOS_ATTR_DESC *ret = NULL;
557 ret = talloc(ctx, struct DOS_ATTR_DESC);
563 /* Obtain the DOS attributes */
564 status = SMBC_getatr(context, srv, filename, &sb);
565 if (!NT_STATUS_IS_OK(status)) {
566 DEBUG(5, ("dos_attr_query Failed to query old attributes\n"));
568 errno = cli_status_to_errno(status);
572 ret->mode = sb.st_mode;
573 ret->size = sb.st_size;
574 ret->create_time = sb.st_ctime;
575 ret->access_time = sb.st_atime;
576 ret->write_time = sb.st_mtime;
577 ret->change_time = sb.st_mtime;
578 ret->inode = sb.st_ino;
584 /* parse a ascii version of a security descriptor */
586 dos_attr_parse(SMBCCTX *context,
587 struct DOS_ATTR_DESC *dad,
594 TALLOC_CTX *frame = NULL;
596 const char * create_time_attr;
597 const char * access_time_attr;
598 const char * write_time_attr;
599 const char * change_time_attr;
602 /* Determine whether to use old-style or new-style attribute names */
603 if (context->internal->full_time_names) {
604 /* new-style names */
605 attr_strings.create_time_attr = "CREATE_TIME";
606 attr_strings.access_time_attr = "ACCESS_TIME";
607 attr_strings.write_time_attr = "WRITE_TIME";
608 attr_strings.change_time_attr = "CHANGE_TIME";
610 /* old-style names */
611 attr_strings.create_time_attr = NULL;
612 attr_strings.access_time_attr = "A_TIME";
613 attr_strings.write_time_attr = "M_TIME";
614 attr_strings.change_time_attr = "C_TIME";
617 /* if this is to set the entire ACL... */
619 /* ... then increment past the first colon if there is one */
620 if ((p = strchr(str, ':')) != NULL) {
627 frame = talloc_stackframe();
628 while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) {
629 if (strncasecmp_m(tok, "MODE:", 5) == 0) {
630 long request = strtol(tok+5, NULL, 16);
633 (dad->mode & FILE_ATTRIBUTE_DIRECTORY)
634 ? FILE_ATTRIBUTE_DIRECTORY
635 : FILE_ATTRIBUTE_NORMAL;
642 if (strncasecmp_m(tok, "SIZE:", 5) == 0) {
643 dad->size = (off_t)atof(tok+5);
647 n = strlen(attr_strings.access_time_attr);
648 if (strncasecmp_m(tok, attr_strings.access_time_attr, n) == 0) {
649 dad->access_time = (time_t)strtol(tok+n+1, NULL, 10);
653 n = strlen(attr_strings.change_time_attr);
654 if (strncasecmp_m(tok, attr_strings.change_time_attr, n) == 0) {
655 dad->change_time = (time_t)strtol(tok+n+1, NULL, 10);
659 n = strlen(attr_strings.write_time_attr);
660 if (strncasecmp_m(tok, attr_strings.write_time_attr, n) == 0) {
661 dad->write_time = (time_t)strtol(tok+n+1, NULL, 10);
665 if (attr_strings.create_time_attr != NULL) {
666 n = strlen(attr_strings.create_time_attr);
667 if (strncasecmp_m(tok, attr_strings.create_time_attr,
669 dad->create_time = (time_t)strtol(tok+n+1,
675 if (strncasecmp_m(tok, "INODE:", 6) == 0) {
676 dad->inode = (SMB_INO_T)atof(tok+6);
683 /*****************************************************
684 Retrieve the acls for a file.
685 *******************************************************/
688 cacl_get(SMBCCTX *context,
691 struct cli_state *ipc_cli,
692 struct policy_handle *pol,
693 const char *filename,
694 const char *attr_name,
707 bool exclude_nt_revision = False;
708 bool exclude_nt_owner = False;
709 bool exclude_nt_group = False;
710 bool exclude_nt_acl = False;
711 bool exclude_dos_mode = False;
712 bool exclude_dos_size = False;
713 bool exclude_dos_create_time = False;
714 bool exclude_dos_access_time = False;
715 bool exclude_dos_write_time = False;
716 bool exclude_dos_change_time = False;
717 bool exclude_dos_inode = False;
719 bool determine_size = (bufsize == 0);
721 struct security_descriptor *sd;
723 fstring name_sandbox;
727 struct cli_state *cli = srv->cli;
729 const char * create_time_attr;
730 const char * access_time_attr;
731 const char * write_time_attr;
732 const char * change_time_attr;
735 const char * create_time_attr;
736 const char * access_time_attr;
737 const char * write_time_attr;
738 const char * change_time_attr;
741 /* Determine whether to use old-style or new-style attribute names */
742 if (context->internal->full_time_names) {
743 /* new-style names */
744 attr_strings.create_time_attr = "CREATE_TIME";
745 attr_strings.access_time_attr = "ACCESS_TIME";
746 attr_strings.write_time_attr = "WRITE_TIME";
747 attr_strings.change_time_attr = "CHANGE_TIME";
749 excl_attr_strings.create_time_attr = "CREATE_TIME";
750 excl_attr_strings.access_time_attr = "ACCESS_TIME";
751 excl_attr_strings.write_time_attr = "WRITE_TIME";
752 excl_attr_strings.change_time_attr = "CHANGE_TIME";
754 /* old-style names */
755 attr_strings.create_time_attr = NULL;
756 attr_strings.access_time_attr = "A_TIME";
757 attr_strings.write_time_attr = "M_TIME";
758 attr_strings.change_time_attr = "C_TIME";
760 excl_attr_strings.create_time_attr = NULL;
761 excl_attr_strings.access_time_attr = "dos_attr.A_TIME";
762 excl_attr_strings.write_time_attr = "dos_attr.M_TIME";
763 excl_attr_strings.change_time_attr = "dos_attr.C_TIME";
766 /* Copy name so we can strip off exclusions (if any are specified) */
767 fstrcpy(name_sandbox, attr_name);
769 /* Ensure name is null terminated */
770 name_sandbox[sizeof(name_sandbox) - 1] = '\0';
772 /* Play in the sandbox */
775 /* If there are any exclusions, point to them and mask them from name */
776 if ((pExclude = strchr(name, '!')) != NULL)
781 all = (strncasecmp_m(name, "system.*", 8) == 0);
782 all_nt = (strncasecmp_m(name, "system.nt_sec_desc.*", 20) == 0);
783 all_nt_acls = (strncasecmp_m(name, "system.nt_sec_desc.acl.*", 24) == 0);
784 all_dos = (strncasecmp_m(name, "system.dos_attr.*", 17) == 0);
785 some_nt = (strncasecmp_m(name, "system.nt_sec_desc.", 19) == 0);
786 some_dos = (strncasecmp_m(name, "system.dos_attr.", 16) == 0);
787 numeric = (* (name + strlen(name) - 1) != '+');
789 /* Look for exclusions from "all" requests */
790 if (all || all_nt || all_dos) {
791 /* Exclusions are delimited by '!' */
794 pExclude = (p == NULL ? NULL : p + 1)) {
796 /* Find end of this exclusion name */
797 if ((p = strchr(pExclude, '!')) != NULL)
802 /* Which exclusion name is this? */
803 if (strcasecmp_m(pExclude,
804 "nt_sec_desc.revision") == 0) {
805 exclude_nt_revision = True;
807 else if (strcasecmp_m(pExclude,
808 "nt_sec_desc.owner") == 0) {
809 exclude_nt_owner = True;
811 else if (strcasecmp_m(pExclude,
812 "nt_sec_desc.group") == 0) {
813 exclude_nt_group = True;
815 else if (strcasecmp_m(pExclude,
816 "nt_sec_desc.acl") == 0) {
817 exclude_nt_acl = True;
819 else if (strcasecmp_m(pExclude,
820 "dos_attr.mode") == 0) {
821 exclude_dos_mode = True;
823 else if (strcasecmp_m(pExclude,
824 "dos_attr.size") == 0) {
825 exclude_dos_size = True;
827 else if (excl_attr_strings.create_time_attr != NULL &&
828 strcasecmp_m(pExclude,
829 excl_attr_strings.change_time_attr) == 0) {
830 exclude_dos_create_time = True;
832 else if (strcasecmp_m(pExclude,
833 excl_attr_strings.access_time_attr) == 0) {
834 exclude_dos_access_time = True;
836 else if (strcasecmp_m(pExclude,
837 excl_attr_strings.write_time_attr) == 0) {
838 exclude_dos_write_time = True;
840 else if (strcasecmp_m(pExclude,
841 excl_attr_strings.change_time_attr) == 0) {
842 exclude_dos_change_time = True;
844 else if (strcasecmp_m(pExclude, "dos_attr.inode") == 0) {
845 exclude_dos_inode = True;
848 DEBUG(5, ("cacl_get received unknown exclusion: %s\n",
859 * If we are (possibly) talking to an NT or new system and some NT
860 * attributes have been requested...
862 if (ipc_cli && (all || some_nt || all_nt_acls)) {
863 char *targetpath = NULL;
864 struct cli_state *targetcli = NULL;
865 struct cli_credentials *creds = NULL;
868 /* Point to the portion after "system.nt_sec_desc." */
869 name += 19; /* if (all) this will be invalid but unused */
871 creds = context->internal->creds;
873 status = cli_resolve_path(
876 cli, filename, &targetcli, &targetpath);
877 if (!NT_STATUS_IS_OK(status)) {
878 DEBUG(5, ("cacl_get Could not resolve %s\n",
884 /* ... then obtain any NT attributes which were requested */
885 status = cli_ntcreate(
887 targetpath, /* fname */
889 READ_CONTROL_ACCESS, /* DesiredAccess */
890 0, /* FileAttributes */
892 FILE_SHARE_WRITE, /* ShareAccess */
893 FILE_OPEN, /* CreateDisposition */
894 0x0, /* CreateOptions */
895 0x0, /* SecurityFlags */
898 if (!NT_STATUS_IS_OK(status)) {
899 DEBUG(5, ("cacl_get failed to open %s: %s\n",
900 targetpath, nt_errstr(status)));
901 errno = cli_status_to_errno(status);
905 status = cli_query_secdesc(targetcli, fnum, ctx, &sd);
906 if (!NT_STATUS_IS_OK(status)) {
907 DEBUG(5,("cacl_get Failed to query old descriptor "
909 targetpath, nt_errstr(status)));
910 errno = cli_status_to_errno(status);
914 cli_close(targetcli, fnum);
916 if (! exclude_nt_revision) {
918 if (determine_size) {
919 p = talloc_asprintf(ctx,
928 n = snprintf(buf, bufsize,
932 } else if (strcasecmp_m(name, "revision") == 0) {
933 if (determine_size) {
934 p = talloc_asprintf(ctx, "%d",
942 n = snprintf(buf, bufsize, "%d",
947 if (!determine_size && n > bufsize) {
957 if (! exclude_nt_owner) {
958 /* Get owner and group sid */
960 convert_sid_to_string(ipc_cli, pol,
969 if (determine_size) {
970 p = talloc_asprintf(ctx, ",OWNER:%s",
977 } else if (sidstr[0] != '\0') {
978 n = snprintf(buf, bufsize,
979 ",OWNER:%s", sidstr);
981 } else if (strncasecmp_m(name, "owner", 5) == 0) {
982 if (determine_size) {
983 p = talloc_asprintf(ctx, "%s", sidstr);
990 n = snprintf(buf, bufsize, "%s",
995 if (!determine_size && n > bufsize) {
1005 if (! exclude_nt_group) {
1006 if (sd->group_sid) {
1007 convert_sid_to_string(ipc_cli, pol,
1011 fstrcpy(sidstr, "");
1014 if (all || all_nt) {
1015 if (determine_size) {
1016 p = talloc_asprintf(ctx, ",GROUP:%s",
1023 } else if (sidstr[0] != '\0') {
1024 n = snprintf(buf, bufsize,
1025 ",GROUP:%s", sidstr);
1027 } else if (strncasecmp_m(name, "group", 5) == 0) {
1028 if (determine_size) {
1029 p = talloc_asprintf(ctx, "%s", sidstr);
1036 n = snprintf(buf, bufsize,
1041 if (!determine_size && n > bufsize) {
1051 if (! exclude_nt_acl) {
1052 /* Add aces to value buffer */
1053 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1055 struct security_ace *ace = &sd->dacl->aces[i];
1056 convert_sid_to_string(ipc_cli, pol,
1060 if (all || all_nt) {
1061 if (determine_size) {
1062 p = talloc_asprintf(
1078 ",ACL:%s:%d/%d/0x%08x",
1084 } else if ((strncasecmp_m(name, "acl", 3) == 0 &&
1085 strcasecmp_m(name+3, sidstr) == 0) ||
1086 (strncasecmp_m(name, "acl+", 4) == 0 &&
1087 strcasecmp_m(name+4, sidstr) == 0)) {
1088 if (determine_size) {
1089 p = talloc_asprintf(
1101 n = snprintf(buf, bufsize,
1107 } else if (all_nt_acls) {
1108 if (determine_size) {
1109 p = talloc_asprintf(
1111 "%s%s:%d/%d/0x%08x",
1123 n = snprintf(buf, bufsize,
1124 "%s%s:%d/%d/0x%08x",
1132 if (!determine_size && n > bufsize) {
1143 /* Restore name pointer to its original value */
1147 if (all || some_dos) {
1148 struct stat sb = {0};
1149 time_t create_time = (time_t)0;
1150 time_t write_time = (time_t)0;
1151 time_t access_time = (time_t)0;
1152 time_t change_time = (time_t)0;
1158 /* Point to the portion after "system.dos_attr." */
1159 name += 16; /* if (all) this will be invalid but unused */
1161 /* Obtain the DOS attributes */
1162 status = SMBC_getatr(context, srv, filename, &sb);
1163 if (!NT_STATUS_IS_OK(status)) {
1164 errno = cli_status_to_errno(status);
1168 create_time = sb.st_ctime;
1169 access_time = sb.st_atime;
1170 write_time = sb.st_mtime;
1171 change_time = sb.st_mtime;
1176 if (! exclude_dos_mode) {
1177 if (all || all_dos) {
1178 if (determine_size) {
1179 p = talloc_asprintf(ctx,
1192 n = snprintf(buf, bufsize,
1200 } else if (strcasecmp_m(name, "mode") == 0) {
1201 if (determine_size) {
1202 p = talloc_asprintf(ctx, "0x%x", mode);
1209 n = snprintf(buf, bufsize,
1214 if (!determine_size && n > bufsize) {
1224 if (! exclude_dos_size) {
1225 if (all || all_dos) {
1226 if (determine_size) {
1227 p = talloc_asprintf(
1237 n = snprintf(buf, bufsize,
1241 } else if (strcasecmp_m(name, "size") == 0) {
1242 if (determine_size) {
1243 p = talloc_asprintf(
1253 n = snprintf(buf, bufsize,
1259 if (!determine_size && n > bufsize) {
1269 if (! exclude_dos_create_time &&
1270 attr_strings.create_time_attr != NULL) {
1271 if (all || all_dos) {
1272 if (determine_size) {
1273 p = talloc_asprintf(ctx,
1275 attr_strings.create_time_attr,
1276 (unsigned long) create_time);
1283 n = snprintf(buf, bufsize,
1285 attr_strings.create_time_attr,
1286 (unsigned long) create_time);
1288 } else if (strcasecmp_m(name, attr_strings.create_time_attr) == 0) {
1289 if (determine_size) {
1290 p = talloc_asprintf(ctx, "%lu", (unsigned long) create_time);
1297 n = snprintf(buf, bufsize,
1298 "%lu", (unsigned long) create_time);
1302 if (!determine_size && n > bufsize) {
1312 if (! exclude_dos_access_time) {
1313 if (all || all_dos) {
1314 if (determine_size) {
1315 p = talloc_asprintf(ctx,
1317 attr_strings.access_time_attr,
1318 (unsigned long) access_time);
1325 n = snprintf(buf, bufsize,
1327 attr_strings.access_time_attr,
1328 (unsigned long) access_time);
1330 } else if (strcasecmp_m(name, attr_strings.access_time_attr) == 0) {
1331 if (determine_size) {
1332 p = talloc_asprintf(ctx, "%lu", (unsigned long) access_time);
1339 n = snprintf(buf, bufsize,
1340 "%lu", (unsigned long) access_time);
1344 if (!determine_size && n > bufsize) {
1354 if (! exclude_dos_write_time) {
1355 if (all || all_dos) {
1356 if (determine_size) {
1357 p = talloc_asprintf(ctx,
1359 attr_strings.write_time_attr,
1360 (unsigned long) write_time);
1367 n = snprintf(buf, bufsize,
1369 attr_strings.write_time_attr,
1370 (unsigned long) write_time);
1372 } else if (strcasecmp_m(name, attr_strings.write_time_attr) == 0) {
1373 if (determine_size) {
1374 p = talloc_asprintf(ctx, "%lu", (unsigned long) write_time);
1381 n = snprintf(buf, bufsize,
1382 "%lu", (unsigned long) write_time);
1386 if (!determine_size && n > bufsize) {
1396 if (! exclude_dos_change_time) {
1397 if (all || all_dos) {
1398 if (determine_size) {
1399 p = talloc_asprintf(ctx,
1401 attr_strings.change_time_attr,
1402 (unsigned long) change_time);
1409 n = snprintf(buf, bufsize,
1411 attr_strings.change_time_attr,
1412 (unsigned long) change_time);
1414 } else if (strcasecmp_m(name, attr_strings.change_time_attr) == 0) {
1415 if (determine_size) {
1416 p = talloc_asprintf(ctx, "%lu", (unsigned long) change_time);
1423 n = snprintf(buf, bufsize,
1424 "%lu", (unsigned long) change_time);
1428 if (!determine_size && n > bufsize) {
1438 if (! exclude_dos_inode) {
1439 if (all || all_dos) {
1440 if (determine_size) {
1441 p = talloc_asprintf(
1451 n = snprintf(buf, bufsize,
1455 } else if (strcasecmp_m(name, "inode") == 0) {
1456 if (determine_size) {
1457 p = talloc_asprintf(
1467 n = snprintf(buf, bufsize,
1473 if (!determine_size && n > bufsize) {
1483 /* Restore name pointer to its original value */
1495 /*****************************************************
1496 set the ACLs on a file given an ascii description
1497 *******************************************************/
1499 cacl_set(SMBCCTX *context,
1501 struct cli_state *cli,
1502 struct cli_state *ipc_cli,
1503 struct policy_handle *pol,
1504 const char *filename,
1509 uint16_t fnum = (uint16_t)-1;
1511 struct security_descriptor *sd = NULL, *old;
1512 struct security_acl *dacl = NULL;
1513 struct dom_sid *owner_sid = NULL;
1514 struct dom_sid *group_sid = NULL;
1519 bool numeric = True;
1520 char *targetpath = NULL;
1521 struct cli_state *targetcli = NULL;
1522 struct cli_credentials *creds = NULL;
1525 /* the_acl will be null for REMOVE_ALL operations */
1527 numeric = ((p = strchr(the_acl, ':')) != NULL &&
1531 /* if this is to set the entire ACL... */
1532 if (*the_acl == '*') {
1533 /* ... then increment past the first colon */
1537 sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, the_acl);
1544 /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller
1545 that doesn't deref sd */
1547 if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) {
1552 creds = context->internal->creds;
1554 status = cli_resolve_path(ctx, "",
1556 cli, filename, &targetcli, &targetpath);
1557 if (!NT_STATUS_IS_OK(status)) {
1558 DEBUG(5,("cacl_set: Could not resolve %s\n", filename));
1563 /* The desired access below is the only one I could find that works
1564 with NT4, W2KP and Samba */
1566 status = cli_ntcreate(
1567 targetcli, /* cli */
1568 targetpath, /* fname */
1570 READ_CONTROL_ACCESS, /* DesiredAccess */
1571 0, /* FileAttributes */
1573 FILE_SHARE_WRITE, /* ShareAccess */
1574 FILE_OPEN, /* CreateDisposition */
1575 0x0, /* CreateOptions */
1576 0x0, /* SecurityFlags */
1579 if (!NT_STATUS_IS_OK(status)) {
1580 DEBUG(5, ("cacl_set failed to open %s: %s\n",
1581 targetpath, nt_errstr(status)));
1586 status = cli_query_secdesc(targetcli, fnum, ctx, &old);
1587 if (!NT_STATUS_IS_OK(status)) {
1588 DEBUG(5,("cacl_set Failed to query old descriptor of %s: %s\n",
1589 targetpath, nt_errstr(status)));
1594 cli_close(targetcli, fnum);
1597 case SMBC_XATTR_MODE_REMOVE_ALL:
1598 old->dacl->num_aces = 0;
1602 case SMBC_XATTR_MODE_REMOVE:
1603 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1606 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
1607 if (security_ace_equal(&sd->dacl->aces[i],
1608 &old->dacl->aces[j])) {
1610 for (k=j; k<old->dacl->num_aces-1;k++) {
1611 old->dacl->aces[k] =
1612 old->dacl->aces[k+1];
1614 old->dacl->num_aces--;
1629 case SMBC_XATTR_MODE_ADD:
1630 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1633 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
1634 if (dom_sid_equal(&sd->dacl->aces[i].trustee,
1635 &old->dacl->aces[j].trustee)) {
1636 if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
1641 old->dacl->aces[j] = sd->dacl->aces[i];
1647 if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) {
1653 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1654 add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
1660 case SMBC_XATTR_MODE_SET:
1662 owner_sid = old->owner_sid;
1663 group_sid = old->group_sid;
1667 case SMBC_XATTR_MODE_CHOWN:
1668 owner_sid = sd->owner_sid;
1671 case SMBC_XATTR_MODE_CHGRP:
1672 group_sid = sd->group_sid;
1676 /* Denied ACE entries must come before allowed ones */
1677 sort_acl(old->dacl);
1679 /* Create new security descriptor and set it */
1680 sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE,
1681 owner_sid, group_sid, NULL, dacl, &sd_size);
1683 status = cli_ntcreate(targetcli, targetpath, 0,
1684 WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS, 0,
1685 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
1686 0x0, 0x0, &fnum, NULL);
1687 if (!NT_STATUS_IS_OK(status)) {
1688 DEBUG(5, ("cacl_set failed to open %s: %s\n",
1689 targetpath, nt_errstr(status)));
1694 status = cli_set_secdesc(targetcli, fnum, sd);
1695 if (!NT_STATUS_IS_OK(status)) {
1696 DEBUG(5, ("ERROR: secdesc set failed: %s\n",
1697 nt_errstr(status)));
1704 cli_close(targetcli, fnum);
1715 SMBC_setxattr_ctx(SMBCCTX *context,
1724 SMBCSRV *srv = NULL;
1725 SMBCSRV *ipc_srv = NULL;
1726 char *server = NULL;
1729 char *password = NULL;
1730 char *workgroup = NULL;
1732 struct DOS_ATTR_DESC *dad = NULL;
1734 const char * create_time_attr;
1735 const char * access_time_attr;
1736 const char * write_time_attr;
1737 const char * change_time_attr;
1740 TALLOC_CTX *frame = talloc_stackframe();
1742 if (!context || !context->internal->initialized) {
1743 errno = EINVAL; /* Best I can think of ... */
1754 DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n",
1755 fname, name, (int) size, (const char*)value));
1757 if (SMBC_parse_path(frame,
1773 if (!user || user[0] == (char)0) {
1774 user = talloc_strdup(frame, smbc_getUser(context));
1782 srv = SMBC_server(frame, context, True,
1783 server, port, share, &workgroup, &user, &password);
1786 return -1; /* errno set by SMBC_server */
1789 if (! srv->no_nt_session) {
1790 ipc_srv = SMBC_attr_server(frame, context, server, port, share,
1791 &workgroup, &user, &password);
1793 srv->no_nt_session = True;
1800 * Are they asking to set the entire set of known attributes?
1802 if (strcasecmp_m(name, "system.*") == 0 ||
1803 strcasecmp_m(name, "system.*+") == 0) {
1806 talloc_asprintf(talloc_tos(), "%s:%s",
1807 name+7, (const char *) value);
1816 ret = cacl_set(context, talloc_tos(), srv->cli,
1817 ipc_srv->cli, &ipc_srv->pol, path,
1820 ? SMBC_XATTR_MODE_SET
1821 : SMBC_XATTR_MODE_ADD),
1827 /* get a DOS Attribute Descriptor with current attributes */
1828 dad = dos_attr_query(context, talloc_tos(), path, srv);
1832 /* Overwrite old with new, using what was provided */
1833 dos_attr_parse(context, dad, srv, namevalue);
1835 /* Set the new DOS attributes */
1841 .tv_sec = dad->create_time },
1843 .tv_sec = dad->access_time },
1845 .tv_sec = dad->write_time },
1847 .tv_sec = dad->change_time },
1850 /* cause failure if NT failed too */
1855 /* we only fail if both NT and DOS sets failed */
1856 if (ret < 0 && ! dad) {
1857 ret = -1; /* in case dad was null */
1868 * Are they asking to set an access control element or to set
1869 * the entire access control list?
1871 if (strcasecmp_m(name, "system.nt_sec_desc.*") == 0 ||
1872 strcasecmp_m(name, "system.nt_sec_desc.*+") == 0 ||
1873 strcasecmp_m(name, "system.nt_sec_desc.revision") == 0 ||
1874 strncasecmp_m(name, "system.nt_sec_desc.acl", 22) == 0 ||
1875 strncasecmp_m(name, "system.nt_sec_desc.acl+", 23) == 0) {
1879 talloc_asprintf(talloc_tos(), "%s:%s",
1880 name+19, (const char *) value);
1883 ret = -1; /* errno set by SMBC_server() */
1885 else if (! namevalue) {
1889 ret = cacl_set(context, talloc_tos(), srv->cli,
1890 ipc_srv->cli, &ipc_srv->pol, path,
1893 ? SMBC_XATTR_MODE_SET
1894 : SMBC_XATTR_MODE_ADD),
1902 * Are they asking to set the owner?
1904 if (strcasecmp_m(name, "system.nt_sec_desc.owner") == 0 ||
1905 strcasecmp_m(name, "system.nt_sec_desc.owner+") == 0) {
1909 talloc_asprintf(talloc_tos(), "%s:%s",
1910 name+19, (const char *) value);
1913 ret = -1; /* errno set by SMBC_server() */
1915 else if (! namevalue) {
1919 ret = cacl_set(context, talloc_tos(), srv->cli,
1920 ipc_srv->cli, &ipc_srv->pol, path,
1921 namevalue, SMBC_XATTR_MODE_CHOWN, 0);
1928 * Are they asking to set the group?
1930 if (strcasecmp_m(name, "system.nt_sec_desc.group") == 0 ||
1931 strcasecmp_m(name, "system.nt_sec_desc.group+") == 0) {
1935 talloc_asprintf(talloc_tos(), "%s:%s",
1936 name+19, (const char *) value);
1939 /* errno set by SMBC_server() */
1942 else if (! namevalue) {
1946 ret = cacl_set(context, talloc_tos(), srv->cli,
1947 ipc_srv->cli, &ipc_srv->pol, path,
1948 namevalue, SMBC_XATTR_MODE_CHGRP, 0);
1954 /* Determine whether to use old-style or new-style attribute names */
1955 if (context->internal->full_time_names) {
1956 /* new-style names */
1957 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
1958 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
1959 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
1960 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
1962 /* old-style names */
1963 attr_strings.create_time_attr = NULL;
1964 attr_strings.access_time_attr = "system.dos_attr.A_TIME";
1965 attr_strings.write_time_attr = "system.dos_attr.M_TIME";
1966 attr_strings.change_time_attr = "system.dos_attr.C_TIME";
1970 * Are they asking to set a DOS attribute?
1972 if (strcasecmp_m(name, "system.dos_attr.*") == 0 ||
1973 strcasecmp_m(name, "system.dos_attr.mode") == 0 ||
1974 (attr_strings.create_time_attr != NULL &&
1975 strcasecmp_m(name, attr_strings.create_time_attr) == 0) ||
1976 strcasecmp_m(name, attr_strings.access_time_attr) == 0 ||
1977 strcasecmp_m(name, attr_strings.write_time_attr) == 0 ||
1978 strcasecmp_m(name, attr_strings.change_time_attr) == 0) {
1980 /* get a DOS Attribute Descriptor with current attributes */
1981 dad = dos_attr_query(context, talloc_tos(), path, srv);
1984 talloc_asprintf(talloc_tos(), "%s:%s",
1985 name+16, (const char *) value);
1990 /* Overwrite old with provided new params */
1991 dos_attr_parse(context, dad, srv, namevalue);
1993 /* Set the new DOS attributes */
1999 .tv_sec = dad->create_time },
2001 .tv_sec = dad->access_time },
2003 .tv_sec = dad->write_time },
2005 .tv_sec = dad->change_time },
2008 /* ret2 has True (success) / False (failure) */
2023 /* Unsupported attribute name */
2030 SMBC_getxattr_ctx(SMBCCTX *context,
2037 SMBCSRV *srv = NULL;
2038 SMBCSRV *ipc_srv = NULL;
2039 char *server = NULL;
2042 char *password = NULL;
2043 char *workgroup = NULL;
2046 const char * create_time_attr;
2047 const char * access_time_attr;
2048 const char * write_time_attr;
2049 const char * change_time_attr;
2052 TALLOC_CTX *frame = talloc_stackframe();
2054 if (!context || !context->internal->initialized) {
2055 errno = EINVAL; /* Best I can think of ... */
2066 DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name));
2068 if (SMBC_parse_path(frame,
2084 if (!user || user[0] == '\0') {
2085 user = talloc_strdup(frame, smbc_getUser(context));
2093 srv = SMBC_server(frame, context, True,
2094 server, port, share, &workgroup, &user, &password);
2097 return -1; /* errno set by SMBC_server */
2100 if (! srv->no_nt_session) {
2101 ipc_srv = SMBC_attr_server(frame, context, server, port, share,
2102 &workgroup, &user, &password);
2104 * SMBC_attr_server() can cause the original
2105 * server to be removed from the cache.
2106 * If so we must error out here as the srv
2107 * pointer has been freed.
2109 if (smbc_getFunctionGetCachedServer(context)(context,
2114 #if defined(ECONNRESET)
2123 srv->no_nt_session = True;
2129 /* Determine whether to use old-style or new-style attribute names */
2130 if (context->internal->full_time_names) {
2131 /* new-style names */
2132 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
2133 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
2134 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
2135 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
2137 /* old-style names */
2138 attr_strings.create_time_attr = NULL;
2139 attr_strings.access_time_attr = "system.dos_attr.A_TIME";
2140 attr_strings.write_time_attr = "system.dos_attr.M_TIME";
2141 attr_strings.change_time_attr = "system.dos_attr.C_TIME";
2144 /* Are they requesting a supported attribute? */
2145 if (strcasecmp_m(name, "system.*") == 0 ||
2146 strncasecmp_m(name, "system.*!", 9) == 0 ||
2147 strcasecmp_m(name, "system.*+") == 0 ||
2148 strncasecmp_m(name, "system.*+!", 10) == 0 ||
2149 strcasecmp_m(name, "system.nt_sec_desc.*") == 0 ||
2150 strncasecmp_m(name, "system.nt_sec_desc.*!", 21) == 0 ||
2151 strcasecmp_m(name, "system.nt_sec_desc.*+") == 0 ||
2152 strncasecmp_m(name, "system.nt_sec_desc.*+!", 22) == 0 ||
2153 strcasecmp_m(name, "system.nt_sec_desc.revision") == 0 ||
2154 strcasecmp_m(name, "system.nt_sec_desc.owner") == 0 ||
2155 strcasecmp_m(name, "system.nt_sec_desc.owner+") == 0 ||
2156 strcasecmp_m(name, "system.nt_sec_desc.group") == 0 ||
2157 strcasecmp_m(name, "system.nt_sec_desc.group+") == 0 ||
2158 strncasecmp_m(name, "system.nt_sec_desc.acl", 22) == 0 ||
2159 strncasecmp_m(name, "system.nt_sec_desc.acl+", 23) == 0 ||
2160 strcasecmp_m(name, "system.dos_attr.*") == 0 ||
2161 strncasecmp_m(name, "system.dos_attr.*!", 18) == 0 ||
2162 strcasecmp_m(name, "system.dos_attr.mode") == 0 ||
2163 strcasecmp_m(name, "system.dos_attr.size") == 0 ||
2164 (attr_strings.create_time_attr != NULL &&
2165 strcasecmp_m(name, attr_strings.create_time_attr) == 0) ||
2166 strcasecmp_m(name, attr_strings.access_time_attr) == 0 ||
2167 strcasecmp_m(name, attr_strings.write_time_attr) == 0 ||
2168 strcasecmp_m(name, attr_strings.change_time_attr) == 0 ||
2169 strcasecmp_m(name, "system.dos_attr.inode") == 0) {
2172 const char *filename = name;
2173 ret = cacl_get(context, talloc_tos(), srv,
2174 ipc_srv == NULL ? NULL : ipc_srv->cli,
2175 &ipc_srv->pol, path,
2177 discard_const_p(char, value),
2181 * static function cacl_get returns a value greater than zero
2182 * which is needed buffer size needed when size_t is 0.
2187 /* Unsupported attribute name */
2195 SMBC_removexattr_ctx(SMBCCTX *context,
2200 SMBCSRV *srv = NULL;
2201 SMBCSRV *ipc_srv = NULL;
2202 char *server = NULL;
2205 char *password = NULL;
2206 char *workgroup = NULL;
2209 TALLOC_CTX *frame = talloc_stackframe();
2211 if (!context || !context->internal->initialized) {
2212 errno = EINVAL; /* Best I can think of ... */
2223 DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name));
2225 if (SMBC_parse_path(frame,
2241 if (!user || user[0] == (char)0) {
2242 user = talloc_strdup(frame, smbc_getUser(context));
2250 srv = SMBC_server(frame, context, True,
2251 server, port, share, &workgroup, &user, &password);
2254 return -1; /* errno set by SMBC_server */
2257 if (! srv->no_nt_session) {
2259 ipc_srv = SMBC_attr_server(frame, context, server, port, share,
2260 &workgroup, &user, &password);
2261 saved_errno = errno;
2263 * SMBC_attr_server() can cause the original
2264 * server to be removed from the cache.
2265 * If so we must error out here as the srv
2266 * pointer has been freed.
2268 if (smbc_getFunctionGetCachedServer(context)(context,
2273 #if defined(ECONNRESET)
2282 errno = saved_errno;
2283 srv->no_nt_session = True;
2291 return -1; /* errno set by SMBC_attr_server */
2294 /* Are they asking to set the entire ACL? */
2295 if (strcasecmp_m(name, "system.nt_sec_desc.*") == 0 ||
2296 strcasecmp_m(name, "system.nt_sec_desc.*+") == 0) {
2299 ret = cacl_set(context, talloc_tos(), srv->cli,
2300 ipc_srv->cli, &ipc_srv->pol, path,
2301 NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
2307 * Are they asking to remove one or more specific security descriptor
2310 if (strcasecmp_m(name, "system.nt_sec_desc.revision") == 0 ||
2311 strcasecmp_m(name, "system.nt_sec_desc.owner") == 0 ||
2312 strcasecmp_m(name, "system.nt_sec_desc.owner+") == 0 ||
2313 strcasecmp_m(name, "system.nt_sec_desc.group") == 0 ||
2314 strcasecmp_m(name, "system.nt_sec_desc.group+") == 0 ||
2315 strncasecmp_m(name, "system.nt_sec_desc.acl", 22) == 0 ||
2316 strncasecmp_m(name, "system.nt_sec_desc.acl+", 23) == 0) {
2319 ret = cacl_set(context, talloc_tos(), srv->cli,
2320 ipc_srv->cli, &ipc_srv->pol, path,
2321 discard_const_p(char, name) + 19,
2322 SMBC_XATTR_MODE_REMOVE, 0);
2327 /* Unsupported attribute name */
2334 SMBC_listxattr_ctx(SMBCCTX *context,
2340 * This isn't quite what listxattr() is supposed to do. This returns
2341 * the complete set of attribute names, always, rather than only those
2342 * attribute names which actually exist for a file. Hmmm...
2345 static const char supported_old[] =
2348 "system.nt_sec_desc.revision\0"
2349 "system.nt_sec_desc.owner\0"
2350 "system.nt_sec_desc.owner+\0"
2351 "system.nt_sec_desc.group\0"
2352 "system.nt_sec_desc.group+\0"
2353 "system.nt_sec_desc.acl.*\0"
2354 "system.nt_sec_desc.acl\0"
2355 "system.nt_sec_desc.acl+\0"
2356 "system.nt_sec_desc.*\0"
2357 "system.nt_sec_desc.*+\0"
2358 "system.dos_attr.*\0"
2359 "system.dos_attr.mode\0"
2360 "system.dos_attr.c_time\0"
2361 "system.dos_attr.a_time\0"
2362 "system.dos_attr.m_time\0"
2364 static const char supported_new[] =
2367 "system.nt_sec_desc.revision\0"
2368 "system.nt_sec_desc.owner\0"
2369 "system.nt_sec_desc.owner+\0"
2370 "system.nt_sec_desc.group\0"
2371 "system.nt_sec_desc.group+\0"
2372 "system.nt_sec_desc.acl.*\0"
2373 "system.nt_sec_desc.acl\0"
2374 "system.nt_sec_desc.acl+\0"
2375 "system.nt_sec_desc.*\0"
2376 "system.nt_sec_desc.*+\0"
2377 "system.dos_attr.*\0"
2378 "system.dos_attr.mode\0"
2379 "system.dos_attr.create_time\0"
2380 "system.dos_attr.access_time\0"
2381 "system.dos_attr.write_time\0"
2382 "system.dos_attr.change_time\0"
2384 const char * supported;
2386 if (context->internal->full_time_names) {
2387 supported = supported_new;
2388 retsize = sizeof(supported_new);
2390 supported = supported_old;
2391 retsize = sizeof(supported_old);
2398 if (retsize > size) {
2403 /* this can't be strcpy() because there are embedded null characters */
2404 memcpy(list, supported, retsize);