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