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