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) {
125 * ace2 and ace1 are reversed here, so that
126 * ACCESS_DENIED_ACE_TYPE (1) sorts before
127 * ACCESS_ALLOWED_ACE_TYPE (0), which is the order you
130 return NUMERIC_CMP(ace2->type, ace1->type);
133 if (dom_sid_compare(&ace1->trustee, &ace2->trustee)) {
134 return dom_sid_compare(&ace1->trustee, &ace2->trustee);
137 if (ace1->flags != ace2->flags) {
138 return NUMERIC_CMP(ace1->flags, ace2->flags);
141 if (ace1->access_mask != ace2->access_mask) {
142 return NUMERIC_CMP(ace1->access_mask, ace2->access_mask);
145 if (ace1->size != ace2->size) {
146 return NUMERIC_CMP(ace1->size, ace2->size);
149 return memcmp(ace1, ace2, sizeof(struct security_ace));
154 sort_acl(struct security_acl *the_acl)
157 if (!the_acl) return;
159 TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces, ace_compare);
161 for (i=1;i<the_acl->num_aces;) {
162 if (security_ace_equal(&the_acl->aces[i-1],
163 &the_acl->aces[i])) {
165 the_acl->aces, i, the_acl->num_aces);
173 /* convert a SID to a string, either numeric or username/group */
175 convert_sid_to_string(struct cli_state *ipc_cli,
176 struct policy_handle *pol,
181 char **domains = NULL;
183 enum lsa_SidType *types = NULL;
184 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
187 sid_to_fstring(str, sid);
190 return; /* no lookup desired */
197 /* Ask LSA to convert the sid to a name */
199 ctx = talloc_stackframe();
201 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx,
202 pol, 1, sid, &domains,
204 !domains || !domains[0] || !names || !names[0]) {
211 fstr_sprintf(str, "%s%s%s",
212 domains[0], lp_winbind_separator(), names[0]);
217 /* convert a string to a SID, either numeric or username/group */
219 convert_string_to_sid(struct cli_state *ipc_cli,
220 struct policy_handle *pol,
225 enum lsa_SidType *types = NULL;
226 struct dom_sid *sids = NULL;
228 TALLOC_CTX *ctx = NULL;
229 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
236 if (strncmp(str, "S-", 2) == 0) {
237 return string_to_sid(sid, str);
244 ctx = talloc_stackframe();
245 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx,
253 sid_copy(sid, &sids[0]);
260 /* parse an struct security_ace in the same format as print_ace() */
262 parse_ace(struct cli_state *ipc_cli,
263 struct policy_handle *pol,
264 struct security_ace *ace,
281 TALLOC_CTX *frame = talloc_stackframe();
283 /* These values discovered by inspection */
284 static const struct perm_value special_values[] = {
293 static const struct perm_value standard_values[] = {
294 { "READ", 0x001200a9 },
295 { "CHANGE", 0x001301bf },
296 { "FULL", 0x001f01ff },
300 p = strchr_m(str,':');
307 /* Try to parse numeric form */
309 if (sscanf(p, "%u/%u/%u", &atype, &aflags, &amask) == 3 &&
310 convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
314 /* Try to parse text form */
316 if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
322 if (!next_token_talloc(frame, &cp, &tok, "/")) {
327 if (strncasecmp_m(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
328 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
329 } else if (strncasecmp_m(tok, "DENIED", strlen("DENIED")) == 0) {
330 atype = SEC_ACE_TYPE_ACCESS_DENIED;
336 /* Only numeric form accepted for flags at present */
338 if (!(next_token_talloc(frame, &cp, &tok, "/") &&
339 sscanf(tok, "%u", &aflags))) {
344 if (!next_token_talloc(frame, &cp, &tok, "/")) {
349 if (strncmp(tok, "0x", 2) == 0) {
350 if (sscanf(tok, "%u", &amask) != 1) {
357 for (i = 0; i < ARRAY_SIZE(standard_values); i++) {
358 const struct perm_value *v = &standard_values[i];
359 if (strcmp(tok, v->perm) == 0) {
370 for (i = 0; i < ARRAY_SIZE(special_values); i++) {
371 const struct perm_value *v = &special_values[i];
372 if (v->perm[0] == *p) {
392 init_sec_ace(ace, &sid, atype, mask, aflags);
397 /* add an struct security_ace to a list of struct security_aces in a struct security_acl */
399 add_ace(struct security_acl **the_acl,
400 const struct security_ace *ace,
403 struct security_acl *acl = *the_acl;
406 acl = make_sec_acl(ctx, 3, 0, NULL);
412 if (acl->num_aces == UINT32_MAX) {
416 acl, struct security_ace, *ace, &acl->aces, &acl->num_aces);
422 /* parse a ascii version of a security descriptor */
423 static struct security_descriptor *
424 sec_desc_parse(TALLOC_CTX *ctx,
425 struct cli_state *ipc_cli,
426 struct policy_handle *pol,
432 struct security_descriptor *ret = NULL;
434 struct dom_sid owner_sid = { .num_auths = 0 };
435 struct dom_sid group_sid = { .num_auths = 0 };
436 bool have_owner = false, have_group = false;
437 struct security_acl *dacl=NULL;
440 while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
442 if (strncasecmp_m(tok,"REVISION:", 9) == 0) {
443 revision = strtol(tok+9, NULL, 16);
447 if (strncasecmp_m(tok,"OWNER:", 6) == 0) {
449 DEBUG(5,("OWNER specified more than once!\n"));
452 if (!convert_string_to_sid(ipc_cli, pol,
454 &owner_sid, tok+6)) {
455 DEBUG(5, ("Failed to parse owner sid\n"));
462 if (strncasecmp_m(tok,"OWNER+:", 7) == 0) {
464 DEBUG(5,("OWNER specified more than once!\n"));
467 if (!convert_string_to_sid(ipc_cli, pol,
469 &owner_sid, tok+7)) {
470 DEBUG(5, ("Failed to parse owner sid\n"));
477 if (strncasecmp_m(tok,"GROUP:", 6) == 0) {
479 DEBUG(5,("GROUP specified more than once!\n"));
482 if (!convert_string_to_sid(ipc_cli, pol,
484 &group_sid, tok+6)) {
485 DEBUG(5, ("Failed to parse group sid\n"));
492 if (strncasecmp_m(tok,"GROUP+:", 7) == 0) {
494 DEBUG(5,("GROUP specified more than once!\n"));
497 if (!convert_string_to_sid(ipc_cli, pol,
499 &group_sid, tok+6)) {
500 DEBUG(5, ("Failed to parse group sid\n"));
507 if (strncasecmp_m(tok,"ACL:", 4) == 0) {
508 struct security_ace ace;
509 if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) {
510 DEBUG(5, ("Failed to parse ACL %s\n", tok));
513 if(!add_ace(&dacl, &ace, ctx)) {
514 DEBUG(5, ("Failed to add ACL %s\n", tok));
520 if (strncasecmp_m(tok,"ACL+:", 5) == 0) {
521 struct security_ace ace;
522 if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) {
523 DEBUG(5, ("Failed to parse ACL %s\n", tok));
526 if(!add_ace(&dacl, &ace, ctx)) {
527 DEBUG(5, ("Failed to add ACL %s\n", tok));
533 DEBUG(5, ("Failed to parse security descriptor\n"));
540 SEC_DESC_SELF_RELATIVE,
541 have_owner ? &owner_sid : NULL,
542 have_group ? &group_sid : NULL,
552 /* Obtain the current dos attributes */
553 static struct DOS_ATTR_DESC *
554 dos_attr_query(SMBCCTX *context,
556 const char *filename,
559 struct stat sb = {0};
560 struct DOS_ATTR_DESC *ret = NULL;
563 ret = talloc(ctx, struct DOS_ATTR_DESC);
569 /* Obtain the DOS attributes */
570 status = SMBC_getatr(context, srv, filename, &sb);
571 if (!NT_STATUS_IS_OK(status)) {
572 DEBUG(5, ("dos_attr_query Failed to query old attributes\n"));
574 errno = cli_status_to_errno(status);
578 ret->mode = sb.st_mode;
579 ret->size = sb.st_size;
580 ret->create_time = sb.st_ctime;
581 ret->access_time = sb.st_atime;
582 ret->write_time = sb.st_mtime;
583 ret->change_time = sb.st_mtime;
584 ret->inode = sb.st_ino;
590 /* parse a ascii version of a security descriptor */
592 dos_attr_parse(SMBCCTX *context,
593 struct DOS_ATTR_DESC *dad,
600 TALLOC_CTX *frame = NULL;
602 const char * create_time_attr;
603 const char * access_time_attr;
604 const char * write_time_attr;
605 const char * change_time_attr;
608 /* Determine whether to use old-style or new-style attribute names */
609 if (context->internal->full_time_names) {
610 /* new-style names */
611 attr_strings.create_time_attr = "CREATE_TIME";
612 attr_strings.access_time_attr = "ACCESS_TIME";
613 attr_strings.write_time_attr = "WRITE_TIME";
614 attr_strings.change_time_attr = "CHANGE_TIME";
616 /* old-style names */
617 attr_strings.create_time_attr = NULL;
618 attr_strings.access_time_attr = "A_TIME";
619 attr_strings.write_time_attr = "M_TIME";
620 attr_strings.change_time_attr = "C_TIME";
623 /* if this is to set the entire ACL... */
625 /* ... then increment past the first colon if there is one */
626 if ((p = strchr(str, ':')) != NULL) {
633 frame = talloc_stackframe();
634 while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) {
635 if (strncasecmp_m(tok, "MODE:", 5) == 0) {
636 long request = strtol(tok+5, NULL, 16);
639 (dad->mode & FILE_ATTRIBUTE_DIRECTORY)
640 ? FILE_ATTRIBUTE_DIRECTORY
641 : FILE_ATTRIBUTE_NORMAL;
648 if (strncasecmp_m(tok, "SIZE:", 5) == 0) {
649 dad->size = (off_t)atof(tok+5);
653 n = strlen(attr_strings.access_time_attr);
654 if (strncasecmp_m(tok, attr_strings.access_time_attr, n) == 0) {
655 dad->access_time = (time_t)strtol(tok+n+1, NULL, 10);
659 n = strlen(attr_strings.change_time_attr);
660 if (strncasecmp_m(tok, attr_strings.change_time_attr, n) == 0) {
661 dad->change_time = (time_t)strtol(tok+n+1, NULL, 10);
665 n = strlen(attr_strings.write_time_attr);
666 if (strncasecmp_m(tok, attr_strings.write_time_attr, n) == 0) {
667 dad->write_time = (time_t)strtol(tok+n+1, NULL, 10);
671 if (attr_strings.create_time_attr != NULL) {
672 n = strlen(attr_strings.create_time_attr);
673 if (strncasecmp_m(tok, attr_strings.create_time_attr,
675 dad->create_time = (time_t)strtol(tok+n+1,
681 if (strncasecmp_m(tok, "INODE:", 6) == 0) {
682 dad->inode = (SMB_INO_T)atof(tok+6);
689 /*****************************************************
690 Retrieve the acls for a file.
691 *******************************************************/
694 cacl_get(SMBCCTX *context,
697 struct cli_state *ipc_cli,
698 struct policy_handle *pol,
699 const char *filename,
700 const char *attr_name,
713 bool exclude_nt_revision = False;
714 bool exclude_nt_owner = False;
715 bool exclude_nt_group = False;
716 bool exclude_nt_acl = False;
717 bool exclude_dos_mode = False;
718 bool exclude_dos_size = False;
719 bool exclude_dos_create_time = False;
720 bool exclude_dos_access_time = False;
721 bool exclude_dos_write_time = False;
722 bool exclude_dos_change_time = False;
723 bool exclude_dos_inode = False;
725 bool determine_size = (bufsize == 0);
727 struct security_descriptor *sd;
729 fstring name_sandbox;
733 struct cli_state *cli = srv->cli;
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 const char * create_time_attr;
742 const char * access_time_attr;
743 const char * write_time_attr;
744 const char * change_time_attr;
747 /* Determine whether to use old-style or new-style attribute names */
748 if (context->internal->full_time_names) {
749 /* new-style names */
750 attr_strings.create_time_attr = "CREATE_TIME";
751 attr_strings.access_time_attr = "ACCESS_TIME";
752 attr_strings.write_time_attr = "WRITE_TIME";
753 attr_strings.change_time_attr = "CHANGE_TIME";
755 excl_attr_strings.create_time_attr = "CREATE_TIME";
756 excl_attr_strings.access_time_attr = "ACCESS_TIME";
757 excl_attr_strings.write_time_attr = "WRITE_TIME";
758 excl_attr_strings.change_time_attr = "CHANGE_TIME";
760 /* old-style names */
761 attr_strings.create_time_attr = NULL;
762 attr_strings.access_time_attr = "A_TIME";
763 attr_strings.write_time_attr = "M_TIME";
764 attr_strings.change_time_attr = "C_TIME";
766 excl_attr_strings.create_time_attr = NULL;
767 excl_attr_strings.access_time_attr = "dos_attr.A_TIME";
768 excl_attr_strings.write_time_attr = "dos_attr.M_TIME";
769 excl_attr_strings.change_time_attr = "dos_attr.C_TIME";
772 /* Copy name so we can strip off exclusions (if any are specified) */
773 fstrcpy(name_sandbox, attr_name);
775 /* Ensure name is null terminated */
776 name_sandbox[sizeof(name_sandbox) - 1] = '\0';
778 /* Play in the sandbox */
781 /* If there are any exclusions, point to them and mask them from name */
782 if ((pExclude = strchr(name, '!')) != NULL)
787 all = (strncasecmp_m(name, "system.*", 8) == 0);
788 all_nt = (strncasecmp_m(name, "system.nt_sec_desc.*", 20) == 0);
789 all_nt_acls = (strncasecmp_m(name, "system.nt_sec_desc.acl.*", 24) == 0);
790 all_dos = (strncasecmp_m(name, "system.dos_attr.*", 17) == 0);
791 some_nt = (strncasecmp_m(name, "system.nt_sec_desc.", 19) == 0);
792 some_dos = (strncasecmp_m(name, "system.dos_attr.", 16) == 0);
793 numeric = (* (name + strlen(name) - 1) != '+');
795 /* Look for exclusions from "all" requests */
796 if (all || all_nt || all_dos) {
797 /* Exclusions are delimited by '!' */
800 pExclude = (p == NULL ? NULL : p + 1)) {
802 /* Find end of this exclusion name */
803 if ((p = strchr(pExclude, '!')) != NULL)
808 /* Which exclusion name is this? */
809 if (strcasecmp_m(pExclude,
810 "nt_sec_desc.revision") == 0) {
811 exclude_nt_revision = True;
813 else if (strcasecmp_m(pExclude,
814 "nt_sec_desc.owner") == 0) {
815 exclude_nt_owner = True;
817 else if (strcasecmp_m(pExclude,
818 "nt_sec_desc.group") == 0) {
819 exclude_nt_group = True;
821 else if (strcasecmp_m(pExclude,
822 "nt_sec_desc.acl") == 0) {
823 exclude_nt_acl = True;
825 else if (strcasecmp_m(pExclude,
826 "dos_attr.mode") == 0) {
827 exclude_dos_mode = True;
829 else if (strcasecmp_m(pExclude,
830 "dos_attr.size") == 0) {
831 exclude_dos_size = True;
833 else if (excl_attr_strings.create_time_attr != NULL &&
834 strcasecmp_m(pExclude,
835 excl_attr_strings.change_time_attr) == 0) {
836 exclude_dos_create_time = True;
838 else if (strcasecmp_m(pExclude,
839 excl_attr_strings.access_time_attr) == 0) {
840 exclude_dos_access_time = True;
842 else if (strcasecmp_m(pExclude,
843 excl_attr_strings.write_time_attr) == 0) {
844 exclude_dos_write_time = True;
846 else if (strcasecmp_m(pExclude,
847 excl_attr_strings.change_time_attr) == 0) {
848 exclude_dos_change_time = True;
850 else if (strcasecmp_m(pExclude, "dos_attr.inode") == 0) {
851 exclude_dos_inode = True;
854 DEBUG(5, ("cacl_get received unknown exclusion: %s\n",
865 * If we are (possibly) talking to an NT or new system and some NT
866 * attributes have been requested...
868 if (ipc_cli && (all || some_nt || all_nt_acls)) {
869 char *targetpath = NULL;
870 struct cli_state *targetcli = NULL;
871 struct cli_credentials *creds = NULL;
874 /* Point to the portion after "system.nt_sec_desc." */
875 name += 19; /* if (all) this will be invalid but unused */
877 creds = context->internal->creds;
879 status = cli_resolve_path(
882 cli, filename, &targetcli, &targetpath);
883 if (!NT_STATUS_IS_OK(status)) {
884 DEBUG(5, ("cacl_get Could not resolve %s\n",
890 /* ... then obtain any NT attributes which were requested */
891 status = cli_ntcreate(
893 targetpath, /* fname */
895 READ_CONTROL_ACCESS, /* DesiredAccess */
896 0, /* FileAttributes */
898 FILE_SHARE_WRITE, /* ShareAccess */
899 FILE_OPEN, /* CreateDisposition */
900 0x0, /* CreateOptions */
901 0x0, /* SecurityFlags */
904 if (!NT_STATUS_IS_OK(status)) {
905 DEBUG(5, ("cacl_get failed to open %s: %s\n",
906 targetpath, nt_errstr(status)));
907 errno = cli_status_to_errno(status);
911 status = cli_query_secdesc(targetcli, fnum, ctx, &sd);
912 if (!NT_STATUS_IS_OK(status)) {
913 DEBUG(5,("cacl_get Failed to query old descriptor "
915 targetpath, nt_errstr(status)));
916 errno = cli_status_to_errno(status);
920 cli_close(targetcli, fnum);
922 if (! exclude_nt_revision) {
924 if (determine_size) {
925 p = talloc_asprintf(ctx,
934 n = snprintf(buf, bufsize,
938 } else if (strcasecmp_m(name, "revision") == 0) {
939 if (determine_size) {
940 p = talloc_asprintf(ctx, "%d",
948 n = snprintf(buf, bufsize, "%d",
953 if (!determine_size && n > bufsize) {
963 if (! exclude_nt_owner) {
964 /* Get owner and group sid */
966 convert_sid_to_string(ipc_cli, pol,
975 if (determine_size) {
976 p = talloc_asprintf(ctx, ",OWNER:%s",
983 } else if (sidstr[0] != '\0') {
984 n = snprintf(buf, bufsize,
985 ",OWNER:%s", sidstr);
987 } else if (strncasecmp_m(name, "owner", 5) == 0) {
988 if (determine_size) {
989 p = talloc_asprintf(ctx, "%s", sidstr);
996 n = snprintf(buf, bufsize, "%s",
1001 if (!determine_size && n > bufsize) {
1011 if (! exclude_nt_group) {
1012 if (sd->group_sid) {
1013 convert_sid_to_string(ipc_cli, pol,
1017 fstrcpy(sidstr, "");
1020 if (all || all_nt) {
1021 if (determine_size) {
1022 p = talloc_asprintf(ctx, ",GROUP:%s",
1029 } else if (sidstr[0] != '\0') {
1030 n = snprintf(buf, bufsize,
1031 ",GROUP:%s", sidstr);
1033 } else if (strncasecmp_m(name, "group", 5) == 0) {
1034 if (determine_size) {
1035 p = talloc_asprintf(ctx, "%s", sidstr);
1042 n = snprintf(buf, bufsize,
1047 if (!determine_size && n > bufsize) {
1057 if (! exclude_nt_acl) {
1058 /* Add aces to value buffer */
1059 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1061 struct security_ace *ace = &sd->dacl->aces[i];
1062 convert_sid_to_string(ipc_cli, pol,
1066 if (all || all_nt) {
1067 if (determine_size) {
1068 p = talloc_asprintf(
1084 ",ACL:%s:%d/%d/0x%08x",
1090 } else if ((strncasecmp_m(name, "acl", 3) == 0 &&
1091 strcasecmp_m(name+3, sidstr) == 0) ||
1092 (strncasecmp_m(name, "acl+", 4) == 0 &&
1093 strcasecmp_m(name+4, sidstr) == 0)) {
1094 if (determine_size) {
1095 p = talloc_asprintf(
1107 n = snprintf(buf, bufsize,
1113 } else if (all_nt_acls) {
1114 if (determine_size) {
1115 p = talloc_asprintf(
1117 "%s%s:%d/%d/0x%08x",
1129 n = snprintf(buf, bufsize,
1130 "%s%s:%d/%d/0x%08x",
1138 if (!determine_size && n > bufsize) {
1149 /* Restore name pointer to its original value */
1153 if (all || some_dos) {
1154 struct stat sb = {0};
1155 time_t create_time = (time_t)0;
1156 time_t write_time = (time_t)0;
1157 time_t access_time = (time_t)0;
1158 time_t change_time = (time_t)0;
1164 /* Point to the portion after "system.dos_attr." */
1165 name += 16; /* if (all) this will be invalid but unused */
1167 /* Obtain the DOS attributes */
1168 status = SMBC_getatr(context, srv, filename, &sb);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 errno = cli_status_to_errno(status);
1174 create_time = sb.st_ctime;
1175 access_time = sb.st_atime;
1176 write_time = sb.st_mtime;
1177 change_time = sb.st_mtime;
1182 if (! exclude_dos_mode) {
1183 if (all || all_dos) {
1184 if (determine_size) {
1185 p = talloc_asprintf(ctx,
1198 n = snprintf(buf, bufsize,
1206 } else if (strcasecmp_m(name, "mode") == 0) {
1207 if (determine_size) {
1208 p = talloc_asprintf(ctx, "0x%x", mode);
1215 n = snprintf(buf, bufsize,
1220 if (!determine_size && n > bufsize) {
1230 if (! exclude_dos_size) {
1231 if (all || all_dos) {
1232 if (determine_size) {
1233 p = talloc_asprintf(
1243 n = snprintf(buf, bufsize,
1247 } else if (strcasecmp_m(name, "size") == 0) {
1248 if (determine_size) {
1249 p = talloc_asprintf(
1259 n = snprintf(buf, bufsize,
1265 if (!determine_size && n > bufsize) {
1275 if (! exclude_dos_create_time &&
1276 attr_strings.create_time_attr != NULL) {
1277 if (all || all_dos) {
1278 if (determine_size) {
1279 p = talloc_asprintf(ctx,
1281 attr_strings.create_time_attr,
1282 (unsigned long) create_time);
1289 n = snprintf(buf, bufsize,
1291 attr_strings.create_time_attr,
1292 (unsigned long) create_time);
1294 } else if (strcasecmp_m(name, attr_strings.create_time_attr) == 0) {
1295 if (determine_size) {
1296 p = talloc_asprintf(ctx, "%lu", (unsigned long) create_time);
1303 n = snprintf(buf, bufsize,
1304 "%lu", (unsigned long) create_time);
1308 if (!determine_size && n > bufsize) {
1318 if (! exclude_dos_access_time) {
1319 if (all || all_dos) {
1320 if (determine_size) {
1321 p = talloc_asprintf(ctx,
1323 attr_strings.access_time_attr,
1324 (unsigned long) access_time);
1331 n = snprintf(buf, bufsize,
1333 attr_strings.access_time_attr,
1334 (unsigned long) access_time);
1336 } else if (strcasecmp_m(name, attr_strings.access_time_attr) == 0) {
1337 if (determine_size) {
1338 p = talloc_asprintf(ctx, "%lu", (unsigned long) access_time);
1345 n = snprintf(buf, bufsize,
1346 "%lu", (unsigned long) access_time);
1350 if (!determine_size && n > bufsize) {
1360 if (! exclude_dos_write_time) {
1361 if (all || all_dos) {
1362 if (determine_size) {
1363 p = talloc_asprintf(ctx,
1365 attr_strings.write_time_attr,
1366 (unsigned long) write_time);
1373 n = snprintf(buf, bufsize,
1375 attr_strings.write_time_attr,
1376 (unsigned long) write_time);
1378 } else if (strcasecmp_m(name, attr_strings.write_time_attr) == 0) {
1379 if (determine_size) {
1380 p = talloc_asprintf(ctx, "%lu", (unsigned long) write_time);
1387 n = snprintf(buf, bufsize,
1388 "%lu", (unsigned long) write_time);
1392 if (!determine_size && n > bufsize) {
1402 if (! exclude_dos_change_time) {
1403 if (all || all_dos) {
1404 if (determine_size) {
1405 p = talloc_asprintf(ctx,
1407 attr_strings.change_time_attr,
1408 (unsigned long) change_time);
1415 n = snprintf(buf, bufsize,
1417 attr_strings.change_time_attr,
1418 (unsigned long) change_time);
1420 } else if (strcasecmp_m(name, attr_strings.change_time_attr) == 0) {
1421 if (determine_size) {
1422 p = talloc_asprintf(ctx, "%lu", (unsigned long) change_time);
1429 n = snprintf(buf, bufsize,
1430 "%lu", (unsigned long) change_time);
1434 if (!determine_size && n > bufsize) {
1444 if (! exclude_dos_inode) {
1445 if (all || all_dos) {
1446 if (determine_size) {
1447 p = talloc_asprintf(
1457 n = snprintf(buf, bufsize,
1461 } else if (strcasecmp_m(name, "inode") == 0) {
1462 if (determine_size) {
1463 p = talloc_asprintf(
1473 n = snprintf(buf, bufsize,
1479 if (!determine_size && n > bufsize) {
1489 /* Restore name pointer to its original value */
1501 /*****************************************************
1502 set the ACLs on a file given an ascii description
1503 *******************************************************/
1505 cacl_set(SMBCCTX *context,
1507 struct cli_state *cli,
1508 struct cli_state *ipc_cli,
1509 struct policy_handle *pol,
1510 const char *filename,
1515 uint16_t fnum = (uint16_t)-1;
1517 struct security_descriptor *sd = NULL, *old;
1518 struct security_acl *dacl = NULL;
1519 struct dom_sid *owner_sid = NULL;
1520 struct dom_sid *group_sid = NULL;
1525 bool numeric = True;
1526 char *targetpath = NULL;
1527 struct cli_state *targetcli = NULL;
1528 struct cli_credentials *creds = NULL;
1531 /* the_acl will be null for REMOVE_ALL operations */
1533 numeric = ((p = strchr(the_acl, ':')) != NULL &&
1537 /* if this is to set the entire ACL... */
1538 if (*the_acl == '*') {
1539 /* ... then increment past the first colon */
1543 sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, the_acl);
1550 /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller
1551 that doesn't deref sd */
1553 if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) {
1558 creds = context->internal->creds;
1560 status = cli_resolve_path(ctx, "",
1562 cli, filename, &targetcli, &targetpath);
1563 if (!NT_STATUS_IS_OK(status)) {
1564 DEBUG(5,("cacl_set: Could not resolve %s\n", filename));
1569 /* The desired access below is the only one I could find that works
1570 with NT4, W2KP and Samba */
1572 status = cli_ntcreate(
1573 targetcli, /* cli */
1574 targetpath, /* fname */
1576 READ_CONTROL_ACCESS, /* DesiredAccess */
1577 0, /* FileAttributes */
1579 FILE_SHARE_WRITE, /* ShareAccess */
1580 FILE_OPEN, /* CreateDisposition */
1581 0x0, /* CreateOptions */
1582 0x0, /* SecurityFlags */
1585 if (!NT_STATUS_IS_OK(status)) {
1586 DEBUG(5, ("cacl_set failed to open %s: %s\n",
1587 targetpath, nt_errstr(status)));
1592 status = cli_query_secdesc(targetcli, fnum, ctx, &old);
1593 if (!NT_STATUS_IS_OK(status)) {
1594 DEBUG(5,("cacl_set Failed to query old descriptor of %s: %s\n",
1595 targetpath, nt_errstr(status)));
1600 cli_close(targetcli, fnum);
1603 case SMBC_XATTR_MODE_REMOVE_ALL:
1604 old->dacl->num_aces = 0;
1608 case SMBC_XATTR_MODE_REMOVE:
1609 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1612 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
1613 if (security_ace_equal(&sd->dacl->aces[i],
1614 &old->dacl->aces[j])) {
1616 for (k=j; k<old->dacl->num_aces-1;k++) {
1617 old->dacl->aces[k] =
1618 old->dacl->aces[k+1];
1620 old->dacl->num_aces--;
1635 case SMBC_XATTR_MODE_ADD:
1636 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1639 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
1640 if (dom_sid_equal(&sd->dacl->aces[i].trustee,
1641 &old->dacl->aces[j].trustee)) {
1642 if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
1647 old->dacl->aces[j] = sd->dacl->aces[i];
1653 if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) {
1659 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
1660 add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
1666 case SMBC_XATTR_MODE_SET:
1668 owner_sid = old->owner_sid;
1669 group_sid = old->group_sid;
1673 case SMBC_XATTR_MODE_CHOWN:
1674 owner_sid = sd->owner_sid;
1677 case SMBC_XATTR_MODE_CHGRP:
1678 group_sid = sd->group_sid;
1682 /* Denied ACE entries must come before allowed ones */
1683 sort_acl(old->dacl);
1685 /* Create new security descriptor and set it */
1686 sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE,
1687 owner_sid, group_sid, NULL, dacl, &sd_size);
1689 status = cli_ntcreate(targetcli, targetpath, 0,
1690 WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS, 0,
1691 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
1692 0x0, 0x0, &fnum, NULL);
1693 if (!NT_STATUS_IS_OK(status)) {
1694 DEBUG(5, ("cacl_set failed to open %s: %s\n",
1695 targetpath, nt_errstr(status)));
1700 status = cli_set_secdesc(targetcli, fnum, sd);
1701 if (!NT_STATUS_IS_OK(status)) {
1702 DEBUG(5, ("ERROR: secdesc set failed: %s\n",
1703 nt_errstr(status)));
1710 cli_close(targetcli, fnum);
1721 SMBC_setxattr_ctx(SMBCCTX *context,
1730 SMBCSRV *srv = NULL;
1731 SMBCSRV *ipc_srv = NULL;
1732 char *server = NULL;
1735 char *password = NULL;
1736 char *workgroup = NULL;
1738 struct DOS_ATTR_DESC *dad = NULL;
1740 const char * create_time_attr;
1741 const char * access_time_attr;
1742 const char * write_time_attr;
1743 const char * change_time_attr;
1746 TALLOC_CTX *frame = talloc_stackframe();
1748 if (!context || !context->internal->initialized) {
1749 errno = EINVAL; /* Best I can think of ... */
1760 DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n",
1761 fname, name, (int) size, (const char*)value));
1763 if (SMBC_parse_path(frame,
1779 if (!user || user[0] == (char)0) {
1780 user = talloc_strdup(frame, smbc_getUser(context));
1788 srv = SMBC_server(frame, context, True,
1789 server, port, share, &workgroup, &user, &password);
1792 return -1; /* errno set by SMBC_server */
1795 if (! srv->no_nt_session) {
1796 ipc_srv = SMBC_attr_server(frame, context, server, port, share,
1797 &workgroup, &user, &password);
1799 srv->no_nt_session = True;
1806 * Are they asking to set the entire set of known attributes?
1808 if (strcasecmp_m(name, "system.*") == 0 ||
1809 strcasecmp_m(name, "system.*+") == 0) {
1812 talloc_asprintf(talloc_tos(), "%s:%s",
1813 name+7, (const char *) value);
1822 ret = cacl_set(context, talloc_tos(), srv->cli,
1823 ipc_srv->cli, &ipc_srv->pol, path,
1826 ? SMBC_XATTR_MODE_SET
1827 : SMBC_XATTR_MODE_ADD),
1833 /* get a DOS Attribute Descriptor with current attributes */
1834 dad = dos_attr_query(context, talloc_tos(), path, srv);
1838 /* Overwrite old with new, using what was provided */
1839 dos_attr_parse(context, dad, srv, namevalue);
1841 /* Set the new DOS attributes */
1847 .tv_sec = dad->create_time },
1849 .tv_sec = dad->access_time },
1851 .tv_sec = dad->write_time },
1853 .tv_sec = dad->change_time },
1856 /* cause failure if NT failed too */
1861 /* we only fail if both NT and DOS sets failed */
1862 if (ret < 0 && ! dad) {
1863 ret = -1; /* in case dad was null */
1874 * Are they asking to set an access control element or to set
1875 * the entire access control list?
1877 if (strcasecmp_m(name, "system.nt_sec_desc.*") == 0 ||
1878 strcasecmp_m(name, "system.nt_sec_desc.*+") == 0 ||
1879 strcasecmp_m(name, "system.nt_sec_desc.revision") == 0 ||
1880 strncasecmp_m(name, "system.nt_sec_desc.acl", 22) == 0 ||
1881 strncasecmp_m(name, "system.nt_sec_desc.acl+", 23) == 0) {
1885 talloc_asprintf(talloc_tos(), "%s:%s",
1886 name+19, (const char *) value);
1889 ret = -1; /* errno set by SMBC_server() */
1891 else if (! namevalue) {
1895 ret = cacl_set(context, talloc_tos(), srv->cli,
1896 ipc_srv->cli, &ipc_srv->pol, path,
1899 ? SMBC_XATTR_MODE_SET
1900 : SMBC_XATTR_MODE_ADD),
1908 * Are they asking to set the owner?
1910 if (strcasecmp_m(name, "system.nt_sec_desc.owner") == 0 ||
1911 strcasecmp_m(name, "system.nt_sec_desc.owner+") == 0) {
1915 talloc_asprintf(talloc_tos(), "%s:%s",
1916 name+19, (const char *) value);
1919 ret = -1; /* errno set by SMBC_server() */
1921 else if (! namevalue) {
1925 ret = cacl_set(context, talloc_tos(), srv->cli,
1926 ipc_srv->cli, &ipc_srv->pol, path,
1927 namevalue, SMBC_XATTR_MODE_CHOWN, 0);
1934 * Are they asking to set the group?
1936 if (strcasecmp_m(name, "system.nt_sec_desc.group") == 0 ||
1937 strcasecmp_m(name, "system.nt_sec_desc.group+") == 0) {
1941 talloc_asprintf(talloc_tos(), "%s:%s",
1942 name+19, (const char *) value);
1945 /* errno set by SMBC_server() */
1948 else if (! namevalue) {
1952 ret = cacl_set(context, talloc_tos(), srv->cli,
1953 ipc_srv->cli, &ipc_srv->pol, path,
1954 namevalue, SMBC_XATTR_MODE_CHGRP, 0);
1960 /* Determine whether to use old-style or new-style attribute names */
1961 if (context->internal->full_time_names) {
1962 /* new-style names */
1963 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
1964 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
1965 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
1966 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
1968 /* old-style names */
1969 attr_strings.create_time_attr = NULL;
1970 attr_strings.access_time_attr = "system.dos_attr.A_TIME";
1971 attr_strings.write_time_attr = "system.dos_attr.M_TIME";
1972 attr_strings.change_time_attr = "system.dos_attr.C_TIME";
1976 * Are they asking to set a DOS attribute?
1978 if (strcasecmp_m(name, "system.dos_attr.*") == 0 ||
1979 strcasecmp_m(name, "system.dos_attr.mode") == 0 ||
1980 (attr_strings.create_time_attr != NULL &&
1981 strcasecmp_m(name, attr_strings.create_time_attr) == 0) ||
1982 strcasecmp_m(name, attr_strings.access_time_attr) == 0 ||
1983 strcasecmp_m(name, attr_strings.write_time_attr) == 0 ||
1984 strcasecmp_m(name, attr_strings.change_time_attr) == 0) {
1986 /* get a DOS Attribute Descriptor with current attributes */
1987 dad = dos_attr_query(context, talloc_tos(), path, srv);
1990 talloc_asprintf(talloc_tos(), "%s:%s",
1991 name+16, (const char *) value);
1996 /* Overwrite old with provided new params */
1997 dos_attr_parse(context, dad, srv, namevalue);
1999 /* Set the new DOS attributes */
2005 .tv_sec = dad->create_time },
2007 .tv_sec = dad->access_time },
2009 .tv_sec = dad->write_time },
2011 .tv_sec = dad->change_time },
2014 /* ret2 has True (success) / False (failure) */
2029 /* Unsupported attribute name */
2036 SMBC_getxattr_ctx(SMBCCTX *context,
2043 SMBCSRV *srv = NULL;
2044 SMBCSRV *ipc_srv = NULL;
2045 char *server = NULL;
2048 char *password = NULL;
2049 char *workgroup = NULL;
2052 const char * create_time_attr;
2053 const char * access_time_attr;
2054 const char * write_time_attr;
2055 const char * change_time_attr;
2058 TALLOC_CTX *frame = talloc_stackframe();
2060 if (!context || !context->internal->initialized) {
2061 errno = EINVAL; /* Best I can think of ... */
2072 DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name));
2074 if (SMBC_parse_path(frame,
2090 if (!user || user[0] == '\0') {
2091 user = talloc_strdup(frame, smbc_getUser(context));
2099 srv = SMBC_server(frame, context, True,
2100 server, port, share, &workgroup, &user, &password);
2103 return -1; /* errno set by SMBC_server */
2106 if (! srv->no_nt_session) {
2107 ipc_srv = SMBC_attr_server(frame, context, server, port, share,
2108 &workgroup, &user, &password);
2110 * SMBC_attr_server() can cause the original
2111 * server to be removed from the cache.
2112 * If so we must error out here as the srv
2113 * pointer has been freed.
2115 if (smbc_getFunctionGetCachedServer(context)(context,
2120 #if defined(ECONNRESET)
2129 srv->no_nt_session = True;
2135 /* Determine whether to use old-style or new-style attribute names */
2136 if (context->internal->full_time_names) {
2137 /* new-style names */
2138 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
2139 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
2140 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
2141 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
2143 /* old-style names */
2144 attr_strings.create_time_attr = NULL;
2145 attr_strings.access_time_attr = "system.dos_attr.A_TIME";
2146 attr_strings.write_time_attr = "system.dos_attr.M_TIME";
2147 attr_strings.change_time_attr = "system.dos_attr.C_TIME";
2150 /* Are they requesting a supported attribute? */
2151 if (strcasecmp_m(name, "system.*") == 0 ||
2152 strncasecmp_m(name, "system.*!", 9) == 0 ||
2153 strcasecmp_m(name, "system.*+") == 0 ||
2154 strncasecmp_m(name, "system.*+!", 10) == 0 ||
2155 strcasecmp_m(name, "system.nt_sec_desc.*") == 0 ||
2156 strncasecmp_m(name, "system.nt_sec_desc.*!", 21) == 0 ||
2157 strcasecmp_m(name, "system.nt_sec_desc.*+") == 0 ||
2158 strncasecmp_m(name, "system.nt_sec_desc.*+!", 22) == 0 ||
2159 strcasecmp_m(name, "system.nt_sec_desc.revision") == 0 ||
2160 strcasecmp_m(name, "system.nt_sec_desc.owner") == 0 ||
2161 strcasecmp_m(name, "system.nt_sec_desc.owner+") == 0 ||
2162 strcasecmp_m(name, "system.nt_sec_desc.group") == 0 ||
2163 strcasecmp_m(name, "system.nt_sec_desc.group+") == 0 ||
2164 strncasecmp_m(name, "system.nt_sec_desc.acl", 22) == 0 ||
2165 strncasecmp_m(name, "system.nt_sec_desc.acl+", 23) == 0 ||
2166 strcasecmp_m(name, "system.dos_attr.*") == 0 ||
2167 strncasecmp_m(name, "system.dos_attr.*!", 18) == 0 ||
2168 strcasecmp_m(name, "system.dos_attr.mode") == 0 ||
2169 strcasecmp_m(name, "system.dos_attr.size") == 0 ||
2170 (attr_strings.create_time_attr != NULL &&
2171 strcasecmp_m(name, attr_strings.create_time_attr) == 0) ||
2172 strcasecmp_m(name, attr_strings.access_time_attr) == 0 ||
2173 strcasecmp_m(name, attr_strings.write_time_attr) == 0 ||
2174 strcasecmp_m(name, attr_strings.change_time_attr) == 0 ||
2175 strcasecmp_m(name, "system.dos_attr.inode") == 0) {
2178 const char *filename = name;
2179 ret = cacl_get(context, talloc_tos(), srv,
2180 ipc_srv == NULL ? NULL : ipc_srv->cli,
2181 &ipc_srv->pol, path,
2183 discard_const_p(char, value),
2187 * static function cacl_get returns a value greater than zero
2188 * which is needed buffer size needed when size_t is 0.
2193 /* Unsupported attribute name */
2201 SMBC_removexattr_ctx(SMBCCTX *context,
2206 SMBCSRV *srv = NULL;
2207 SMBCSRV *ipc_srv = NULL;
2208 char *server = NULL;
2211 char *password = NULL;
2212 char *workgroup = NULL;
2215 TALLOC_CTX *frame = talloc_stackframe();
2217 if (!context || !context->internal->initialized) {
2218 errno = EINVAL; /* Best I can think of ... */
2229 DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name));
2231 if (SMBC_parse_path(frame,
2247 if (!user || user[0] == (char)0) {
2248 user = talloc_strdup(frame, smbc_getUser(context));
2256 srv = SMBC_server(frame, context, True,
2257 server, port, share, &workgroup, &user, &password);
2260 return -1; /* errno set by SMBC_server */
2263 if (! srv->no_nt_session) {
2265 ipc_srv = SMBC_attr_server(frame, context, server, port, share,
2266 &workgroup, &user, &password);
2267 saved_errno = errno;
2269 * SMBC_attr_server() can cause the original
2270 * server to be removed from the cache.
2271 * If so we must error out here as the srv
2272 * pointer has been freed.
2274 if (smbc_getFunctionGetCachedServer(context)(context,
2279 #if defined(ECONNRESET)
2288 errno = saved_errno;
2289 srv->no_nt_session = True;
2297 return -1; /* errno set by SMBC_attr_server */
2300 /* Are they asking to set the entire ACL? */
2301 if (strcasecmp_m(name, "system.nt_sec_desc.*") == 0 ||
2302 strcasecmp_m(name, "system.nt_sec_desc.*+") == 0) {
2305 ret = cacl_set(context, talloc_tos(), srv->cli,
2306 ipc_srv->cli, &ipc_srv->pol, path,
2307 NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
2313 * Are they asking to remove one or more specific security descriptor
2316 if (strcasecmp_m(name, "system.nt_sec_desc.revision") == 0 ||
2317 strcasecmp_m(name, "system.nt_sec_desc.owner") == 0 ||
2318 strcasecmp_m(name, "system.nt_sec_desc.owner+") == 0 ||
2319 strcasecmp_m(name, "system.nt_sec_desc.group") == 0 ||
2320 strcasecmp_m(name, "system.nt_sec_desc.group+") == 0 ||
2321 strncasecmp_m(name, "system.nt_sec_desc.acl", 22) == 0 ||
2322 strncasecmp_m(name, "system.nt_sec_desc.acl+", 23) == 0) {
2325 ret = cacl_set(context, talloc_tos(), srv->cli,
2326 ipc_srv->cli, &ipc_srv->pol, path,
2327 discard_const_p(char, name) + 19,
2328 SMBC_XATTR_MODE_REMOVE, 0);
2333 /* Unsupported attribute name */
2340 SMBC_listxattr_ctx(SMBCCTX *context,
2346 * This isn't quite what listxattr() is supposed to do. This returns
2347 * the complete set of attribute names, always, rather than only those
2348 * attribute names which actually exist for a file. Hmmm...
2351 static const char supported_old[] =
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.c_time\0"
2367 "system.dos_attr.a_time\0"
2368 "system.dos_attr.m_time\0"
2370 static const char supported_new[] =
2373 "system.nt_sec_desc.revision\0"
2374 "system.nt_sec_desc.owner\0"
2375 "system.nt_sec_desc.owner+\0"
2376 "system.nt_sec_desc.group\0"
2377 "system.nt_sec_desc.group+\0"
2378 "system.nt_sec_desc.acl.*\0"
2379 "system.nt_sec_desc.acl\0"
2380 "system.nt_sec_desc.acl+\0"
2381 "system.nt_sec_desc.*\0"
2382 "system.nt_sec_desc.*+\0"
2383 "system.dos_attr.*\0"
2384 "system.dos_attr.mode\0"
2385 "system.dos_attr.create_time\0"
2386 "system.dos_attr.access_time\0"
2387 "system.dos_attr.write_time\0"
2388 "system.dos_attr.change_time\0"
2390 const char * supported;
2392 if (context->internal->full_time_names) {
2393 supported = supported_new;
2394 retsize = sizeof(supported_new);
2396 supported = supported_old;
2397 retsize = sizeof(supported_old);
2404 if (retsize > size) {
2409 /* this can't be strcpy() because there are embedded null characters */
2410 memcpy(list, supported, retsize);