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
,
270 const struct perm_value
*v
;
275 TALLOC_CTX
*frame
= talloc_stackframe();
277 /* These values discovered by inspection */
278 static const struct perm_value special_values
[] = {
288 static const struct perm_value standard_values
[] = {
289 { "READ", 0x001200a9 },
290 { "CHANGE", 0x001301bf },
291 { "FULL", 0x001f01ff },
296 p
= strchr_m(str
,':');
303 /* Try to parse numeric form */
305 if (sscanf(p
, "%u/%u/%u", &atype
, &aflags
, &amask
) == 3 &&
306 convert_string_to_sid(ipc_cli
, pol
, numeric
, &sid
, str
)) {
310 /* Try to parse text form */
312 if (!convert_string_to_sid(ipc_cli
, pol
, numeric
, &sid
, str
)) {
318 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
323 if (strncasecmp_m(tok
, "ALLOWED", strlen("ALLOWED")) == 0) {
324 atype
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
325 } else if (strncasecmp_m(tok
, "DENIED", strlen("DENIED")) == 0) {
326 atype
= SEC_ACE_TYPE_ACCESS_DENIED
;
332 /* Only numeric form accepted for flags at present */
334 if (!(next_token_talloc(frame
, &cp
, &tok
, "/") &&
335 sscanf(tok
, "%u", &aflags
))) {
340 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
345 if (strncmp(tok
, "0x", 2) == 0) {
346 if (sscanf(tok
, "%u", &amask
) != 1) {
353 for (v
= standard_values
; v
!= NULL
; v
++) {
354 if (strcmp(tok
, v
->perm
) == 0) {
365 for (v
= special_values
; v
!= NULL
; v
++) {
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);
632 dad
->mode
= (request
|
633 (IS_DOS_DIR(dad
->mode
)
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
)));
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
)));
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
),
2179 if (ret
< 0 && errno
== 0) {
2180 errno
= SMBC_errno(context
, srv
->cli
);
2186 /* Unsupported attribute name */
2194 SMBC_removexattr_ctx(SMBCCTX
*context
,
2199 SMBCSRV
*srv
= NULL
;
2200 SMBCSRV
*ipc_srv
= NULL
;
2201 char *server
= NULL
;
2204 char *password
= NULL
;
2205 char *workgroup
= NULL
;
2208 TALLOC_CTX
*frame
= talloc_stackframe();
2210 if (!context
|| !context
->internal
->initialized
) {
2211 errno
= EINVAL
; /* Best I can think of ... */
2222 DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname
, name
));
2224 if (SMBC_parse_path(frame
,
2240 if (!user
|| user
[0] == (char)0) {
2241 user
= talloc_strdup(frame
, smbc_getUser(context
));
2249 srv
= SMBC_server(frame
, context
, True
,
2250 server
, port
, share
, &workgroup
, &user
, &password
);
2253 return -1; /* errno set by SMBC_server */
2256 if (! srv
->no_nt_session
) {
2258 ipc_srv
= SMBC_attr_server(frame
, context
, server
, port
, share
,
2259 &workgroup
, &user
, &password
);
2260 saved_errno
= errno
;
2262 * SMBC_attr_server() can cause the original
2263 * server to be removed from the cache.
2264 * If so we must error out here as the srv
2265 * pointer has been freed.
2267 if (smbc_getFunctionGetCachedServer(context
)(context
,
2272 #if defined(ECONNRESET)
2281 errno
= saved_errno
;
2282 srv
->no_nt_session
= True
;
2290 return -1; /* errno set by SMBC_attr_server */
2293 /* Are they asking to set the entire ACL? */
2294 if (strcasecmp_m(name
, "system.nt_sec_desc.*") == 0 ||
2295 strcasecmp_m(name
, "system.nt_sec_desc.*+") == 0) {
2298 ret
= cacl_set(context
, talloc_tos(), srv
->cli
,
2299 ipc_srv
->cli
, &ipc_srv
->pol
, path
,
2300 NULL
, SMBC_XATTR_MODE_REMOVE_ALL
, 0);
2306 * Are they asking to remove one or more specific security descriptor
2309 if (strcasecmp_m(name
, "system.nt_sec_desc.revision") == 0 ||
2310 strcasecmp_m(name
, "system.nt_sec_desc.owner") == 0 ||
2311 strcasecmp_m(name
, "system.nt_sec_desc.owner+") == 0 ||
2312 strcasecmp_m(name
, "system.nt_sec_desc.group") == 0 ||
2313 strcasecmp_m(name
, "system.nt_sec_desc.group+") == 0 ||
2314 strncasecmp_m(name
, "system.nt_sec_desc.acl", 22) == 0 ||
2315 strncasecmp_m(name
, "system.nt_sec_desc.acl+", 23) == 0) {
2318 ret
= cacl_set(context
, talloc_tos(), srv
->cli
,
2319 ipc_srv
->cli
, &ipc_srv
->pol
, path
,
2320 discard_const_p(char, name
) + 19,
2321 SMBC_XATTR_MODE_REMOVE
, 0);
2326 /* Unsupported attribute name */
2333 SMBC_listxattr_ctx(SMBCCTX
*context
,
2339 * This isn't quite what listxattr() is supposed to do. This returns
2340 * the complete set of attribute names, always, rather than only those
2341 * attribute names which actually exist for a file. Hmmm...
2344 const char supported_old
[] =
2347 "system.nt_sec_desc.revision\0"
2348 "system.nt_sec_desc.owner\0"
2349 "system.nt_sec_desc.owner+\0"
2350 "system.nt_sec_desc.group\0"
2351 "system.nt_sec_desc.group+\0"
2352 "system.nt_sec_desc.acl.*\0"
2353 "system.nt_sec_desc.acl\0"
2354 "system.nt_sec_desc.acl+\0"
2355 "system.nt_sec_desc.*\0"
2356 "system.nt_sec_desc.*+\0"
2357 "system.dos_attr.*\0"
2358 "system.dos_attr.mode\0"
2359 "system.dos_attr.c_time\0"
2360 "system.dos_attr.a_time\0"
2361 "system.dos_attr.m_time\0"
2363 const char supported_new
[] =
2366 "system.nt_sec_desc.revision\0"
2367 "system.nt_sec_desc.owner\0"
2368 "system.nt_sec_desc.owner+\0"
2369 "system.nt_sec_desc.group\0"
2370 "system.nt_sec_desc.group+\0"
2371 "system.nt_sec_desc.acl.*\0"
2372 "system.nt_sec_desc.acl\0"
2373 "system.nt_sec_desc.acl+\0"
2374 "system.nt_sec_desc.*\0"
2375 "system.nt_sec_desc.*+\0"
2376 "system.dos_attr.*\0"
2377 "system.dos_attr.mode\0"
2378 "system.dos_attr.create_time\0"
2379 "system.dos_attr.access_time\0"
2380 "system.dos_attr.write_time\0"
2381 "system.dos_attr.change_time\0"
2383 const char * supported
;
2385 if (context
->internal
->full_time_names
) {
2386 supported
= supported_new
;
2387 retsize
= sizeof(supported_new
);
2389 supported
= supported_old
;
2390 retsize
= sizeof(supported_old
);
2397 if (retsize
> size
) {
2402 /* this can't be strcpy() because there are embedded null characters */
2403 memcpy(list
, supported
, retsize
);