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
);