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