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, 2004 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 2 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23*/ 24 25#include "includes.h" 26 27#include "include/libsmb_internal.h" 28 29struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir); 30struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, 31 struct smbc_dirent *dirent); 32 33/* 34 * DOS Attribute values (used internally) 35 */ 36typedef struct DOS_ATTR_DESC { 37 int mode; 38 SMB_OFF_T size; 39 time_t create_time; 40 time_t access_time; 41 time_t write_time; 42 time_t change_time; 43 SMB_INO_T inode; 44} DOS_ATTR_DESC; 45 46 47/* 48 * Internal flags for extended attributes 49 */ 50 51/* internal mode values */ 52#define SMBC_XATTR_MODE_ADD 1 53#define SMBC_XATTR_MODE_REMOVE 2 54#define SMBC_XATTR_MODE_REMOVE_ALL 3 55#define SMBC_XATTR_MODE_SET 4 56#define SMBC_XATTR_MODE_CHOWN 5 57#define SMBC_XATTR_MODE_CHGRP 6 58 59#define CREATE_ACCESS_READ READ_CONTROL_ACCESS 60 61/*We should test for this in configure ... */ 62#ifndef ENOTSUP 63#define ENOTSUP EOPNOTSUPP 64#endif 65 66/* 67 * Functions exported by libsmb_cache.c that we need here 68 */ 69int smbc_default_cache_functions(SMBCCTX *context); 70 71/* 72 * check if an element is part of the list. 73 * FIXME: Does not belong here ! 74 * Can anyone put this in a macro in dlinklist.h ? 75 * -- Tom 76 */ 77static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) { 78 if (!p || !list) return False; 79 do { 80 if (p == list) return True; 81 list = list->next; 82 } while (list); 83 return False; 84} 85 86/* 87 * Find an lsa pipe handle associated with a cli struct. 88 */ 89static struct rpc_pipe_client * 90find_lsa_pipe_hnd(struct cli_state *ipc_cli) 91{ 92 struct rpc_pipe_client *pipe_hnd; 93 94 for (pipe_hnd = ipc_cli->pipe_list; 95 pipe_hnd; 96 pipe_hnd = pipe_hnd->next) { 97 98 if (pipe_hnd->pipe_idx == PI_LSARPC) { 99 return pipe_hnd; 100 } 101 } 102 103 return NULL; 104} 105 106static int 107smbc_close_ctx(SMBCCTX *context, 108 SMBCFILE *file); 109static off_t 110smbc_lseek_ctx(SMBCCTX *context, 111 SMBCFILE *file, 112 off_t offset, 113 int whence); 114 115extern BOOL in_client; 116 117/* 118 * Is the logging working / configfile read ? 119 */ 120static int smbc_initialized = 0; 121 122static int 123hex2int( unsigned int _char ) 124{ 125 if ( _char >= 'A' && _char <='F') 126 return _char - 'A' + 10; 127 if ( _char >= 'a' && _char <='f') 128 return _char - 'a' + 10; 129 if ( _char >= '0' && _char <='9') 130 return _char - '0'; 131 return -1; 132} 133 134/* 135 * smbc_urldecode() 136 * 137 * Convert strings of %xx to their single character equivalent. Each 'x' must 138 * be a valid hexadecimal digit, or that % sequence is left undecoded. 139 * 140 * dest may, but need not be, the same pointer as src. 141 * 142 * Returns the number of % sequences which could not be converted due to lack 143 * of two following hexadecimal digits. 144 */ 145int 146smbc_urldecode(char *dest, char * src, size_t max_dest_len) 147{ 148 int old_length = strlen(src); 149 int i = 0; 150 int err_count = 0; 151 pstring temp; 152 char * p; 153 154 if ( old_length == 0 ) { 155 return 0; 156 } 157 158 p = temp; 159 while ( i < old_length ) { 160 unsigned char character = src[ i++ ]; 161 162 if (character == '%') { 163 int a = i+1 < old_length ? hex2int( src[i] ) : -1; 164 int b = i+1 < old_length ? hex2int( src[i+1] ) : -1; 165 166 /* Replace valid sequence */ 167 if (a != -1 && b != -1) { 168 169 /* Replace valid %xx sequence with %dd */ 170 character = (a * 16) + b; 171 172 if (character == '\0') { 173 break; /* Stop at %00 */ 174 } 175 176 i += 2; 177 } else { 178 179 err_count++; 180 } 181 } 182 183 *p++ = character; 184 } 185 186 *p = '\0'; 187 188 strncpy(dest, temp, max_dest_len - 1); 189 dest[max_dest_len - 1] = '\0'; 190 191 return err_count; 192} 193 194/* 195 * smbc_urlencode() 196 * 197 * Convert any characters not specifically allowed in a URL into their %xx 198 * equivalent. 199 * 200 * Returns the remaining buffer length. 201 */ 202int 203smbc_urlencode(char * dest, char * src, int max_dest_len) 204{ 205 char hex[] = "0123456789ABCDEF"; 206 207 for (; *src != '\0' && max_dest_len >= 3; src++) { 208 209 if ((*src < '0' && 210 *src != '-' && 211 *src != '.') || 212 (*src > '9' && 213 *src < 'A') || 214 (*src > 'Z' && 215 *src < 'a' && 216 *src != '_') || 217 (*src > 'z')) { 218 *dest++ = '%'; 219 *dest++ = hex[(*src >> 4) & 0x0f]; 220 *dest++ = hex[*src & 0x0f]; 221 max_dest_len -= 3; 222 } else { 223 *dest++ = *src; 224 max_dest_len--; 225 } 226 } 227 228 *dest++ = '\0'; 229 max_dest_len--; 230 231 return max_dest_len; 232} 233 234/* 235 * Function to parse a path and turn it into components 236 * 237 * The general format of an SMB URI is explain in Christopher Hertel's CIFS 238 * book, at http://ubiqx.org/cifs/Appendix-D.html. We accept a subset of the 239 * general format ("smb:" only; we do not look for "cifs:"). 240 * 241 * 242 * We accept: 243 * smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options] 244 * 245 * Meaning of URLs: 246 * 247 * smb:// Show all workgroups. 248 * 249 * The method of locating the list of workgroups varies 250 * depending upon the setting of the context variable 251 * context->options.browse_max_lmb_count. This value 252 * determine the maximum number of local master browsers to 253 * query for the list of workgroups. In order to ensure that 254 * a complete list of workgroups is obtained, all master 255 * browsers must be queried, but if there are many 256 * workgroups, the time spent querying can begin to add up. 257 * For small networks (not many workgroups), it is suggested 258 * that this variable be set to 0, indicating query all local 259 * master browsers. When the network has many workgroups, a 260 * reasonable setting for this variable might be around 3. 261 * 262 * smb://name/ if name<1D> or name<1B> exists, list servers in 263 * workgroup, else, if name<20> exists, list all shares 264 * for server ... 265 * 266 * If "options" are provided, this function returns the entire option list as a 267 * string, for later parsing by the caller. Note that currently, no options 268 * are supported. 269 */ 270 271static const char *smbc_prefix = "smb:"; 272 273static int 274smbc_parse_path(SMBCCTX *context, 275 const char *fname, 276 char *workgroup, int workgroup_len, 277 char *server, int server_len, 278 char *share, int share_len, 279 char *path, int path_len, 280 char *user, int user_len, 281 char *password, int password_len, 282 char *options, int options_len) 283{ 284 static pstring s; 285 pstring userinfo; 286 const char *p; 287 char *q, *r; 288 int len; 289 290 server[0] = share[0] = path[0] = user[0] = password[0] = (char)0; 291 292 /* 293 * Assume we wont find an authentication domain to parse, so default 294 * to the workgroup in the provided context. 295 */ 296 if (workgroup != NULL) { 297 strncpy(workgroup, context->workgroup, workgroup_len - 1); 298 workgroup[workgroup_len - 1] = '\0'; 299 } 300 301 if (options != NULL && options_len > 0) { 302 options[0] = (char)0; 303 } 304 pstrcpy(s, fname); 305 306 /* see if it has the right prefix */ 307 len = strlen(smbc_prefix); 308 if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) { 309 return -1; /* What about no smb: ? */ 310 } 311 312 p = s + len; 313 314 /* Watch the test below, we are testing to see if we should exit */ 315 316 if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) { 317 318 DEBUG(1, ("Invalid path (does not begin with smb://")); 319 return -1; 320 321 } 322 323 p += 2; /* Skip the double slash */ 324 325 /* See if any options were specified */ 326 if ((q = strrchr(p, '?')) != NULL ) { 327 /* There are options. Null terminate here and point to them */ 328 *q++ = '\0'; 329 330 DEBUG(4, ("Found options '%s'", q)); 331 332 /* Copy the options */ 333 if (options != NULL && options_len > 0) { 334 safe_strcpy(options, q, options_len - 1); 335 } 336 } 337 338 if (*p == (char)0) 339 goto decoding; 340 341 if (*p == '/') { 342 int wl = strlen(context->workgroup); 343 344 if (wl > 16) { 345 wl = 16; 346 } 347 348 strncpy(server, context->workgroup, wl); 349 server[wl] = '\0'; 350 return 0; 351 } 352 353 /* 354 * ok, its for us. Now parse out the server, share etc. 355 * 356 * However, we want to parse out [[domain;]user[:password]@] if it 357 * exists ... 358 */ 359 360 /* check that '@' occurs before '/', if '/' exists at all */ 361 q = strchr_m(p, '@'); 362 r = strchr_m(p, '/'); 363 if (q && (!r || q < r)) { 364 pstring username, passwd, domain; 365 const char *u = userinfo; 366 367 next_token_no_ltrim(&p, userinfo, "@", sizeof(fstring)); 368 369 username[0] = passwd[0] = domain[0] = 0; 370 371 if (strchr_m(u, ';')) { 372 373 next_token_no_ltrim(&u, domain, ";", sizeof(fstring)); 374 375 } 376 377 if (strchr_m(u, ':')) { 378 379 next_token_no_ltrim(&u, username, ":", sizeof(fstring)); 380 381 pstrcpy(passwd, u); 382 383 } 384 else { 385 386 pstrcpy(username, u); 387 388 } 389 390 if (domain[0] && workgroup) { 391 strncpy(workgroup, domain, workgroup_len - 1); 392 workgroup[workgroup_len - 1] = '\0'; 393 } 394 395 if (username[0]) { 396 strncpy(user, username, user_len - 1); 397 user[user_len - 1] = '\0'; 398 } 399 400 if (passwd[0]) { 401 strncpy(password, passwd, password_len - 1); 402 password[password_len - 1] = '\0'; 403 } 404 405 } 406 407 if (!next_token(&p, server, "/", sizeof(fstring))) { 408 409 return -1; 410 411 } 412 413 if (*p == (char)0) goto decoding; /* That's it ... */ 414 415 if (!next_token(&p, share, "/", sizeof(fstring))) { 416 417 return -1; 418 419 } 420 421 /* 422 * Prepend a leading slash if there's a file path, as required by 423 * NetApp filers. 424 */ 425 *path = '\0'; 426 if (*p != '\0') { 427 *path = '/'; 428 safe_strcpy(path + 1, p, path_len - 2); 429 } 430 431 all_string_sub(path, "/", "\\", 0); 432 433 decoding: 434 (void) smbc_urldecode(path, path, path_len); 435 (void) smbc_urldecode(server, server, server_len); 436 (void) smbc_urldecode(share, share, share_len); 437 (void) smbc_urldecode(user, user, user_len); 438 (void) smbc_urldecode(password, password, password_len); 439 440 return 0; 441} 442 443/* 444 * Verify that the options specified in a URL are valid 445 */ 446static int 447smbc_check_options(char *server, 448 char *share, 449 char *path, 450 char *options) 451{ 452 DEBUG(4, ("smbc_check_options(): server='%s' share='%s' " 453 "path='%s' options='%s'\n", 454 server, share, path, options)); 455 456 /* No options at all is always ok */ 457 if (! *options) return 0; 458 459 /* Currently, we don't support any options. */ 460 return -1; 461} 462 463/* 464 * Convert an SMB error into a UNIX error ... 465 */ 466static int 467smbc_errno(SMBCCTX *context, 468 struct cli_state *c) 469{ 470 int ret = cli_errno(c); 471 472 if (cli_is_dos_error(c)) { 473 uint8 eclass; 474 uint32 ecode; 475 476 cli_dos_error(c, &eclass, &ecode); 477 478 DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", 479 (int)eclass, (int)ecode, (int)ecode, ret)); 480 } else { 481 NTSTATUS status; 482 483 status = cli_nt_error(c); 484 485 DEBUG(3,("smbc errno %s -> %d\n", 486 nt_errstr(status), ret)); 487 } 488 489 return ret; 490} 491 492/* 493 * Check a server for being alive and well. 494 * returns 0 if the server is in shape. Returns 1 on error 495 * 496 * Also useable outside libsmbclient to enable external cache 497 * to do some checks too. 498 */ 499static int 500smbc_check_server(SMBCCTX * context, 501 SMBCSRV * server) 502{ 503 socklen_t size; 504 struct sockaddr addr; 505 506 /* 507 * Although the use of port 139 is not a guarantee that we're using 508 * netbios, we assume so. We don't want to send a keepalive packet if 509 * not netbios because it's not valid, and Vista, at least, 510 * disconnects the client on such a request. 511 */ 512 if (server->cli->port == 139) { 513 /* Assuming netbios. Send a keepalive packet */ 514 if ( send_keepalive(server->cli->fd) == False ) { 515 return 1; 516 } 517 } else { 518 /* 519 * Assuming not netbios. Try a different method to detect if 520 * the connection is still alive. 521 */ 522 size = sizeof(addr); 523 if (getpeername(server->cli->fd, &addr, &size) == -1) { 524 return 1; 525 } 526 } 527 528 /* connection is ok */ 529 return 0; 530} 531 532/* 533 * Remove a server from the cached server list it's unused. 534 * On success, 0 is returned. 1 is returned if the server could not be removed. 535 * 536 * Also useable outside libsmbclient 537 */ 538int 539smbc_remove_unused_server(SMBCCTX * context, 540 SMBCSRV * srv) 541{ 542 SMBCFILE * file; 543 544 /* are we being fooled ? */ 545 if (!context || !context->internal || 546 !context->internal->_initialized || !srv) return 1; 547 548 549 /* Check all open files/directories for a relation with this server */ 550 for (file = context->internal->_files; file; file=file->next) { 551 if (file->srv == srv) { 552 /* Still used */ 553 DEBUG(3, ("smbc_remove_usused_server: " 554 "%p still used by %p.\n", 555 srv, file)); 556 return 1; 557 } 558 } 559 560 DLIST_REMOVE(context->internal->_servers, srv); 561 562 cli_shutdown(srv->cli); 563 srv->cli = NULL; 564 565 DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); 566 567 context->callbacks.remove_cached_srv_fn(context, srv); 568 569 SAFE_FREE(srv); 570 571 return 0; 572} 573 574static SMBCSRV * 575find_server(SMBCCTX *context, 576 const char *server, 577 const char *share, 578 fstring workgroup, 579 fstring username, 580 fstring password) 581{ 582 SMBCSRV *srv; 583 int auth_called = 0; 584 585 check_server_cache: 586 587 srv = context->callbacks.get_cached_srv_fn(context, server, share, 588 workgroup, username); 589 590 if (!auth_called && !srv && (!username[0] || !password[0])) { 591 if (context->internal->_auth_fn_with_context != NULL) { 592 context->internal->_auth_fn_with_context( 593 context, 594 server, share, 595 workgroup, sizeof(fstring), 596 username, sizeof(fstring), 597 password, sizeof(fstring)); 598 } else { 599 context->callbacks.auth_fn( 600 server, share, 601 workgroup, sizeof(fstring), 602 username, sizeof(fstring), 603 password, sizeof(fstring)); 604 } 605 606 /* 607 * However, smbc_auth_fn may have picked up info relating to 608 * an existing connection, so try for an existing connection 609 * again ... 610 */ 611 auth_called = 1; 612 goto check_server_cache; 613 614 } 615 616 if (srv) { 617 if (context->callbacks.check_server_fn(context, srv)) { 618 /* 619 * This server is no good anymore 620 * Try to remove it and check for more possible 621 * servers in the cache 622 */ 623 if (context->callbacks.remove_unused_server_fn(context, 624 srv)) { 625 /* 626 * We could not remove the server completely, 627 * remove it from the cache so we will not get 628 * it again. It will be removed when the last 629 * file/dir is closed. 630 */ 631 context->callbacks.remove_cached_srv_fn(context, 632 srv); 633 } 634 635 /* 636 * Maybe there are more cached connections to this 637 * server 638 */ 639 goto check_server_cache; 640 } 641 642 return srv; 643 } 644 645 return NULL; 646} 647 648/* 649 * Connect to a server, possibly on an existing connection 650 * 651 * Here, what we want to do is: If the server and username 652 * match an existing connection, reuse that, otherwise, establish a 653 * new connection. 654 * 655 * If we have to create a new connection, call the auth_fn to get the 656 * info we need, unless the username and password were passed in. 657 */ 658 659static SMBCSRV * 660smbc_server(SMBCCTX *context, 661 BOOL connect_if_not_found, 662 const char *server, 663 const char *share, 664 fstring workgroup, 665 fstring username, 666 fstring password) 667{ 668 SMBCSRV *srv=NULL; 669 struct cli_state *c; 670 struct nmb_name called, calling; 671 const char *server_n = server; 672 pstring ipenv; 673 struct in_addr ip; 674 int tried_reverse = 0; 675 int port_try_first; 676 int port_try_next; 677 const char *username_used; 678 679 zero_ip(&ip); 680 ZERO_STRUCT(c); 681 682 if (server[0] == 0) { 683 errno = EPERM; 684 return NULL; 685 } 686 687 /* Look for a cached connection */ 688 srv = find_server(context, server, share, 689 workgroup, username, password); 690 691 /* 692 * If we found a connection and we're only allowed one share per 693 * server... 694 */ 695 if (srv && *share != '\0' && context->options.one_share_per_server) { 696 697 /* 698 * ... then if there's no current connection to the share, 699 * connect to it. find_server(), or rather the function 700 * pointed to by context->callbacks.get_cached_srv_fn which 701 * was called by find_server(), will have issued a tree 702 * disconnect if the requested share is not the same as the 703 * one that was already connected. 704 */ 705 if (srv->cli->cnum == (uint16) -1) { 706 /* Ensure we have accurate auth info */ 707 if (context->internal->_auth_fn_with_context != NULL) { 708 context->internal->_auth_fn_with_context( 709 context, 710 server, share, 711 workgroup, sizeof(fstring), 712 username, sizeof(fstring), 713 password, sizeof(fstring)); 714 } else { 715 context->callbacks.auth_fn( 716 server, share, 717 workgroup, sizeof(fstring), 718 username, sizeof(fstring), 719 password, sizeof(fstring)); 720 } 721 722 if (! cli_send_tconX(srv->cli, share, "?????", 723 password, strlen(password)+1)) { 724 725 errno = smbc_errno(context, srv->cli); 726 cli_shutdown(srv->cli); 727 srv->cli = NULL; 728 context->callbacks.remove_cached_srv_fn(context, 729 srv); 730 srv = NULL; 731 } 732 733 /* 734 * Regenerate the dev value since it's based on both 735 * server and share 736 */ 737 if (srv) { 738 srv->dev = (dev_t)(str_checksum(server) ^ 739 str_checksum(share)); 740 } 741 } 742 } 743 744 /* If we have a connection... */ 745 if (srv) { 746 747 /* ... then we're done here. Give 'em what they came for. */ 748 return srv; 749 } 750 751 /* If we're not asked to connect when a connection doesn't exist... */ 752 if (! connect_if_not_found) { 753 /* ... then we're done here. */ 754 return NULL; 755 } 756 757 make_nmb_name(&calling, context->netbios_name, 0x0); 758 make_nmb_name(&called , server, 0x20); 759 760 DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server)); 761 762 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); 763 764 again: 765 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); 766 767 zero_ip(&ip); 768 769 /* have to open a new connection */ 770 if ((c = cli_initialise()) == NULL) { 771 errno = ENOMEM; 772 return NULL; 773 } 774 775 if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) { 776 c->use_kerberos = True; 777 } 778 if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { 779 c->fallback_after_kerberos = True; 780 } 781 782 c->timeout = context->timeout; 783 784 /* 785 * Force use of port 139 for first try if share is $IPC, empty, or 786 * null, so browse lists can work 787 */ 788 if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) { 789 port_try_first = 139; 790 port_try_next = 445; 791 } else { 792 port_try_first = 445; 793 port_try_next = 139; 794 } 795 796 c->port = port_try_first; 797 798 if (!cli_connect(c, server_n, &ip)) { 799 800 /* First connection attempt failed. Try alternate port. */ 801 c->port = port_try_next; 802 803 if (!cli_connect(c, server_n, &ip)) { 804 cli_shutdown(c); 805 errno = ETIMEDOUT; 806 return NULL; 807 } 808 } 809 810 if (!cli_session_request(c, &calling, &called)) { 811 cli_shutdown(c); 812 if (strcmp(called.name, "*SMBSERVER")) { 813 make_nmb_name(&called , "*SMBSERVER", 0x20); 814 goto again; 815 } else { /* Try one more time, but ensure we don't loop */ 816 817 /* Only try this if server is an IP address ... */ 818 819 if (is_ipaddress(server) && !tried_reverse) { 820 fstring remote_name; 821 struct in_addr rem_ip; 822 823 if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) { 824 DEBUG(4, ("Could not convert IP address " 825 "%s to struct in_addr\n", server)); 826 errno = ETIMEDOUT; 827 return NULL; 828 } 829 830 tried_reverse++; /* Yuck */ 831 832 if (name_status_find("*", 0, 0, rem_ip, remote_name)) { 833 make_nmb_name(&called, remote_name, 0x20); 834 goto again; 835 } 836 } 837 } 838 errno = ETIMEDOUT; 839 return NULL; 840 } 841 842 DEBUG(4,(" session request ok\n")); 843 844 if (!cli_negprot(c)) { 845 cli_shutdown(c); 846 errno = ETIMEDOUT; 847 return NULL; 848 } 849 850 username_used = username; 851 852 if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, 853 password, strlen(password), 854 password, strlen(password), 855 workgroup))) { 856 857 /* Failed. Try an anonymous login, if allowed by flags. */ 858 username_used = ""; 859 860 if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || 861 !NT_STATUS_IS_OK(cli_session_setup(c, username_used, 862 password, 1, 863 password, 0, 864 workgroup))) { 865 866 cli_shutdown(c); 867 errno = EPERM; 868 return NULL; 869 } 870 } 871 872 DEBUG(4,(" session setup ok\n")); 873 874 if (!cli_send_tconX(c, share, "?????", 875 password, strlen(password)+1)) { 876 errno = smbc_errno(context, c); 877 cli_shutdown(c); 878 return NULL; 879 } 880 881 DEBUG(4,(" tconx ok\n")); 882 883 /* 884 * Ok, we have got a nice connection 885 * Let's allocate a server structure. 886 */ 887 888 srv = SMB_MALLOC_P(SMBCSRV); 889 if (!srv) { 890 errno = ENOMEM; 891 goto failed; 892 } 893 894 ZERO_STRUCTP(srv); 895 srv->cli = c; 896 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); 897 srv->no_pathinfo = False; 898 srv->no_pathinfo2 = False; 899 srv->no_nt_session = False; 900 901 /* now add it to the cache (internal or external) */ 902 /* Let the cache function set errno if it wants to */ 903 errno = 0; 904 if (context->callbacks.add_cached_srv_fn(context, srv, server, share, workgroup, username)) { 905 int saved_errno = errno; 906 DEBUG(3, (" Failed to add server to cache\n")); 907 errno = saved_errno; 908 if (errno == 0) { 909 errno = ENOMEM; 910 } 911 goto failed; 912 } 913 914 DEBUG(2, ("Server connect ok: //%s/%s: %p\n", 915 server, share, srv)); 916 917 DLIST_ADD(context->internal->_servers, srv); 918 return srv; 919 920 failed: 921 cli_shutdown(c); 922 if (!srv) { 923 return NULL; 924 } 925 926 SAFE_FREE(srv); 927 return NULL; 928} 929 930/* 931 * Connect to a server for getting/setting attributes, possibly on an existing 932 * connection. This works similarly to smbc_server(). 933 */ 934SMBCSRV * 935smbc_attr_server(SMBCCTX *context, 936 const char *server, 937 const char *share, 938 fstring workgroup, 939 fstring username, 940 fstring password, 941 POLICY_HND *pol) 942{ 943 int flags; 944 struct in_addr ip; 945 struct cli_state *ipc_cli; 946 struct rpc_pipe_client *pipe_hnd; 947 NTSTATUS nt_status; 948 SMBCSRV *ipc_srv=NULL; 949 950 /* 951 * See if we've already created this special connection. Reference 952 * our "special" share name '*IPC$', which is an impossible real share 953 * name due to the leading asterisk. 954 */ 955 ipc_srv = find_server(context, server, "*IPC$", 956 workgroup, username, password); 957 if (!ipc_srv) { 958 959 /* We didn't find a cached connection. Get the password */ 960 if (*password == '\0') { 961 /* ... then retrieve it now. */ 962 if (context->internal->_auth_fn_with_context != NULL) { 963 context->internal->_auth_fn_with_context( 964 context, 965 server, share, 966 workgroup, sizeof(fstring), 967 username, sizeof(fstring), 968 password, sizeof(fstring)); 969 } else { 970 context->callbacks.auth_fn( 971 server, share, 972 workgroup, sizeof(fstring), 973 username, sizeof(fstring), 974 password, sizeof(fstring)); 975 } 976 } 977 978 flags = 0; 979 if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) { 980 flags |= CLI_FULL_CONNECTION_USE_KERBEROS; 981 } 982 983 zero_ip(&ip); 984 nt_status = cli_full_connection(&ipc_cli, 985 global_myname(), server, 986 &ip, 0, "IPC$", "?????", 987 username, workgroup, 988 password, flags, 989 Undefined, NULL); 990 if (! NT_STATUS_IS_OK(nt_status)) { 991 DEBUG(1,("cli_full_connection failed! (%s)\n", 992 nt_errstr(nt_status))); 993 errno = ENOTSUP; 994 return NULL; 995 } 996 997 ipc_srv = SMB_MALLOC_P(SMBCSRV); 998 if (!ipc_srv) { 999 errno = ENOMEM; 1000 cli_shutdown(ipc_cli); 1001 return NULL; 1002 } 1003 1004 ZERO_STRUCTP(ipc_srv); 1005 ipc_srv->cli = ipc_cli; 1006 1007 if (pol) { 1008 pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli, 1009 PI_LSARPC, 1010 &nt_status); 1011 if (!pipe_hnd) { 1012 DEBUG(1, ("cli_nt_session_open fail!\n")); 1013 errno = ENOTSUP; 1014 cli_shutdown(ipc_srv->cli); 1015 free(ipc_srv); 1016 return NULL; 1017 } 1018 1019 /* 1020 * Some systems don't support 1021 * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000 1022 * so we might as well do it too. 1023 */ 1024 1025 nt_status = rpccli_lsa_open_policy( 1026 pipe_hnd, 1027 ipc_srv->cli->mem_ctx, 1028 True, 1029 GENERIC_EXECUTE_ACCESS, 1030 pol); 1031 1032 if (!NT_STATUS_IS_OK(nt_status)) { 1033 errno = smbc_errno(context, ipc_srv->cli); 1034 cli_shutdown(ipc_srv->cli); 1035 return NULL; 1036 } 1037 } 1038 1039 /* now add it to the cache (internal or external) */ 1040 1041 errno = 0; /* let cache function set errno if it likes */ 1042 if (context->callbacks.add_cached_srv_fn(context, ipc_srv, 1043 server, 1044 "*IPC$", 1045 workgroup, 1046 username)) { 1047 DEBUG(3, (" Failed to add server to cache\n")); 1048 if (errno == 0) { 1049 errno = ENOMEM; 1050 } 1051 cli_shutdown(ipc_srv->cli); 1052 free(ipc_srv); 1053 return NULL; 1054 } 1055 1056 DLIST_ADD(context->internal->_servers, ipc_srv); 1057 } 1058 1059 return ipc_srv; 1060} 1061 1062/* 1063 * Routine to open() a file ... 1064 */ 1065 1066static SMBCFILE * 1067smbc_open_ctx(SMBCCTX *context, 1068 const char *fname, 1069 int flags, 1070 mode_t mode) 1071{ 1072 fstring server, share, user, password, workgroup; 1073 pstring path; 1074 pstring targetpath; 1075 struct cli_state *targetcli; 1076 SMBCSRV *srv = NULL; 1077 SMBCFILE *file = NULL; 1078 int fd; 1079 1080 if (!context || !context->internal || 1081 !context->internal->_initialized) { 1082 1083 errno = EINVAL; /* Best I can think of ... */ 1084 return NULL; 1085 1086 } 1087 1088 if (!fname) { 1089 1090 errno = EINVAL; 1091 return NULL; 1092 1093 } 1094 1095 if (smbc_parse_path(context, fname, 1096 workgroup, sizeof(workgroup), 1097 server, sizeof(server), 1098 share, sizeof(share), 1099 path, sizeof(path), 1100 user, sizeof(user), 1101 password, sizeof(password), 1102 NULL, 0)) { 1103 errno = EINVAL; 1104 return NULL; 1105 } 1106 1107 if (user[0] == (char)0) fstrcpy(user, context->user); 1108 1109 srv = smbc_server(context, True, 1110 server, share, workgroup, user, password); 1111 1112 if (!srv) { 1113 1114 if (errno == EPERM) errno = EACCES; 1115 return NULL; /* smbc_server sets errno */ 1116 1117 } 1118 1119 /* Hmmm, the test for a directory is suspect here ... FIXME */ 1120 1121 if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') { 1122 1123 fd = -1; 1124 1125 } 1126 else { 1127 1128 file = SMB_MALLOC_P(SMBCFILE); 1129 1130 if (!file) { 1131 1132 errno = ENOMEM; 1133 return NULL; 1134 1135 } 1136 1137 ZERO_STRUCTP(file); 1138 1139 /*d_printf(">>>open: resolving %s\n", path);*/ 1140 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) 1141 { 1142 d_printf("Could not resolve %s\n", path); 1143 SAFE_FREE(file); 1144 return NULL; 1145 } 1146 /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ 1147 1148 if ((fd = cli_open(targetcli, targetpath, flags, 1149 context->internal->_share_mode)) < 0) { 1150 1151 /* Handle the error ... */ 1152 1153 SAFE_FREE(file); 1154 errno = smbc_errno(context, targetcli); 1155 return NULL; 1156 1157 } 1158 1159 /* Fill in file struct */ 1160 1161 file->cli_fd = fd; 1162 file->fname = SMB_STRDUP(fname); 1163 file->srv = srv; 1164 file->offset = 0; 1165 file->file = True; 1166 1167 DLIST_ADD(context->internal->_files, file); 1168 1169 /* 1170 * If the file was opened in O_APPEND mode, all write 1171 * operations should be appended to the file. To do that, 1172 * though, using this protocol, would require a getattrE() 1173 * call for each and every write, to determine where the end 1174 * of the file is. (There does not appear to be an append flag 1175 * in the protocol.) Rather than add all of that overhead of 1176 * retrieving the current end-of-file offset prior to each 1177 * write operation, we'll assume that most append operations 1178 * will continuously write, so we'll just set the offset to 1179 * the end of the file now and hope that's adequate. 1180 * 1181 * Note to self: If this proves inadequate, and O_APPEND 1182 * should, in some cases, be forced for each write, add a 1183 * field in the context options structure, for 1184 * "strict_append_mode" which would select between the current 1185 * behavior (if FALSE) or issuing a getattrE() prior to each 1186 * write and forcing the write to the end of the file (if 1187 * TRUE). Adding that capability will likely require adding 1188 * an "append" flag into the _SMBCFILE structure to track 1189 * whether a file was opened in O_APPEND mode. -- djl 1190 */ 1191 if (flags & O_APPEND) { 1192 if (smbc_lseek_ctx(context, file, 0, SEEK_END) < 0) { 1193 (void) smbc_close_ctx(context, file); 1194 errno = ENXIO; 1195 return NULL; 1196 } 1197 } 1198 1199 return file; 1200 1201 } 1202 1203 /* Check if opendir needed ... */ 1204 1205 if (fd == -1) { 1206 int eno = 0; 1207 1208 eno = smbc_errno(context, srv->cli); 1209 file = context->opendir(context, fname); 1210 if (!file) errno = eno; 1211 return file; 1212 1213 } 1214 1215 errno = EINVAL; /* FIXME, correct errno ? */ 1216 return NULL; 1217 1218} 1219 1220/* 1221 * Routine to create a file 1222 */ 1223 1224static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */ 1225 1226static SMBCFILE * 1227smbc_creat_ctx(SMBCCTX *context, 1228 const char *path, 1229 mode_t mode) 1230{ 1231 1232 if (!context || !context->internal || 1233 !context->internal->_initialized) { 1234 1235 errno = EINVAL; 1236 return NULL; 1237 1238 } 1239 1240 return smbc_open_ctx(context, path, creat_bits, mode); 1241} 1242 1243/* 1244 * Routine to read() a file ... 1245 */ 1246 1247static ssize_t 1248smbc_read_ctx(SMBCCTX *context, 1249 SMBCFILE *file, 1250 void *buf, 1251 size_t count) 1252{ 1253 int ret; 1254 fstring server, share, user, password; 1255 pstring path, targetpath; 1256 struct cli_state *targetcli; 1257 1258 /* 1259 * offset: 1260 * 1261 * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) -- 1262 * appears to pass file->offset (which is type off_t) differently than 1263 * a local variable of type off_t. Using local variable "offset" in 1264 * the call to cli_read() instead of file->offset fixes a problem 1265 * retrieving data at an offset greater than 4GB. 1266 */ 1267 off_t offset; 1268 1269 if (!context || !context->internal || 1270 !context->internal->_initialized) { 1271 1272 errno = EINVAL; 1273 return -1; 1274 1275 } 1276 1277 DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count)); 1278 1279 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1280 1281 errno = EBADF; 1282 return -1; 1283 1284 } 1285 1286 offset = file->offset; 1287 1288 /* Check that the buffer exists ... */ 1289 1290 if (buf == NULL) { 1291 1292 errno = EINVAL; 1293 return -1; 1294 1295 } 1296 1297 /*d_printf(">>>read: parsing %s\n", file->fname);*/ 1298 if (smbc_parse_path(context, file->fname, 1299 NULL, 0, 1300 server, sizeof(server), 1301 share, sizeof(share), 1302 path, sizeof(path), 1303 user, sizeof(user), 1304 password, sizeof(password), 1305 NULL, 0)) { 1306 errno = EINVAL; 1307 return -1; 1308 } 1309 1310 /*d_printf(">>>read: resolving %s\n", path);*/ 1311 if (!cli_resolve_path("", file->srv->cli, path, 1312 &targetcli, targetpath)) 1313 { 1314 d_printf("Could not resolve %s\n", path); 1315 return -1; 1316 } 1317 /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ 1318 1319 ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count); 1320 1321 if (ret < 0) { 1322 1323 errno = smbc_errno(context, targetcli); 1324 return -1; 1325 1326 } 1327 1328 file->offset += ret; 1329 1330 DEBUG(4, (" --> %d\n", ret)); 1331 1332 return ret; /* Success, ret bytes of data ... */ 1333 1334} 1335 1336/* 1337 * Routine to write() a file ... 1338 */ 1339 1340static ssize_t 1341smbc_write_ctx(SMBCCTX *context, 1342 SMBCFILE *file, 1343 void *buf, 1344 size_t count) 1345{ 1346 int ret; 1347 off_t offset; 1348 fstring server, share, user, password; 1349 pstring path, targetpath; 1350 struct cli_state *targetcli; 1351 1352 /* First check all pointers before dereferencing them */ 1353 1354 if (!context || !context->internal || 1355 !context->internal->_initialized) { 1356 1357 errno = EINVAL; 1358 return -1; 1359 1360 } 1361 1362 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1363 1364 errno = EBADF; 1365 return -1; 1366 1367 } 1368 1369 /* Check that the buffer exists ... */ 1370 1371 if (buf == NULL) { 1372 1373 errno = EINVAL; 1374 return -1; 1375 1376 } 1377 1378 offset = file->offset; /* See "offset" comment in smbc_read_ctx() */ 1379 1380 /*d_printf(">>>write: parsing %s\n", file->fname);*/ 1381 if (smbc_parse_path(context, file->fname, 1382 NULL, 0, 1383 server, sizeof(server), 1384 share, sizeof(share), 1385 path, sizeof(path), 1386 user, sizeof(user), 1387 password, sizeof(password), 1388 NULL, 0)) { 1389 errno = EINVAL; 1390 return -1; 1391 } 1392 1393 /*d_printf(">>>write: resolving %s\n", path);*/ 1394 if (!cli_resolve_path("", file->srv->cli, path, 1395 &targetcli, targetpath)) 1396 { 1397 d_printf("Could not resolve %s\n", path); 1398 return -1; 1399 } 1400 /*d_printf(">>>write: resolved path as %s\n", targetpath);*/ 1401 1402 1403 ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count); 1404 1405 if (ret <= 0) { 1406 1407 errno = smbc_errno(context, targetcli); 1408 return -1; 1409 1410 } 1411 1412 file->offset += ret; 1413 1414 return ret; /* Success, 0 bytes of data ... */ 1415} 1416 1417/* 1418 * Routine to close() a file ... 1419 */ 1420 1421static int 1422smbc_close_ctx(SMBCCTX *context, 1423 SMBCFILE *file) 1424{ 1425 SMBCSRV *srv; 1426 fstring server, share, user, password; 1427 pstring path, targetpath; 1428 struct cli_state *targetcli; 1429 1430 if (!context || !context->internal || 1431 !context->internal->_initialized) { 1432 1433 errno = EINVAL; 1434 return -1; 1435 1436 } 1437 1438 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1439 1440 errno = EBADF; 1441 return -1; 1442 1443 } 1444 1445 /* IS a dir ... */ 1446 if (!file->file) { 1447 1448 return context->closedir(context, file); 1449 1450 } 1451 1452 /*d_printf(">>>close: parsing %s\n", file->fname);*/ 1453 if (smbc_parse_path(context, file->fname, 1454 NULL, 0, 1455 server, sizeof(server), 1456 share, sizeof(share), 1457 path, sizeof(path), 1458 user, sizeof(user), 1459 password, sizeof(password), 1460 NULL, 0)) { 1461 errno = EINVAL; 1462 return -1; 1463 } 1464 1465 /*d_printf(">>>close: resolving %s\n", path);*/ 1466 if (!cli_resolve_path("", file->srv->cli, path, 1467 &targetcli, targetpath)) 1468 { 1469 d_printf("Could not resolve %s\n", path); 1470 return -1; 1471 } 1472 /*d_printf(">>>close: resolved path as %s\n", targetpath);*/ 1473 1474 if (!cli_close(targetcli, file->cli_fd)) { 1475 1476 DEBUG(3, ("cli_close failed on %s. purging server.\n", 1477 file->fname)); 1478 /* Deallocate slot and remove the server 1479 * from the server cache if unused */ 1480 errno = smbc_errno(context, targetcli); 1481 srv = file->srv; 1482 DLIST_REMOVE(context->internal->_files, file); 1483 SAFE_FREE(file->fname); 1484 SAFE_FREE(file); 1485 context->callbacks.remove_unused_server_fn(context, srv); 1486 1487 return -1; 1488 1489 } 1490 1491 DLIST_REMOVE(context->internal->_files, file); 1492 SAFE_FREE(file->fname); 1493 SAFE_FREE(file); 1494 1495 return 0; 1496} 1497 1498/* 1499 * Get info from an SMB server on a file. Use a qpathinfo call first 1500 * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo 1501 */ 1502static BOOL 1503smbc_getatr(SMBCCTX * context, 1504 SMBCSRV *srv, 1505 char *path, 1506 uint16 *mode, 1507 SMB_OFF_T *size, 1508 struct timespec *create_time_ts, 1509 struct timespec *access_time_ts, 1510 struct timespec *write_time_ts, 1511 struct timespec *change_time_ts, 1512 SMB_INO_T *ino) 1513{ 1514 pstring fixedpath; 1515 pstring targetpath; 1516 struct cli_state *targetcli; 1517 time_t write_time; 1518 1519 if (!context || !context->internal || 1520 !context->internal->_initialized) { 1521 1522 errno = EINVAL; 1523 return -1; 1524 1525 } 1526 1527 /* path fixup for . and .. */ 1528 if (strequal(path, ".") || strequal(path, "..")) 1529 pstrcpy(fixedpath, "\\"); 1530 else 1531 { 1532 pstrcpy(fixedpath, path); 1533 trim_string(fixedpath, NULL, "\\.."); 1534 trim_string(fixedpath, NULL, "\\."); 1535 } 1536 DEBUG(4,("smbc_getatr: sending qpathinfo\n")); 1537 1538 if (!cli_resolve_path( "", srv->cli, fixedpath, &targetcli, targetpath)) 1539 { 1540 d_printf("Couldn't resolve %s\n", path); 1541 return False; 1542 } 1543 1544 if (!srv->no_pathinfo2 && 1545 cli_qpathinfo2(targetcli, targetpath, 1546 create_time_ts, 1547 access_time_ts, 1548 write_time_ts, 1549 change_time_ts, 1550 size, mode, ino)) { 1551 return True; 1552 } 1553 1554 /* if this is NT then don't bother with the getatr */ 1555 if (targetcli->capabilities & CAP_NT_SMBS) { 1556 errno = EPERM; 1557 return False; 1558 } 1559 1560 if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) { 1561 1562 struct timespec w_time_ts; 1563 1564 w_time_ts = convert_time_t_to_timespec(write_time); 1565 1566 if (write_time_ts != NULL) { 1567 *write_time_ts = w_time_ts; 1568 } 1569 1570 if (create_time_ts != NULL) { 1571 *create_time_ts = w_time_ts; 1572 } 1573 1574 if (access_time_ts != NULL) { 1575 *access_time_ts = w_time_ts; 1576 } 1577 1578 if (change_time_ts != NULL) { 1579 *change_time_ts = w_time_ts; 1580 } 1581 1582 srv->no_pathinfo2 = True; 1583 return True; 1584 } 1585 1586 errno = EPERM; 1587 return False; 1588 1589} 1590 1591/* 1592 * Set file info on an SMB server. Use setpathinfo call first. If that 1593 * fails, use setattrE.. 1594 * 1595 * Access and modification time parameters are always used and must be 1596 * provided. Create time, if zero, will be determined from the actual create 1597 * time of the file. If non-zero, the create time will be set as well. 1598 * 1599 * "mode" (attributes) parameter may be set to -1 if it is not to be set. 1600 */ 1601static BOOL 1602smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, 1603 time_t create_time, 1604 time_t access_time, 1605 time_t write_time, 1606 time_t change_time, 1607 uint16 mode) 1608{ 1609 int fd; 1610 int ret; 1611 1612 /* 1613 * First, try setpathinfo (if qpathinfo succeeded), for it is the 1614 * modern function for "new code" to be using, and it works given a 1615 * filename rather than requiring that the file be opened to have its 1616 * attributes manipulated. 1617 */ 1618 if (srv->no_pathinfo || 1619 ! cli_setpathinfo(srv->cli, path, 1620 create_time, 1621 access_time, 1622 write_time, 1623 change_time, 1624 mode)) { 1625 1626 /* 1627 * setpathinfo is not supported; go to plan B. 1628 * 1629 * cli_setatr() does not work on win98, and it also doesn't 1630 * support setting the access time (only the modification 1631 * time), so in all cases, we open the specified file and use 1632 * cli_setattrE() which should work on all OS versions, and 1633 * supports both times. 1634 */ 1635 1636 /* Don't try {q,set}pathinfo() again, with this server */ 1637 srv->no_pathinfo = True; 1638 1639 /* Open the file */ 1640 if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) { 1641 1642 errno = smbc_errno(context, srv->cli); 1643 return -1; 1644 } 1645 1646 /* Set the new attributes */ 1647 ret = cli_setattrE(srv->cli, fd, 1648 change_time, 1649 access_time, 1650 write_time); 1651 1652 /* Close the file */ 1653 cli_close(srv->cli, fd); 1654 1655 /* 1656 * Unfortunately, setattrE() doesn't have a provision for 1657 * setting the access mode (attributes). We'll have to try 1658 * cli_setatr() for that, and with only this parameter, it 1659 * seems to work on win98. 1660 */ 1661 if (ret && mode != (uint16) -1) { 1662 ret = cli_setatr(srv->cli, path, mode, 0); 1663 } 1664 1665 if (! ret) { 1666 errno = smbc_errno(context, srv->cli); 1667 return False; 1668 } 1669 } 1670 1671 return True; 1672} 1673 1674 /* 1675 * Routine to unlink() a file 1676 */ 1677 1678static int 1679smbc_unlink_ctx(SMBCCTX *context, 1680 const char *fname) 1681{ 1682 fstring server, share, user, password, workgroup; 1683 pstring path, targetpath; 1684 struct cli_state *targetcli; 1685 SMBCSRV *srv = NULL; 1686 1687 if (!context || !context->internal || 1688 !context->internal->_initialized) { 1689 1690 errno = EINVAL; /* Best I can think of ... */ 1691 return -1; 1692 1693 } 1694 1695 if (!fname) { 1696 1697 errno = EINVAL; 1698 return -1; 1699 1700 } 1701 1702 if (smbc_parse_path(context, fname, 1703 workgroup, sizeof(workgroup), 1704 server, sizeof(server), 1705 share, sizeof(share), 1706 path, sizeof(path), 1707 user, sizeof(user), 1708 password, sizeof(password), 1709 NULL, 0)) { 1710 errno = EINVAL; 1711 return -1; 1712 } 1713 1714 if (user[0] == (char)0) fstrcpy(user, context->user); 1715 1716 srv = smbc_server(context, True, 1717 server, share, workgroup, user, password); 1718 1719 if (!srv) { 1720 1721 return -1; /* smbc_server sets errno */ 1722 1723 } 1724 1725 /*d_printf(">>>unlink: resolving %s\n", path);*/ 1726 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) 1727 { 1728 d_printf("Could not resolve %s\n", path); 1729 return -1; 1730 } 1731 /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/ 1732 1733 if (!cli_unlink(targetcli, targetpath)) { 1734 1735 errno = smbc_errno(context, targetcli); 1736 1737 if (errno == EACCES) { /* Check if the file is a directory */ 1738 1739 int saverr = errno; 1740 SMB_OFF_T size = 0; 1741 uint16 mode = 0; 1742 struct timespec write_time_ts; 1743 struct timespec access_time_ts; 1744 struct timespec change_time_ts; 1745 SMB_INO_T ino = 0; 1746 1747 if (!smbc_getatr(context, srv, path, &mode, &size, 1748 NULL, 1749 &access_time_ts, 1750 &write_time_ts, 1751 &change_time_ts, 1752 &ino)) { 1753 1754 /* Hmmm, bad error ... What? */ 1755 1756 errno = smbc_errno(context, targetcli); 1757 return -1; 1758 1759 } 1760 else { 1761 1762 if (IS_DOS_DIR(mode)) 1763 errno = EISDIR; 1764 else 1765 errno = saverr; /* Restore this */ 1766 1767 } 1768 } 1769 1770 return -1; 1771 1772 } 1773 1774 return 0; /* Success ... */ 1775 1776} 1777 1778/* 1779 * Routine to rename() a file 1780 */ 1781 1782static int 1783smbc_rename_ctx(SMBCCTX *ocontext, 1784 const char *oname, 1785 SMBCCTX *ncontext, 1786 const char *nname) 1787{ 1788 fstring server1; 1789 fstring share1; 1790 fstring server2; 1791 fstring share2; 1792 fstring user1; 1793 fstring user2; 1794 fstring password1; 1795 fstring password2; 1796 fstring workgroup; 1797 pstring path1; 1798 pstring path2; 1799 pstring targetpath1; 1800 pstring targetpath2; 1801 struct cli_state *targetcli1; 1802 struct cli_state *targetcli2; 1803 SMBCSRV *srv = NULL; 1804 1805 if (!ocontext || !ncontext || 1806 !ocontext->internal || !ncontext->internal || 1807 !ocontext->internal->_initialized || 1808 !ncontext->internal->_initialized) { 1809 1810 errno = EINVAL; /* Best I can think of ... */ 1811 return -1; 1812 1813 } 1814 1815 if (!oname || !nname) { 1816 1817 errno = EINVAL; 1818 return -1; 1819 1820 } 1821 1822 DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname)); 1823 1824 smbc_parse_path(ocontext, oname, 1825 workgroup, sizeof(workgroup), 1826 server1, sizeof(server1), 1827 share1, sizeof(share1), 1828 path1, sizeof(path1), 1829 user1, sizeof(user1), 1830 password1, sizeof(password1), 1831 NULL, 0); 1832 1833 if (user1[0] == (char)0) fstrcpy(user1, ocontext->user); 1834 1835 smbc_parse_path(ncontext, nname, 1836 NULL, 0, 1837 server2, sizeof(server2), 1838 share2, sizeof(share2), 1839 path2, sizeof(path2), 1840 user2, sizeof(user2), 1841 password2, sizeof(password2), 1842 NULL, 0); 1843 1844 if (user2[0] == (char)0) fstrcpy(user2, ncontext->user); 1845 1846 if (strcmp(server1, server2) || strcmp(share1, share2) || 1847 strcmp(user1, user2)) { 1848 1849 /* Can't rename across file systems, or users?? */ 1850 1851 errno = EXDEV; 1852 return -1; 1853 1854 } 1855 1856 srv = smbc_server(ocontext, True, 1857 server1, share1, workgroup, user1, password1); 1858 if (!srv) { 1859 1860 return -1; 1861 1862 } 1863 1864 /*d_printf(">>>rename: resolving %s\n", path1);*/ 1865 if (!cli_resolve_path( "", srv->cli, path1, &targetcli1, targetpath1)) 1866 { 1867 d_printf("Could not resolve %s\n", path1); 1868 return -1; 1869 } 1870 /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/ 1871 /*d_printf(">>>rename: resolving %s\n", path2);*/ 1872 if (!cli_resolve_path( "", srv->cli, path2, &targetcli2, targetpath2)) 1873 { 1874 d_printf("Could not resolve %s\n", path2); 1875 return -1; 1876 } 1877 /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/ 1878 1879 if (strcmp(targetcli1->desthost, targetcli2->desthost) || 1880 strcmp(targetcli1->share, targetcli2->share)) 1881 { 1882 /* can't rename across file systems */ 1883 1884 errno = EXDEV; 1885 return -1; 1886 } 1887 1888 if (!cli_rename(targetcli1, targetpath1, targetpath2)) { 1889 int eno = smbc_errno(ocontext, targetcli1); 1890 1891 if (eno != EEXIST || 1892 !cli_unlink(targetcli1, targetpath2) || 1893 !cli_rename(targetcli1, targetpath1, targetpath2)) { 1894 1895 errno = eno; 1896 return -1; 1897 1898 } 1899 } 1900 1901 return 0; /* Success */ 1902 1903} 1904 1905/* 1906 * A routine to lseek() a file 1907 */ 1908 1909static off_t 1910smbc_lseek_ctx(SMBCCTX *context, 1911 SMBCFILE *file, 1912 off_t offset, 1913 int whence) 1914{ 1915 SMB_OFF_T size; 1916 fstring server, share, user, password; 1917 pstring path, targetpath; 1918 struct cli_state *targetcli; 1919 1920 if (!context || !context->internal || 1921 !context->internal->_initialized) { 1922 1923 errno = EINVAL; 1924 return -1; 1925 1926 } 1927 1928 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1929 1930 errno = EBADF; 1931 return -1; 1932 1933 } 1934 1935 if (!file->file) { 1936 1937 errno = EINVAL; 1938 return -1; /* Can't lseek a dir ... */ 1939 1940 } 1941 1942 switch (whence) { 1943 case SEEK_SET: 1944 file->offset = offset; 1945 break; 1946 1947 case SEEK_CUR: 1948 file->offset += offset; 1949 break; 1950 1951 case SEEK_END: 1952 /*d_printf(">>>lseek: parsing %s\n", file->fname);*/ 1953 if (smbc_parse_path(context, file->fname, 1954 NULL, 0, 1955 server, sizeof(server), 1956 share, sizeof(share), 1957 path, sizeof(path), 1958 user, sizeof(user), 1959 password, sizeof(password), 1960 NULL, 0)) { 1961 1962 errno = EINVAL; 1963 return -1; 1964 } 1965 1966 /*d_printf(">>>lseek: resolving %s\n", path);*/ 1967 if (!cli_resolve_path("", file->srv->cli, path, 1968 &targetcli, targetpath)) 1969 { 1970 d_printf("Could not resolve %s\n", path); 1971 return -1; 1972 } 1973 /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/ 1974 1975 if (!cli_qfileinfo(targetcli, file->cli_fd, NULL, 1976 &size, NULL, NULL, NULL, NULL, NULL)) 1977 { 1978 SMB_OFF_T b_size = size; 1979 if (!cli_getattrE(targetcli, file->cli_fd, 1980 NULL, &b_size, NULL, NULL, NULL)) 1981 { 1982 errno = EINVAL; 1983 return -1; 1984 } else 1985 size = b_size; 1986 } 1987 file->offset = size + offset; 1988 break; 1989 1990 default: 1991 errno = EINVAL; 1992 break; 1993 1994 } 1995 1996 return file->offset; 1997 1998} 1999 2000/* 2001 * Generate an inode number from file name for those things that need it 2002 */ 2003 2004static ino_t 2005smbc_inode(SMBCCTX *context, 2006 const char *name) 2007{ 2008 2009 if (!context || !context->internal || 2010 !context->internal->_initialized) { 2011 2012 errno = EINVAL; 2013 return -1; 2014 2015 } 2016 2017 if (!*name) return 2; /* FIXME, why 2 ??? */ 2018 return (ino_t)str_checksum(name); 2019 2020} 2021 2022/* 2023 * Routine to put basic stat info into a stat structure ... Used by stat and 2024 * fstat below. 2025 */ 2026 2027static int 2028smbc_setup_stat(SMBCCTX *context, 2029 struct stat *st, 2030 char *fname, 2031 SMB_OFF_T size, 2032 int mode) 2033{ 2034 2035 st->st_mode = 0; 2036 2037 if (IS_DOS_DIR(mode)) { 2038 st->st_mode = SMBC_DIR_MODE; 2039 } else { 2040 st->st_mode = SMBC_FILE_MODE; 2041 } 2042 2043 if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR; 2044 if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP; 2045 if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH; 2046 if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR; 2047 2048 st->st_size = size; 2049#ifdef HAVE_STAT_ST_BLKSIZE 2050 st->st_blksize = 512; 2051#endif 2052#ifdef HAVE_STAT_ST_BLOCKS 2053 st->st_blocks = (size+511)/512; 2054#endif 2055 st->st_uid = getuid(); 2056 st->st_gid = getgid(); 2057 2058 if (IS_DOS_DIR(mode)) { 2059 st->st_nlink = 2; 2060 } else { 2061 st->st_nlink = 1; 2062 } 2063 2064 if (st->st_ino == 0) { 2065 st->st_ino = smbc_inode(context, fname); 2066 } 2067 2068 return True; /* FIXME: Is this needed ? */ 2069 2070} 2071 2072/* 2073 * Routine to stat a file given a name 2074 */ 2075 2076static int 2077smbc_stat_ctx(SMBCCTX *context, 2078 const char *fname, 2079 struct stat *st) 2080{ 2081 SMBCSRV *srv; 2082 fstring server; 2083 fstring share; 2084 fstring user; 2085 fstring password; 2086 fstring workgroup; 2087 pstring path; 2088 struct timespec write_time_ts; 2089 struct timespec access_time_ts; 2090 struct timespec change_time_ts; 2091 SMB_OFF_T size = 0; 2092 uint16 mode = 0; 2093 SMB_INO_T ino = 0; 2094 2095 if (!context || !context->internal || 2096 !context->internal->_initialized) { 2097 2098 errno = EINVAL; /* Best I can think of ... */ 2099 return -1; 2100 2101 } 2102 2103 if (!fname) { 2104 2105 errno = EINVAL; 2106 return -1; 2107 2108 } 2109 2110 DEBUG(4, ("smbc_stat(%s)\n", fname)); 2111 2112 if (smbc_parse_path(context, fname, 2113 workgroup, sizeof(workgroup), 2114 server, sizeof(server), 2115 share, sizeof(share), 2116 path, sizeof(path), 2117 user, sizeof(user), 2118 password, sizeof(password), 2119 NULL, 0)) { 2120 errno = EINVAL; 2121 return -1; 2122 } 2123 2124 if (user[0] == (char)0) fstrcpy(user, context->user); 2125 2126 srv = smbc_server(context, True, 2127 server, share, workgroup, user, password); 2128 2129 if (!srv) { 2130 return -1; /* errno set by smbc_server */ 2131 } 2132 2133 if (!smbc_getatr(context, srv, path, &mode, &size, 2134 NULL, 2135 &access_time_ts, 2136 &write_time_ts, 2137 &change_time_ts, 2138 &ino)) { 2139 2140 errno = smbc_errno(context, srv->cli); 2141 return -1; 2142 2143 } 2144 2145 st->st_ino = ino; 2146 2147 smbc_setup_stat(context, st, path, size, mode); 2148 2149 set_atimespec(st, access_time_ts); 2150 set_ctimespec(st, change_time_ts); 2151 set_mtimespec(st, write_time_ts); 2152 st->st_dev = srv->dev; 2153 2154 return 0; 2155 2156} 2157 2158/* 2159 * Routine to stat a file given an fd 2160 */ 2161 2162static int 2163smbc_fstat_ctx(SMBCCTX *context, 2164 SMBCFILE *file, 2165 struct stat *st) 2166{ 2167 struct timespec change_time_ts; 2168 struct timespec access_time_ts; 2169 struct timespec write_time_ts; 2170 SMB_OFF_T size; 2171 uint16 mode; 2172 fstring server; 2173 fstring share; 2174 fstring user; 2175 fstring password; 2176 pstring path; 2177 pstring targetpath; 2178 struct cli_state *targetcli; 2179 SMB_INO_T ino = 0; 2180 2181 if (!context || !context->internal || 2182 !context->internal->_initialized) { 2183 2184 errno = EINVAL; 2185 return -1; 2186 2187 } 2188 2189 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 2190 2191 errno = EBADF; 2192 return -1; 2193 2194 } 2195 2196 if (!file->file) { 2197 2198 return context->fstatdir(context, file, st); 2199 2200 } 2201 2202 /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ 2203 if (smbc_parse_path(context, file->fname, 2204 NULL, 0, 2205 server, sizeof(server), 2206 share, sizeof(share), 2207 path, sizeof(path), 2208 user, sizeof(user), 2209 password, sizeof(password), 2210 NULL, 0)) { 2211 errno = EINVAL; 2212 return -1; 2213 } 2214 2215 /*d_printf(">>>fstat: resolving %s\n", path);*/ 2216 if (!cli_resolve_path("", file->srv->cli, path, 2217 &targetcli, targetpath)) 2218 { 2219 d_printf("Could not resolve %s\n", path); 2220 return -1; 2221 } 2222 /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ 2223 2224 if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size, 2225 NULL, 2226 &access_time_ts, 2227 &write_time_ts, 2228 &change_time_ts, 2229 &ino)) { 2230 2231 time_t change_time, access_time, write_time; 2232 2233 if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size, 2234 &change_time, &access_time, &write_time)) { 2235 2236 errno = EINVAL; 2237 return -1; 2238 } 2239 2240 change_time_ts = convert_time_t_to_timespec(change_time); 2241 access_time_ts = convert_time_t_to_timespec(access_time); 2242 write_time_ts = convert_time_t_to_timespec(write_time); 2243 } 2244 2245 st->st_ino = ino; 2246 2247 smbc_setup_stat(context, st, file->fname, size, mode); 2248 2249 set_atimespec(st, access_time_ts); 2250 set_ctimespec(st, change_time_ts); 2251 set_mtimespec(st, write_time_ts); 2252 st->st_dev = file->srv->dev; 2253 2254 return 0; 2255 2256} 2257 2258/* 2259 * Routine to open a directory 2260 * We accept the URL syntax explained in smbc_parse_path(), above. 2261 */ 2262 2263static void 2264smbc_remove_dir(SMBCFILE *dir) 2265{ 2266 struct smbc_dir_list *d,*f; 2267 2268 d = dir->dir_list; 2269 while (d) { 2270 2271 f = d; d = d->next; 2272 2273 SAFE_FREE(f->dirent); 2274 SAFE_FREE(f); 2275 2276 } 2277 2278 dir->dir_list = dir->dir_end = dir->dir_next = NULL; 2279 2280} 2281 2282static int 2283add_dirent(SMBCFILE *dir, 2284 const char *name, 2285 const char *comment, 2286 uint32 type) 2287{ 2288 struct smbc_dirent *dirent; 2289 int size; 2290 int name_length = (name == NULL ? 0 : strlen(name)); 2291 int comment_len = (comment == NULL ? 0 : strlen(comment)); 2292 2293 /* 2294 * Allocate space for the dirent, which must be increased by the 2295 * size of the name and the comment and 1 each for the null terminator. 2296 */ 2297 2298 size = sizeof(struct smbc_dirent) + name_length + comment_len + 2; 2299 2300 dirent = (struct smbc_dirent *)SMB_MALLOC(size); 2301 2302 if (!dirent) { 2303 2304 dir->dir_error = ENOMEM; 2305 return -1; 2306 2307 } 2308 2309 ZERO_STRUCTP(dirent); 2310 2311 if (dir->dir_list == NULL) { 2312 2313 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list); 2314 if (!dir->dir_list) { 2315 2316 SAFE_FREE(dirent); 2317 dir->dir_error = ENOMEM; 2318 return -1; 2319 2320 } 2321 ZERO_STRUCTP(dir->dir_list); 2322 2323 dir->dir_end = dir->dir_next = dir->dir_list; 2324 } 2325 else { 2326 2327 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list); 2328 2329 if (!dir->dir_end->next) { 2330 2331 SAFE_FREE(dirent); 2332 dir->dir_error = ENOMEM; 2333 return -1; 2334 2335 } 2336 ZERO_STRUCTP(dir->dir_end->next); 2337 2338 dir->dir_end = dir->dir_end->next; 2339 } 2340 2341 dir->dir_end->next = NULL; 2342 dir->dir_end->dirent = dirent; 2343 2344 dirent->smbc_type = type; 2345 dirent->namelen = name_length; 2346 dirent->commentlen = comment_len; 2347 dirent->dirlen = size; 2348 2349 /* 2350 * dirent->namelen + 1 includes the null (no null termination needed) 2351 * Ditto for dirent->commentlen. 2352 * The space for the two null bytes was allocated. 2353 */ 2354 strncpy(dirent->name, (name?name:""), dirent->namelen + 1); 2355 dirent->comment = (char *)(&dirent->name + dirent->namelen + 1); 2356 strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1); 2357 2358 return 0; 2359 2360} 2361 2362static void 2363list_unique_wg_fn(const char *name, 2364 uint32 type, 2365 const char *comment, 2366 void *state) 2367{ 2368 SMBCFILE *dir = (SMBCFILE *)state; 2369 struct smbc_dir_list *dir_list; 2370 struct smbc_dirent *dirent; 2371 int dirent_type; 2372 int do_remove = 0; 2373 2374 dirent_type = dir->dir_type; 2375 2376 if (add_dirent(dir, name, comment, dirent_type) < 0) { 2377 2378 /* An error occurred, what do we do? */ 2379 /* FIXME: Add some code here */ 2380 } 2381 2382 /* Point to the one just added */ 2383 dirent = dir->dir_end->dirent; 2384 2385 /* See if this was a duplicate */ 2386 for (dir_list = dir->dir_list; 2387 dir_list != dir->dir_end; 2388 dir_list = dir_list->next) { 2389 if (! do_remove && 2390 strcmp(dir_list->dirent->name, dirent->name) == 0) { 2391 /* Duplicate. End end of list need to be removed. */ 2392 do_remove = 1; 2393 } 2394 2395 if (do_remove && dir_list->next == dir->dir_end) { 2396 /* Found the end of the list. Remove it. */ 2397 dir->dir_end = dir_list; 2398 free(dir_list->next); 2399 free(dirent); 2400 dir_list->next = NULL; 2401 break; 2402 } 2403 } 2404} 2405 2406static void 2407list_fn(const char *name, 2408 uint32 type, 2409 const char *comment, 2410 void *state) 2411{ 2412 SMBCFILE *dir = (SMBCFILE *)state; 2413 int dirent_type; 2414 2415 /* 2416 * We need to process the type a little ... 2417 * 2418 * Disk share = 0x00000000 2419 * Print share = 0x00000001 2420 * Comms share = 0x00000002 (obsolete?) 2421 * IPC$ share = 0x00000003 2422 * 2423 * administrative shares: 2424 * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000 2425 */ 2426 2427 if (dir->dir_type == SMBC_FILE_SHARE) { 2428 2429 switch (type) { 2430 case 0 | 0x80000000: 2431 case 0: 2432 dirent_type = SMBC_FILE_SHARE; 2433 break; 2434 2435 case 1: 2436 dirent_type = SMBC_PRINTER_SHARE; 2437 break; 2438 2439 case 2: 2440 dirent_type = SMBC_COMMS_SHARE; 2441 break; 2442 2443 case 3 | 0x80000000: 2444 case 3: 2445 dirent_type = SMBC_IPC_SHARE; 2446 break; 2447 2448 default: 2449 dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */ 2450 break; 2451 } 2452 } 2453 else { 2454 dirent_type = dir->dir_type; 2455 } 2456 2457 if (add_dirent(dir, name, comment, dirent_type) < 0) { 2458 2459 /* An error occurred, what do we do? */ 2460 /* FIXME: Add some code here */ 2461 2462 } 2463} 2464 2465static void 2466dir_list_fn(const char *mnt, 2467 file_info *finfo, 2468 const char *mask, 2469 void *state) 2470{ 2471 2472 if (add_dirent((SMBCFILE *)state, finfo->name, "", 2473 (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) { 2474 2475 /* Handle an error ... */ 2476 2477 /* FIXME: Add some code ... */ 2478 2479 } 2480 2481} 2482 2483static int 2484net_share_enum_rpc(struct cli_state *cli, 2485 void (*fn)(const char *name, 2486 uint32 type, 2487 const char *comment, 2488 void *state), 2489 void *state) 2490{ 2491 int i; 2492 WERROR result; 2493 ENUM_HND enum_hnd; 2494 uint32 info_level = 1; 2495 uint32 preferred_len = 0xffffffff; 2496 uint32 type; 2497 SRV_SHARE_INFO_CTR ctr; 2498 fstring name = ""; 2499 fstring comment = ""; 2500 void *mem_ctx; 2501 struct rpc_pipe_client *pipe_hnd; 2502 NTSTATUS nt_status; 2503 2504 /* Open the server service pipe */ 2505 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status); 2506 if (!pipe_hnd) { 2507 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n")); 2508 return -1; 2509 } 2510 2511 /* Allocate a context for parsing and for the entries in "ctr" */ 2512 mem_ctx = talloc_init("libsmbclient: net_share_enum_rpc"); 2513 if (mem_ctx == NULL) { 2514 DEBUG(0, ("out of memory for net_share_enum_rpc!\n")); 2515 cli_rpc_pipe_close(pipe_hnd); 2516 return -1; 2517 } 2518 2519 /* Issue the NetShareEnum RPC call and retrieve the response */ 2520 init_enum_hnd(&enum_hnd, 0); 2521 result = rpccli_srvsvc_net_share_enum(pipe_hnd, 2522 mem_ctx, 2523 info_level, 2524 &ctr, 2525 preferred_len, 2526 &enum_hnd); 2527 2528 /* Was it successful? */ 2529 if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) { 2530 /* Nope. Go clean up. */ 2531 goto done; 2532 } 2533 2534 /* For each returned entry... */ 2535 for (i = 0; i < ctr.num_entries; i++) { 2536 2537 /* pull out the share name */ 2538 rpcstr_pull_unistr2_fstring( 2539 name, &ctr.share.info1[i].info_1_str.uni_netname); 2540 2541 /* pull out the share's comment */ 2542 rpcstr_pull_unistr2_fstring( 2543 comment, &ctr.share.info1[i].info_1_str.uni_remark); 2544 2545 /* Get the type value */ 2546 type = ctr.share.info1[i].info_1.type; 2547 2548 /* Add this share to the list */ 2549 (*fn)(name, type, comment, state); 2550 } 2551 2552done: 2553 /* Close the server service pipe */ 2554 cli_rpc_pipe_close(pipe_hnd); 2555 2556 /* Free all memory which was allocated for this request */ 2557 TALLOC_FREE(mem_ctx); 2558 2559 /* Tell 'em if it worked */ 2560 return W_ERROR_IS_OK(result) ? 0 : -1; 2561} 2562 2563 2564 2565static SMBCFILE * 2566smbc_opendir_ctx(SMBCCTX *context, 2567 const char *fname) 2568{ 2569 int saved_errno; 2570 fstring server, share, user, password, options; 2571 pstring workgroup; 2572 pstring path; 2573 uint16 mode; 2574 char *p; 2575 SMBCSRV *srv = NULL; 2576 SMBCFILE *dir = NULL; 2577 struct _smbc_callbacks *cb; 2578 struct in_addr rem_ip; 2579 2580 if (!context || !context->internal || 2581 !context->internal->_initialized) { 2582 DEBUG(4, ("no valid context\n")); 2583 errno = EINVAL + 8192; 2584 return NULL; 2585 2586 } 2587 2588 if (!fname) { 2589 DEBUG(4, ("no valid fname\n")); 2590 errno = EINVAL + 8193; 2591 return NULL; 2592 } 2593 2594 if (smbc_parse_path(context, fname, 2595 workgroup, sizeof(workgroup), 2596 server, sizeof(server), 2597 share, sizeof(share), 2598 path, sizeof(path), 2599 user, sizeof(user), 2600 password, sizeof(password), 2601 options, sizeof(options))) { 2602 DEBUG(4, ("no valid path\n")); 2603 errno = EINVAL + 8194; 2604 return NULL; 2605 } 2606 2607 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' " 2608 "path='%s' options='%s'\n", 2609 fname, server, share, path, options)); 2610 2611 /* Ensure the options are valid */ 2612 if (smbc_check_options(server, share, path, options)) { 2613 DEBUG(4, ("unacceptable options (%s)\n", options)); 2614 errno = EINVAL + 8195; 2615 return NULL; 2616 } 2617 2618 if (user[0] == (char)0) fstrcpy(user, context->user); 2619 2620 dir = SMB_MALLOC_P(SMBCFILE); 2621 2622 if (!dir) { 2623 2624 errno = ENOMEM; 2625 return NULL; 2626 2627 } 2628 2629 ZERO_STRUCTP(dir); 2630 2631 dir->cli_fd = 0; 2632 dir->fname = SMB_STRDUP(fname); 2633 dir->srv = NULL; 2634 dir->offset = 0; 2635 dir->file = False; 2636 dir->dir_list = dir->dir_next = dir->dir_end = NULL; 2637 2638 if (server[0] == (char)0) { 2639 2640 int i; 2641 int count; 2642 int max_lmb_count; 2643 struct ip_service *ip_list; 2644 struct ip_service server_addr; 2645 struct user_auth_info u_info; 2646 struct cli_state *cli; 2647 2648 if (share[0] != (char)0 || path[0] != (char)0) { 2649 2650 errno = EINVAL + 8196; 2651 if (dir) { 2652 SAFE_FREE(dir->fname); 2653 SAFE_FREE(dir); 2654 } 2655 return NULL; 2656 } 2657 2658 /* Determine how many local master browsers to query */ 2659 max_lmb_count = (context->options.browse_max_lmb_count == 0 2660 ? INT_MAX 2661 : context->options.browse_max_lmb_count); 2662 2663 pstrcpy(u_info.username, user); 2664 pstrcpy(u_info.password, password); 2665 2666 /* 2667 * We have server and share and path empty but options 2668 * requesting that we scan all master browsers for their list 2669 * of workgroups/domains. This implies that we must first try 2670 * broadcast queries to find all master browsers, and if that 2671 * doesn't work, then try our other methods which return only 2672 * a single master browser. 2673 */ 2674 2675 ip_list = NULL; 2676 if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { 2677 2678 SAFE_FREE(ip_list); 2679 2680 if (!find_master_ip(workgroup, &server_addr.ip)) { 2681 2682 if (dir) { 2683 SAFE_FREE(dir->fname); 2684 SAFE_FREE(dir); 2685 } 2686 errno = ENOENT; 2687 return NULL; 2688 } 2689 2690 ip_list = &server_addr; 2691 count = 1; 2692 } 2693 2694 for (i = 0; i < count && i < max_lmb_count; i++) { 2695 DEBUG(99, ("Found master browser %d of %d: %s\n", 2696 i+1, MAX(count, max_lmb_count), 2697 inet_ntoa(ip_list[i].ip))); 2698 2699 cli = get_ipc_connect_master_ip(&ip_list[i], 2700 workgroup, &u_info); 2701 /* cli == NULL is the master browser refused to talk or 2702 could not be found */ 2703 if ( !cli ) 2704 continue; 2705 2706 fstrcpy(server, cli->desthost); 2707 cli_shutdown(cli); 2708 2709 DEBUG(4, ("using workgroup %s %s\n", 2710 workgroup, server)); 2711 2712 /* 2713 * For each returned master browser IP address, get a 2714 * connection to IPC$ on the server if we do not 2715 * already have one, and determine the 2716 * workgroups/domains that it knows about. 2717 */ 2718 2719 srv = smbc_server(context, True, server, "IPC$", 2720 workgroup, user, password); 2721 if (!srv) { 2722 continue; 2723 } 2724 2725 dir->srv = srv; 2726 dir->dir_type = SMBC_WORKGROUP; 2727 2728 /* Now, list the stuff ... */ 2729 2730 if (!cli_NetServerEnum(srv->cli, 2731 workgroup, 2732 SV_TYPE_DOMAIN_ENUM, 2733 list_unique_wg_fn, 2734 (void *)dir)) { 2735 continue; 2736 } 2737 } 2738 2739 SAFE_FREE(ip_list); 2740 } else { 2741 /* 2742 * Server not an empty string ... Check the rest and see what 2743 * gives 2744 */ 2745 if (*share == '\0') { 2746 if (*path != '\0') { 2747 2748 /* Should not have empty share with path */ 2749 errno = EINVAL + 8197; 2750 if (dir) { 2751 SAFE_FREE(dir->fname); 2752 SAFE_FREE(dir); 2753 } 2754 return NULL; 2755 2756 } 2757 2758 /* 2759 * We don't know if <server> is really a server name 2760 * or is a workgroup/domain name. If we already have 2761 * a server structure for it, we'll use it. 2762 * Otherwise, check to see if <server><1D>, 2763 * <server><1B>, or <server><20> translates. We check 2764 * to see if <server> is an IP address first. 2765 */ 2766 2767 /* 2768 * See if we have an existing server. Do not 2769 * establish a connection if one does not already 2770 * exist. 2771 */ 2772 srv = smbc_server(context, False, server, "IPC$", 2773 workgroup, user, password); 2774 2775 /* 2776 * If no existing server and not an IP addr, look for 2777 * LMB or DMB 2778 */ 2779 if (!srv && 2780 !is_ipaddress(server) && 2781 (resolve_name(server, &rem_ip, 0x1d) || /* LMB */ 2782 resolve_name(server, &rem_ip, 0x1b) )) { /* DMB */ 2783 2784 fstring buserver; 2785 2786 dir->dir_type = SMBC_SERVER; 2787 2788 /* 2789 * Get the backup list ... 2790 */ 2791 if (!name_status_find(server, 0, 0, 2792 rem_ip, buserver)) { 2793 2794 DEBUG(0, ("Could not get name of " 2795 "local/domain master browser " 2796 "for server %s\n", server)); 2797 if (dir) { 2798 SAFE_FREE(dir->fname); 2799 SAFE_FREE(dir); 2800 } 2801 errno = EPERM; 2802 return NULL; 2803 2804 } 2805 2806 /* 2807 * Get a connection to IPC$ on the server if 2808 * we do not already have one 2809 */ 2810 srv = smbc_server(context, True, 2811 buserver, "IPC$", 2812 workgroup, user, password); 2813 if (!srv) { 2814 DEBUG(0, ("got no contact to IPC$\n")); 2815 if (dir) { 2816 SAFE_FREE(dir->fname); 2817 SAFE_FREE(dir); 2818 } 2819 return NULL; 2820 2821 } 2822 2823 dir->srv = srv; 2824 2825 /* Now, list the servers ... */ 2826 if (!cli_NetServerEnum(srv->cli, server, 2827 0x0000FFFE, list_fn, 2828 (void *)dir)) { 2829 2830 if (dir) { 2831 SAFE_FREE(dir->fname); 2832 SAFE_FREE(dir); 2833 } 2834 return NULL; 2835 } 2836 } else if (srv || 2837 (resolve_name(server, &rem_ip, 0x20))) { 2838 2839 /* If we hadn't found the server, get one now */ 2840 if (!srv) { 2841 srv = smbc_server(context, True, 2842 server, "IPC$", 2843 workgroup, 2844 user, password); 2845 } 2846 2847 if (!srv) { 2848 if (dir) { 2849 SAFE_FREE(dir->fname); 2850 SAFE_FREE(dir); 2851 } 2852 return NULL; 2853 2854 } 2855 2856 dir->dir_type = SMBC_FILE_SHARE; 2857 dir->srv = srv; 2858 2859 /* List the shares ... */ 2860 2861 if (net_share_enum_rpc( 2862 srv->cli, 2863 list_fn, 2864 (void *) dir) < 0 && 2865 cli_RNetShareEnum( 2866 srv->cli, 2867 list_fn, 2868 (void *)dir) < 0) { 2869 2870 errno = cli_errno(srv->cli); 2871 if (dir) { 2872 SAFE_FREE(dir->fname); 2873 SAFE_FREE(dir); 2874 } 2875 return NULL; 2876 2877 } 2878 } else { 2879 /* Neither the workgroup nor server exists */ 2880 errno = ECONNREFUSED; 2881 if (dir) { 2882 SAFE_FREE(dir->fname); 2883 SAFE_FREE(dir); 2884 } 2885 return NULL; 2886 } 2887 2888 } 2889 else { 2890 /* 2891 * The server and share are specified ... work from 2892 * there ... 2893 */ 2894 pstring targetpath; 2895 struct cli_state *targetcli; 2896 2897 /* We connect to the server and list the directory */ 2898 dir->dir_type = SMBC_FILE_SHARE; 2899 2900 srv = smbc_server(context, True, server, share, 2901 workgroup, user, password); 2902 2903 if (!srv) { 2904 2905 if (dir) { 2906 SAFE_FREE(dir->fname); 2907 SAFE_FREE(dir); 2908 } 2909 return NULL; 2910 2911 } 2912 2913 dir->srv = srv; 2914 2915 /* Now, list the files ... */ 2916 2917 p = path + strlen(path); 2918 pstrcat(path, "\\*"); 2919 2920 if (!cli_resolve_path("", srv->cli, path, 2921 &targetcli, targetpath)) 2922 { 2923 d_printf("Could not resolve %s\n", path); 2924 if (dir) { 2925 SAFE_FREE(dir->fname); 2926 SAFE_FREE(dir); 2927 } 2928 return NULL; 2929 } 2930 2931 if (cli_list(targetcli, targetpath, 2932 aDIR | aSYSTEM | aHIDDEN, 2933 dir_list_fn, (void *)dir) < 0) { 2934 2935 if (dir) { 2936 SAFE_FREE(dir->fname); 2937 SAFE_FREE(dir); 2938 } 2939 saved_errno = smbc_errno(context, targetcli); 2940 2941 if (saved_errno == EINVAL) { 2942 /* 2943 * See if they asked to opendir something 2944 * other than a directory. If so, the 2945 * converted error value we got would have 2946 * been EINVAL rather than ENOTDIR. 2947 */ 2948 *p = '\0'; /* restore original path */ 2949 2950 if (smbc_getatr(context, srv, path, 2951 &mode, NULL, 2952 NULL, NULL, NULL, NULL, 2953 NULL) && 2954 ! IS_DOS_DIR(mode)) { 2955 2956 /* It is. Correct the error value */ 2957 saved_errno = ENOTDIR; 2958 } 2959 } 2960 2961 /* 2962 * If there was an error and the server is no 2963 * good any more... 2964 */ 2965 cb = &context->callbacks; 2966 if (cli_is_error(targetcli) && 2967 cb->check_server_fn(context, srv)) { 2968 2969 /* ... then remove it. */ 2970 if (cb->remove_unused_server_fn(context, 2971 srv)) { 2972 /* 2973 * We could not remove the server 2974 * completely, remove it from the 2975 * cache so we will not get it 2976 * again. It will be removed when the 2977 * last file/dir is closed. 2978 */ 2979 cb->remove_cached_srv_fn(context, srv); 2980 } 2981 } 2982 2983 errno = saved_errno; 2984 return NULL; 2985 } 2986 } 2987 2988 } 2989 2990 DLIST_ADD(context->internal->_files, dir); 2991 return dir; 2992 2993} 2994 2995/* 2996 * Routine to close a directory 2997 */ 2998 2999static int 3000smbc_closedir_ctx(SMBCCTX *context, 3001 SMBCFILE *dir) 3002{ 3003 3004 if (!context || !context->internal || 3005 !context->internal->_initialized) { 3006 3007 errno = EINVAL; 3008 return -1; 3009 3010 } 3011 3012 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 3013 3014 errno = EBADF; 3015 return -1; 3016 3017 } 3018 3019 smbc_remove_dir(dir); /* Clean it up */ 3020 3021 DLIST_REMOVE(context->internal->_files, dir); 3022 3023 if (dir) { 3024 3025 SAFE_FREE(dir->fname); 3026 SAFE_FREE(dir); /* Free the space too */ 3027 } 3028 3029 return 0; 3030 3031} 3032 3033static void 3034smbc_readdir_internal(SMBCCTX * context, 3035 struct smbc_dirent *dest, 3036 struct smbc_dirent *src, 3037 int max_namebuf_len) 3038{ 3039 if (context->options.urlencode_readdir_entries) { 3040 3041 /* url-encode the name. get back remaining buffer space */ 3042 max_namebuf_len = 3043 smbc_urlencode(dest->name, src->name, max_namebuf_len); 3044 3045 /* We now know the name length */ 3046 dest->namelen = strlen(dest->name); 3047 3048 /* Save the pointer to the beginning of the comment */ 3049 dest->comment = dest->name + dest->namelen + 1; 3050 3051 /* Copy the comment */ 3052 strncpy(dest->comment, src->comment, max_namebuf_len - 1); 3053 dest->comment[max_namebuf_len - 1] = '\0'; 3054 3055 /* Save other fields */ 3056 dest->smbc_type = src->smbc_type; 3057 dest->commentlen = strlen(dest->comment); 3058 dest->dirlen = ((dest->comment + dest->commentlen + 1) - 3059 (char *) dest); 3060 } else { 3061 3062 /* No encoding. Just copy the entry as is. */ 3063 memcpy(dest, src, src->dirlen); 3064 dest->comment = (char *)(&dest->name + src->namelen + 1); 3065 } 3066 3067} 3068 3069/* 3070 * Routine to get a directory entry 3071 */ 3072 3073struct smbc_dirent * 3074smbc_readdir_ctx(SMBCCTX *context, 3075 SMBCFILE *dir) 3076{ 3077 int maxlen; 3078 struct smbc_dirent *dirp, *dirent; 3079 3080 /* Check that all is ok first ... */ 3081 3082 if (!context || !context->internal || 3083 !context->internal->_initialized) { 3084 3085 errno = EINVAL; 3086 DEBUG(0, ("Invalid context in smbc_readdir_ctx()\n")); 3087 return NULL; 3088 3089 } 3090 3091 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 3092 3093 errno = EBADF; 3094 DEBUG(0, ("Invalid dir in smbc_readdir_ctx()\n")); 3095 return NULL; 3096 3097 } 3098 3099 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 3100 3101 errno = ENOTDIR; 3102 DEBUG(0, ("Found file vs directory in smbc_readdir_ctx()\n")); 3103 return NULL; 3104 3105 } 3106 3107 if (!dir->dir_next) { 3108 return NULL; 3109 } 3110 3111 dirent = dir->dir_next->dirent; 3112 if (!dirent) { 3113 3114 errno = ENOENT; 3115 return NULL; 3116 3117 } 3118 3119 dirp = (struct smbc_dirent *)context->internal->_dirent; 3120 maxlen = (sizeof(context->internal->_dirent) - 3121 sizeof(struct smbc_dirent)); 3122 3123 smbc_readdir_internal(context, dirp, dirent, maxlen); 3124 3125 dir->dir_next = dir->dir_next->next; 3126 3127 return dirp; 3128} 3129 3130/* 3131 * Routine to get directory entries 3132 */ 3133 3134static int 3135smbc_getdents_ctx(SMBCCTX *context, 3136 SMBCFILE *dir, 3137 struct smbc_dirent *dirp, 3138 int count) 3139{ 3140 int rem = count; 3141 int reqd; 3142 int maxlen; 3143 char *ndir = (char *)dirp; 3144 struct smbc_dir_list *dirlist; 3145 3146 /* Check that all is ok first ... */ 3147 3148 if (!context || !context->internal || 3149 !context->internal->_initialized) { 3150 3151 errno = EINVAL; 3152 return -1; 3153 3154 } 3155 3156 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 3157 3158 errno = EBADF; 3159 return -1; 3160 3161 } 3162 3163 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 3164 3165 errno = ENOTDIR; 3166 return -1; 3167 3168 } 3169 3170 /* 3171 * Now, retrieve the number of entries that will fit in what was passed 3172 * We have to figure out if the info is in the list, or we need to 3173 * send a request to the server to get the info. 3174 */ 3175 3176 while ((dirlist = dir->dir_next)) { 3177 struct smbc_dirent *dirent; 3178 3179 if (!dirlist->dirent) { 3180 3181 errno = ENOENT; /* Bad error */ 3182 return -1; 3183 3184 } 3185 3186 /* Do urlencoding of next entry, if so selected */ 3187 dirent = (struct smbc_dirent *)context->internal->_dirent; 3188 maxlen = (sizeof(context->internal->_dirent) - 3189 sizeof(struct smbc_dirent)); 3190 smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen); 3191 3192 reqd = dirent->dirlen; 3193 3194 if (rem < reqd) { 3195 3196 if (rem < count) { /* We managed to copy something */ 3197 3198 errno = 0; 3199 return count - rem; 3200 3201 } 3202 else { /* Nothing copied ... */ 3203 3204 errno = EINVAL; /* Not enough space ... */ 3205 return -1; 3206 3207 } 3208 3209 } 3210 3211 memcpy(ndir, dirent, reqd); /* Copy the data in ... */ 3212 3213 ((struct smbc_dirent *)ndir)->comment = 3214 (char *)(&((struct smbc_dirent *)ndir)->name + 3215 dirent->namelen + 3216 1); 3217 3218 ndir += reqd; 3219 3220 rem -= reqd; 3221 3222 dir->dir_next = dirlist = dirlist -> next; 3223 } 3224 3225 if (rem == count) 3226 return 0; 3227 else 3228 return count - rem; 3229 3230} 3231 3232/* 3233 * Routine to create a directory ... 3234 */ 3235 3236static int 3237smbc_mkdir_ctx(SMBCCTX *context, 3238 const char *fname, 3239 mode_t mode) 3240{ 3241 SMBCSRV *srv; 3242 fstring server; 3243 fstring share; 3244 fstring user; 3245 fstring password; 3246 fstring workgroup; 3247 pstring path, targetpath; 3248 struct cli_state *targetcli; 3249 3250 if (!context || !context->internal || 3251 !context->internal->_initialized) { 3252 3253 errno = EINVAL; 3254 return -1; 3255 3256 } 3257 3258 if (!fname) { 3259 3260 errno = EINVAL; 3261 return -1; 3262 3263 } 3264 3265 DEBUG(4, ("smbc_mkdir(%s)\n", fname)); 3266 3267 if (smbc_parse_path(context, fname, 3268 workgroup, sizeof(workgroup), 3269 server, sizeof(server), 3270 share, sizeof(share), 3271 path, sizeof(path), 3272 user, sizeof(user), 3273 password, sizeof(password), 3274 NULL, 0)) { 3275 errno = EINVAL; 3276 return -1; 3277 } 3278 3279 if (user[0] == (char)0) fstrcpy(user, context->user); 3280 3281 srv = smbc_server(context, True, 3282 server, share, workgroup, user, password); 3283 3284 if (!srv) { 3285 3286 return -1; /* errno set by smbc_server */ 3287 3288 } 3289 3290 /*d_printf(">>>mkdir: resolving %s\n", path);*/ 3291 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) 3292 { 3293 d_printf("Could not resolve %s\n", path); 3294 return -1; 3295 } 3296 /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/ 3297 3298 if (!cli_mkdir(targetcli, targetpath)) { 3299 3300 errno = smbc_errno(context, targetcli); 3301 return -1; 3302 3303 } 3304 3305 return 0; 3306 3307} 3308 3309/* 3310 * Our list function simply checks to see if a directory is not empty 3311 */ 3312 3313static int smbc_rmdir_dirempty = True; 3314 3315static void 3316rmdir_list_fn(const char *mnt, 3317 file_info *finfo, 3318 const char *mask, 3319 void *state) 3320{ 3321 if (strncmp(finfo->name, ".", 1) != 0 && 3322 strncmp(finfo->name, "..", 2) != 0) { 3323 3324 smbc_rmdir_dirempty = False; 3325 } 3326} 3327 3328/* 3329 * Routine to remove a directory 3330 */ 3331 3332static int 3333smbc_rmdir_ctx(SMBCCTX *context, 3334 const char *fname) 3335{ 3336 SMBCSRV *srv; 3337 fstring server; 3338 fstring share; 3339 fstring user; 3340 fstring password; 3341 fstring workgroup; 3342 pstring path; 3343 pstring targetpath; 3344 struct cli_state *targetcli; 3345 3346 if (!context || !context->internal || 3347 !context->internal->_initialized) { 3348 3349 errno = EINVAL; 3350 return -1; 3351 3352 } 3353 3354 if (!fname) { 3355 3356 errno = EINVAL; 3357 return -1; 3358 3359 } 3360 3361 DEBUG(4, ("smbc_rmdir(%s)\n", fname)); 3362 3363 if (smbc_parse_path(context, fname, 3364 workgroup, sizeof(workgroup), 3365 server, sizeof(server), 3366 share, sizeof(share), 3367 path, sizeof(path), 3368 user, sizeof(user), 3369 password, sizeof(password), 3370 NULL, 0)) 3371 { 3372 errno = EINVAL; 3373 return -1; 3374 } 3375 3376 if (user[0] == (char)0) fstrcpy(user, context->user); 3377 3378 srv = smbc_server(context, True, 3379 server, share, workgroup, user, password); 3380 3381 if (!srv) { 3382 3383 return -1; /* errno set by smbc_server */ 3384 3385 } 3386 3387 /*d_printf(">>>rmdir: resolving %s\n", path);*/ 3388 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) 3389 { 3390 d_printf("Could not resolve %s\n", path); 3391 return -1; 3392 } 3393 /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/ 3394 3395 3396 if (!cli_rmdir(targetcli, targetpath)) { 3397 3398 errno = smbc_errno(context, targetcli); 3399 3400 if (errno == EACCES) { /* Check if the dir empty or not */ 3401 3402 /* Local storage to avoid buffer overflows */ 3403 pstring lpath; 3404 3405 smbc_rmdir_dirempty = True; /* Make this so ... */ 3406 3407 pstrcpy(lpath, targetpath); 3408 pstrcat(lpath, "\\*"); 3409 3410 if (cli_list(targetcli, lpath, 3411 aDIR | aSYSTEM | aHIDDEN, 3412 rmdir_list_fn, NULL) < 0) { 3413 3414 /* Fix errno to ignore latest error ... */ 3415 DEBUG(5, ("smbc_rmdir: " 3416 "cli_list returned an error: %d\n", 3417 smbc_errno(context, targetcli))); 3418 errno = EACCES; 3419 3420 } 3421 3422 if (smbc_rmdir_dirempty) 3423 errno = EACCES; 3424 else 3425 errno = ENOTEMPTY; 3426 3427 } 3428 3429 return -1; 3430 3431 } 3432 3433 return 0; 3434 3435} 3436 3437/* 3438 * Routine to return the current directory position 3439 */ 3440 3441static off_t 3442smbc_telldir_ctx(SMBCCTX *context, 3443 SMBCFILE *dir) 3444{ 3445 off_t ret_val; /* Squash warnings about cast */ 3446 3447 if (!context || !context->internal || 3448 !context->internal->_initialized) { 3449 3450 errno = EINVAL; 3451 return -1; 3452 3453 } 3454 3455 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 3456 3457 errno = EBADF; 3458 return -1; 3459 3460 } 3461 3462 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 3463 3464 errno = ENOTDIR; 3465 return -1; 3466 3467 } 3468 3469 /* 3470 * We return the pointer here as the offset 3471 */ 3472 ret_val = (off_t)(long)dir->dir_next; 3473 return ret_val; 3474 3475} 3476 3477/* 3478 * A routine to run down the list and see if the entry is OK 3479 */ 3480 3481struct smbc_dir_list * 3482smbc_check_dir_ent(struct smbc_dir_list *list, 3483 struct smbc_dirent *dirent) 3484{ 3485 3486 /* Run down the list looking for what we want */ 3487 3488 if (dirent) { 3489 3490 struct smbc_dir_list *tmp = list; 3491 3492 while (tmp) { 3493 3494 if (tmp->dirent == dirent) 3495 return tmp; 3496 3497 tmp = tmp->next; 3498 3499 } 3500 3501 } 3502 3503 return NULL; /* Not found, or an error */ 3504 3505} 3506 3507 3508/* 3509 * Routine to seek on a directory 3510 */ 3511 3512static int 3513smbc_lseekdir_ctx(SMBCCTX *context, 3514 SMBCFILE *dir, 3515 off_t offset) 3516{ 3517 long int l_offset = offset; /* Handle problems of size */ 3518 struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset; 3519 struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL; 3520 3521 if (!context || !context->internal || 3522 !context->internal->_initialized) { 3523 3524 errno = EINVAL; 3525 return -1; 3526 3527 } 3528 3529 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 3530 3531 errno = ENOTDIR; 3532 return -1; 3533 3534 } 3535 3536 /* Now, check what we were passed and see if it is OK ... */ 3537 3538 if (dirent == NULL) { /* Seek to the begining of the list */ 3539 3540 dir->dir_next = dir->dir_list; 3541 return 0; 3542 3543 } 3544 3545 /* Now, run down the list and make sure that the entry is OK */ 3546 /* This may need to be changed if we change the format of the list */ 3547 3548 if ((list_ent = smbc_check_dir_ent(dir->dir_list, dirent)) == NULL) { 3549 3550 errno = EINVAL; /* Bad entry */ 3551 return -1; 3552 3553 } 3554 3555 dir->dir_next = list_ent; 3556 3557 return 0; 3558 3559} 3560 3561/* 3562 * Routine to fstat a dir 3563 */ 3564 3565static int 3566smbc_fstatdir_ctx(SMBCCTX *context, 3567 SMBCFILE *dir, 3568 struct stat *st) 3569{ 3570 3571 if (!context || !context->internal || 3572 !context->internal->_initialized) { 3573 3574 errno = EINVAL; 3575 return -1; 3576 3577 } 3578 3579 /* No code yet ... */ 3580 3581 return 0; 3582 3583} 3584 3585static int 3586smbc_chmod_ctx(SMBCCTX *context, 3587 const char *fname, 3588 mode_t newmode) 3589{ 3590 SMBCSRV *srv; 3591 fstring server; 3592 fstring share; 3593 fstring user; 3594 fstring password; 3595 fstring workgroup; 3596 pstring path; 3597 uint16 mode; 3598 3599 if (!context || !context->internal || 3600 !context->internal->_initialized) { 3601 3602 errno = EINVAL; /* Best I can think of ... */ 3603 return -1; 3604 3605 } 3606 3607 if (!fname) { 3608 3609 errno = EINVAL; 3610 return -1; 3611 3612 } 3613 3614 DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode)); 3615 3616 if (smbc_parse_path(context, fname, 3617 workgroup, sizeof(workgroup), 3618 server, sizeof(server), 3619 share, sizeof(share), 3620 path, sizeof(path), 3621 user, sizeof(user), 3622 password, sizeof(password), 3623 NULL, 0)) { 3624 errno = EINVAL; 3625 return -1; 3626 } 3627 3628 if (user[0] == (char)0) fstrcpy(user, context->user); 3629 3630 srv = smbc_server(context, True, 3631 server, share, workgroup, user, password); 3632 3633 if (!srv) { 3634 return -1; /* errno set by smbc_server */ 3635 } 3636 3637 mode = 0; 3638 3639 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; 3640 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; 3641 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; 3642 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; 3643 3644 if (!cli_setatr(srv->cli, path, mode, 0)) { 3645 errno = smbc_errno(context, srv->cli); 3646 return -1; 3647 } 3648 3649 return 0; 3650} 3651 3652static int 3653smbc_utimes_ctx(SMBCCTX *context, 3654 const char *fname, 3655 struct timeval *tbuf) 3656{ 3657 SMBCSRV *srv; 3658 fstring server; 3659 fstring share; 3660 fstring user; 3661 fstring password; 3662 fstring workgroup; 3663 pstring path; 3664 time_t access_time; 3665 time_t write_time; 3666 3667 if (!context || !context->internal || 3668 !context->internal->_initialized) { 3669 3670 errno = EINVAL; /* Best I can think of ... */ 3671 return -1; 3672 3673 } 3674 3675 if (!fname) { 3676 3677 errno = EINVAL; 3678 return -1; 3679 3680 } 3681 3682 if (tbuf == NULL) { 3683 access_time = write_time = time(NULL); 3684 } else { 3685 access_time = tbuf[0].tv_sec; 3686 write_time = tbuf[1].tv_sec; 3687 } 3688 3689 if (DEBUGLVL(4)) 3690 { 3691 char *p; 3692 char atimebuf[32]; 3693 char mtimebuf[32]; 3694 3695 strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1); 3696 atimebuf[sizeof(atimebuf) - 1] = '\0'; 3697 if ((p = strchr(atimebuf, '\n')) != NULL) { 3698 *p = '\0'; 3699 } 3700 3701 strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1); 3702 mtimebuf[sizeof(mtimebuf) - 1] = '\0'; 3703 if ((p = strchr(mtimebuf, '\n')) != NULL) { 3704 *p = '\0'; 3705 } 3706 3707 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n", 3708 fname, atimebuf, mtimebuf); 3709 } 3710 3711 if (smbc_parse_path(context, fname, 3712 workgroup, sizeof(workgroup), 3713 server, sizeof(server), 3714 share, sizeof(share), 3715 path, sizeof(path), 3716 user, sizeof(user), 3717 password, sizeof(password), 3718 NULL, 0)) { 3719 errno = EINVAL; 3720 return -1; 3721 } 3722 3723 if (user[0] == (char)0) fstrcpy(user, context->user); 3724 3725 srv = smbc_server(context, True, 3726 server, share, workgroup, user, password); 3727 3728 if (!srv) { 3729 return -1; /* errno set by smbc_server */ 3730 } 3731 3732 if (!smbc_setatr(context, srv, path, 3733 0, access_time, write_time, 0, 0)) { 3734 return -1; /* errno set by smbc_setatr */ 3735 } 3736 3737 return 0; 3738} 3739 3740 3741/* The MSDN is contradictory over the ordering of ACE entries in an ACL. 3742 However NT4 gives a "The information may have been modified by a 3743 computer running Windows NT 5.0" if denied ACEs do not appear before 3744 allowed ACEs. */ 3745 3746static int 3747ace_compare(SEC_ACE *ace1, 3748 SEC_ACE *ace2) 3749{ 3750 if (sec_ace_equal(ace1, ace2)) 3751 return 0; 3752 3753 if (ace1->type != ace2->type) 3754 return ace2->type - ace1->type; 3755 3756 if (sid_compare(&ace1->trustee, &ace2->trustee)) 3757 return sid_compare(&ace1->trustee, &ace2->trustee); 3758 3759 if (ace1->flags != ace2->flags) 3760 return ace1->flags - ace2->flags; 3761 3762 if (ace1->access_mask != ace2->access_mask) 3763 return ace1->access_mask - ace2->access_mask; 3764 3765 if (ace1->size != ace2->size) 3766 return ace1->size - ace2->size; 3767 3768 return memcmp(ace1, ace2, sizeof(SEC_ACE)); 3769} 3770 3771 3772static void 3773sort_acl(SEC_ACL *the_acl) 3774{ 3775 uint32 i; 3776 if (!the_acl) return; 3777 3778 qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), 3779 QSORT_CAST ace_compare); 3780 3781 for (i=1;i<the_acl->num_aces;) { 3782 if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) { 3783 int j; 3784 for (j=i; j<the_acl->num_aces-1; j++) { 3785 the_acl->aces[j] = the_acl->aces[j+1]; 3786 } 3787 the_acl->num_aces--; 3788 } else { 3789 i++; 3790 } 3791 } 3792} 3793 3794/* convert a SID to a string, either numeric or username/group */ 3795static void 3796convert_sid_to_string(struct cli_state *ipc_cli, 3797 POLICY_HND *pol, 3798 fstring str, 3799 BOOL numeric, 3800 DOM_SID *sid) 3801{ 3802 char **domains = NULL; 3803 char **names = NULL; 3804 enum lsa_SidType *types = NULL; 3805 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); 3806 sid_to_string(str, sid); 3807 3808 if (numeric) { 3809 return; /* no lookup desired */ 3810 } 3811 3812 if (!pipe_hnd) { 3813 return; 3814 } 3815 3816 /* Ask LSA to convert the sid to a name */ 3817 3818 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ipc_cli->mem_ctx, 3819 pol, 1, sid, &domains, 3820 &names, &types)) || 3821 !domains || !domains[0] || !names || !names[0]) { 3822 return; 3823 } 3824 3825 /* Converted OK */ 3826 3827 slprintf(str, sizeof(fstring) - 1, "%s%s%s", 3828 domains[0], lp_winbind_separator(), 3829 names[0]); 3830} 3831 3832/* convert a string to a SID, either numeric or username/group */ 3833static BOOL 3834convert_string_to_sid(struct cli_state *ipc_cli, 3835 POLICY_HND *pol, 3836 BOOL numeric, 3837 DOM_SID *sid, 3838 const char *str) 3839{ 3840 enum lsa_SidType *types = NULL; 3841 DOM_SID *sids = NULL; 3842 BOOL result = True; 3843 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); 3844 3845 if (!pipe_hnd) { 3846 return False; 3847 } 3848 3849 if (numeric) { 3850 if (strncmp(str, "S-", 2) == 0) { 3851 return string_to_sid(sid, str); 3852 } 3853 3854 result = False; 3855 goto done; 3856 } 3857 3858 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx, 3859 pol, 1, &str, NULL, &sids, 3860 &types))) { 3861 result = False; 3862 goto done; 3863 } 3864 3865 sid_copy(sid, &sids[0]); 3866 done: 3867 3868 return result; 3869} 3870 3871 3872/* parse an ACE in the same format as print_ace() */ 3873static BOOL 3874parse_ace(struct cli_state *ipc_cli, 3875 POLICY_HND *pol, 3876 SEC_ACE *ace, 3877 BOOL numeric, 3878 char *str) 3879{ 3880 char *p; 3881 const char *cp; 3882 fstring tok; 3883 unsigned int atype; 3884 unsigned int aflags; 3885 unsigned int amask; 3886 DOM_SID sid; 3887 SEC_ACCESS mask; 3888 const struct perm_value *v; 3889 struct perm_value { 3890 const char *perm; 3891 uint32 mask; 3892 }; 3893 3894 /* These values discovered by inspection */ 3895 static const struct perm_value special_values[] = { 3896 { "R", 0x00120089 }, 3897 { "W", 0x00120116 }, 3898 { "X", 0x001200a0 }, 3899 { "D", 0x00010000 }, 3900 { "P", 0x00040000 }, 3901 { "O", 0x00080000 }, 3902 { NULL, 0 }, 3903 }; 3904 3905 static const struct perm_value standard_values[] = { 3906 { "READ", 0x001200a9 }, 3907 { "CHANGE", 0x001301bf }, 3908 { "FULL", 0x001f01ff }, 3909 { NULL, 0 }, 3910 }; 3911 3912 3913 ZERO_STRUCTP(ace); 3914 p = strchr_m(str,':'); 3915 if (!p) return False; 3916 *p = '\0'; 3917 p++; 3918 /* Try to parse numeric form */ 3919 3920 if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 && 3921 convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { 3922 goto done; 3923 } 3924 3925 /* Try to parse text form */ 3926 3927 if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { 3928 return False; 3929 } 3930 3931 cp = p; 3932 if (!next_token(&cp, tok, "/", sizeof(fstring))) { 3933 return False; 3934 } 3935 3936 if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { 3937 atype = SEC_ACE_TYPE_ACCESS_ALLOWED; 3938 } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) { 3939 atype = SEC_ACE_TYPE_ACCESS_DENIED; 3940 } else { 3941 return False; 3942 } 3943 3944 /* Only numeric form accepted for flags at present */ 3945 3946 if (!(next_token(&cp, tok, "/", sizeof(fstring)) && 3947 sscanf(tok, "%i", &aflags))) { 3948 return False; 3949 } 3950 3951 if (!next_token(&cp, tok, "/", sizeof(fstring))) { 3952 return False; 3953 } 3954 3955 if (strncmp(tok, "0x", 2) == 0) { 3956 if (sscanf(tok, "%i", &amask) != 1) { 3957 return False; 3958 } 3959 goto done; 3960 } 3961 3962 for (v = standard_values; v->perm; v++) { 3963 if (strcmp(tok, v->perm) == 0) { 3964 amask = v->mask; 3965 goto done; 3966 } 3967 } 3968 3969 p = tok; 3970 3971 while(*p) { 3972 BOOL found = False; 3973 3974 for (v = special_values; v->perm; v++) { 3975 if (v->perm[0] == *p) { 3976 amask |= v->mask; 3977 found = True; 3978 } 3979 } 3980 3981 if (!found) return False; 3982 p++; 3983 } 3984 3985 if (*p) { 3986 return False; 3987 } 3988 3989 done: 3990 mask = amask; 3991 init_sec_ace(ace, &sid, atype, mask, aflags); 3992 return True; 3993} 3994 3995/* add an ACE to a list of ACEs in a SEC_ACL */ 3996static BOOL 3997add_ace(SEC_ACL **the_acl, 3998 SEC_ACE *ace, 3999 TALLOC_CTX *ctx) 4000{ 4001 SEC_ACL *newacl; 4002 SEC_ACE *aces; 4003 4004 if (! *the_acl) { 4005 (*the_acl) = make_sec_acl(ctx, 3, 1, ace); 4006 return True; 4007 } 4008 4009 if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) { 4010 return False; 4011 } 4012 memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE)); 4013 memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE)); 4014 newacl = make_sec_acl(ctx, (*the_acl)->revision, 4015 1+(*the_acl)->num_aces, aces); 4016 SAFE_FREE(aces); 4017 (*the_acl) = newacl; 4018 return True; 4019} 4020 4021 4022/* parse a ascii version of a security descriptor */ 4023static SEC_DESC * 4024sec_desc_parse(TALLOC_CTX *ctx, 4025 struct cli_state *ipc_cli, 4026 POLICY_HND *pol, 4027 BOOL numeric, 4028 char *str) 4029{ 4030 const char *p = str; 4031 fstring tok; 4032 SEC_DESC *ret = NULL; 4033 size_t sd_size; 4034 DOM_SID *group_sid=NULL; 4035 DOM_SID *owner_sid=NULL; 4036 SEC_ACL *dacl=NULL; 4037 int revision=1; 4038 4039 while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { 4040 4041 if (StrnCaseCmp(tok,"REVISION:", 9) == 0) { 4042 revision = strtol(tok+9, NULL, 16); 4043 continue; 4044 } 4045 4046 if (StrnCaseCmp(tok,"OWNER:", 6) == 0) { 4047 if (owner_sid) { 4048 DEBUG(5, ("OWNER specified more than once!\n")); 4049 goto done; 4050 } 4051 owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 4052 if (!owner_sid || 4053 !convert_string_to_sid(ipc_cli, pol, 4054 numeric, 4055 owner_sid, tok+6)) { 4056 DEBUG(5, ("Failed to parse owner sid\n")); 4057 goto done; 4058 } 4059 continue; 4060 } 4061 4062 if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) { 4063 if (owner_sid) { 4064 DEBUG(5, ("OWNER specified more than once!\n")); 4065 goto done; 4066 } 4067 owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 4068 if (!owner_sid || 4069 !convert_string_to_sid(ipc_cli, pol, 4070 False, 4071 owner_sid, tok+7)) { 4072 DEBUG(5, ("Failed to parse owner sid\n")); 4073 goto done; 4074 } 4075 continue; 4076 } 4077 4078 if (StrnCaseCmp(tok,"GROUP:", 6) == 0) { 4079 if (group_sid) { 4080 DEBUG(5, ("GROUP specified more than once!\n")); 4081 goto done; 4082 } 4083 group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 4084 if (!group_sid || 4085 !convert_string_to_sid(ipc_cli, pol, 4086 numeric, 4087 group_sid, tok+6)) { 4088 DEBUG(5, ("Failed to parse group sid\n")); 4089 goto done; 4090 } 4091 continue; 4092 } 4093 4094 if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) { 4095 if (group_sid) { 4096 DEBUG(5, ("GROUP specified more than once!\n")); 4097 goto done; 4098 } 4099 group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 4100 if (!group_sid || 4101 !convert_string_to_sid(ipc_cli, pol, 4102 False, 4103 group_sid, tok+6)) { 4104 DEBUG(5, ("Failed to parse group sid\n")); 4105 goto done; 4106 } 4107 continue; 4108 } 4109 4110 if (StrnCaseCmp(tok,"ACL:", 4) == 0) { 4111 SEC_ACE ace; 4112 if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) { 4113 DEBUG(5, ("Failed to parse ACL %s\n", tok)); 4114 goto done; 4115 } 4116 if(!add_ace(&dacl, &ace, ctx)) { 4117 DEBUG(5, ("Failed to add ACL %s\n", tok)); 4118 goto done; 4119 } 4120 continue; 4121 } 4122 4123 if (StrnCaseCmp(tok,"ACL+:", 5) == 0) { 4124 SEC_ACE ace; 4125 if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) { 4126 DEBUG(5, ("Failed to parse ACL %s\n", tok)); 4127 goto done; 4128 } 4129 if(!add_ace(&dacl, &ace, ctx)) { 4130 DEBUG(5, ("Failed to add ACL %s\n", tok)); 4131 goto done; 4132 } 4133 continue; 4134 } 4135 4136 DEBUG(5, ("Failed to parse security descriptor\n")); 4137 goto done; 4138 } 4139 4140 ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, 4141 owner_sid, group_sid, NULL, dacl, &sd_size); 4142 4143 done: 4144 SAFE_FREE(group_sid); 4145 SAFE_FREE(owner_sid); 4146 4147 return ret; 4148} 4149 4150 4151/* Obtain the current dos attributes */ 4152static DOS_ATTR_DESC * 4153dos_attr_query(SMBCCTX *context, 4154 TALLOC_CTX *ctx, 4155 const char *filename, 4156 SMBCSRV *srv) 4157{ 4158 struct timespec create_time_ts; 4159 struct timespec write_time_ts; 4160 struct timespec access_time_ts; 4161 struct timespec change_time_ts; 4162 SMB_OFF_T size = 0; 4163 uint16 mode = 0; 4164 SMB_INO_T inode = 0; 4165 DOS_ATTR_DESC *ret; 4166 4167 ret = TALLOC_P(ctx, DOS_ATTR_DESC); 4168 if (!ret) { 4169 errno = ENOMEM; 4170 return NULL; 4171 } 4172 4173 /* Obtain the DOS attributes */ 4174 if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename), 4175 &mode, &size, 4176 &create_time_ts, 4177 &access_time_ts, 4178 &write_time_ts, 4179 &change_time_ts, 4180 &inode)) { 4181 4182 errno = smbc_errno(context, srv->cli); 4183 DEBUG(5, ("dos_attr_query Failed to query old attributes\n")); 4184 return NULL; 4185 4186 } 4187 4188 ret->mode = mode; 4189 ret->size = size; 4190 ret->create_time = convert_timespec_to_time_t(create_time_ts); 4191 ret->access_time = convert_timespec_to_time_t(access_time_ts); 4192 ret->write_time = convert_timespec_to_time_t(write_time_ts); 4193 ret->change_time = convert_timespec_to_time_t(change_time_ts); 4194 ret->inode = inode; 4195 4196 return ret; 4197} 4198 4199 4200/* parse a ascii version of a security descriptor */ 4201static void 4202dos_attr_parse(SMBCCTX *context, 4203 DOS_ATTR_DESC *dad, 4204 SMBCSRV *srv, 4205 char *str) 4206{ 4207 int n; 4208 const char *p = str; 4209 fstring tok; 4210 struct { 4211 const char * create_time_attr; 4212 const char * access_time_attr; 4213 const char * write_time_attr; 4214 const char * change_time_attr; 4215 } attr_strings; 4216 4217 /* Determine whether to use old-style or new-style attribute names */ 4218 if (context->internal->_full_time_names) { 4219 /* new-style names */ 4220 attr_strings.create_time_attr = "CREATE_TIME"; 4221 attr_strings.access_time_attr = "ACCESS_TIME"; 4222 attr_strings.write_time_attr = "WRITE_TIME"; 4223 attr_strings.change_time_attr = "CHANGE_TIME"; 4224 } else { 4225 /* old-style names */ 4226 attr_strings.create_time_attr = NULL; 4227 attr_strings.access_time_attr = "A_TIME"; 4228 attr_strings.write_time_attr = "M_TIME"; 4229 attr_strings.change_time_attr = "C_TIME"; 4230 } 4231 4232 /* if this is to set the entire ACL... */ 4233 if (*str == '*') { 4234 /* ... then increment past the first colon if there is one */ 4235 if ((p = strchr(str, ':')) != NULL) { 4236 ++p; 4237 } else { 4238 p = str; 4239 } 4240 } 4241 4242 while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { 4243 4244 if (StrnCaseCmp(tok, "MODE:", 5) == 0) { 4245 dad->mode = strtol(tok+5, NULL, 16); 4246 continue; 4247 } 4248 4249 if (StrnCaseCmp(tok, "SIZE:", 5) == 0) { 4250 dad->size = (SMB_OFF_T)atof(tok+5); 4251 continue; 4252 } 4253 4254 n = strlen(attr_strings.access_time_attr); 4255 if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) { 4256 dad->access_time = (time_t)strtol(tok+n+1, NULL, 10); 4257 continue; 4258 } 4259 4260 n = strlen(attr_strings.change_time_attr); 4261 if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) { 4262 dad->change_time = (time_t)strtol(tok+n+1, NULL, 10); 4263 continue; 4264 } 4265 4266 n = strlen(attr_strings.write_time_attr); 4267 if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) { 4268 dad->write_time = (time_t)strtol(tok+n+1, NULL, 10); 4269 continue; 4270 } 4271 4272 if (attr_strings.create_time_attr != NULL) { 4273 n = strlen(attr_strings.create_time_attr); 4274 if (StrnCaseCmp(tok, attr_strings.create_time_attr, 4275 n) == 0) { 4276 dad->create_time = (time_t)strtol(tok+n+1, 4277 NULL, 10); 4278 continue; 4279 } 4280 } 4281 4282 if (StrnCaseCmp(tok, "INODE:", 6) == 0) { 4283 dad->inode = (SMB_INO_T)atof(tok+6); 4284 continue; 4285 } 4286 } 4287} 4288 4289/***************************************************** 4290 Retrieve the acls for a file. 4291*******************************************************/ 4292 4293static int 4294cacl_get(SMBCCTX *context, 4295 TALLOC_CTX *ctx, 4296 SMBCSRV *srv, 4297 struct cli_state *ipc_cli, 4298 POLICY_HND *pol, 4299 char *filename, 4300 char *attr_name, 4301 char *buf, 4302 int bufsize) 4303{ 4304 uint32 i; 4305 int n = 0; 4306 int n_used; 4307 BOOL all; 4308 BOOL all_nt; 4309 BOOL all_nt_acls; 4310 BOOL all_dos; 4311 BOOL some_nt; 4312 BOOL some_dos; 4313 BOOL exclude_nt_revision = False; 4314 BOOL exclude_nt_owner = False; 4315 BOOL exclude_nt_group = False; 4316 BOOL exclude_nt_acl = False; 4317 BOOL exclude_dos_mode = False; 4318 BOOL exclude_dos_size = False; 4319 BOOL exclude_dos_create_time = False; 4320 BOOL exclude_dos_access_time = False; 4321 BOOL exclude_dos_write_time = False; 4322 BOOL exclude_dos_change_time = False; 4323 BOOL exclude_dos_inode = False; 4324 BOOL numeric = True; 4325 BOOL determine_size = (bufsize == 0); 4326 int fnum = -1; 4327 SEC_DESC *sd; 4328 fstring sidstr; 4329 fstring name_sandbox; 4330 char *name; 4331 char *pExclude; 4332 char *p; 4333 struct timespec create_time_ts; 4334 struct timespec write_time_ts; 4335 struct timespec access_time_ts; 4336 struct timespec change_time_ts; 4337 time_t create_time = (time_t)0; 4338 time_t write_time = (time_t)0; 4339 time_t access_time = (time_t)0; 4340 time_t change_time = (time_t)0; 4341 SMB_OFF_T size = 0; 4342 uint16 mode = 0; 4343 SMB_INO_T ino = 0; 4344 struct cli_state *cli = srv->cli; 4345 struct { 4346 const char * create_time_attr; 4347 const char * access_time_attr; 4348 const char * write_time_attr; 4349 const char * change_time_attr; 4350 } attr_strings; 4351 struct { 4352 const char * create_time_attr; 4353 const char * access_time_attr; 4354 const char * write_time_attr; 4355 const char * change_time_attr; 4356 } excl_attr_strings; 4357 4358 /* Determine whether to use old-style or new-style attribute names */ 4359 if (context->internal->_full_time_names) { 4360 /* new-style names */ 4361 attr_strings.create_time_attr = "CREATE_TIME"; 4362 attr_strings.access_time_attr = "ACCESS_TIME"; 4363 attr_strings.write_time_attr = "WRITE_TIME"; 4364 attr_strings.change_time_attr = "CHANGE_TIME"; 4365 4366 excl_attr_strings.create_time_attr = "CREATE_TIME"; 4367 excl_attr_strings.access_time_attr = "ACCESS_TIME"; 4368 excl_attr_strings.write_time_attr = "WRITE_TIME"; 4369 excl_attr_strings.change_time_attr = "CHANGE_TIME"; 4370 } else { 4371 /* old-style names */ 4372 attr_strings.create_time_attr = NULL; 4373 attr_strings.access_time_attr = "A_TIME"; 4374 attr_strings.write_time_attr = "M_TIME"; 4375 attr_strings.change_time_attr = "C_TIME"; 4376 4377 excl_attr_strings.create_time_attr = NULL; 4378 excl_attr_strings.access_time_attr = "dos_attr.A_TIME"; 4379 excl_attr_strings.write_time_attr = "dos_attr.M_TIME"; 4380 excl_attr_strings.change_time_attr = "dos_attr.C_TIME"; 4381 } 4382 4383 /* Copy name so we can strip off exclusions (if any are specified) */ 4384 strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1); 4385 4386 /* Ensure name is null terminated */ 4387 name_sandbox[sizeof(name_sandbox) - 1] = '\0'; 4388 4389 /* Play in the sandbox */ 4390 name = name_sandbox; 4391 4392 /* If there are any exclusions, point to them and mask them from name */ 4393 if ((pExclude = strchr(name, '!')) != NULL) 4394 { 4395 *pExclude++ = '\0'; 4396 } 4397 4398 all = (StrnCaseCmp(name, "system.*", 8) == 0); 4399 all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0); 4400 all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0); 4401 all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0); 4402 some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0); 4403 some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0); 4404 numeric = (* (name + strlen(name) - 1) != '+'); 4405 4406 /* Look for exclusions from "all" requests */ 4407 if (all || all_nt || all_dos) { 4408 4409 /* Exclusions are delimited by '!' */ 4410 for (; 4411 pExclude != NULL; 4412 pExclude = (p == NULL ? NULL : p + 1)) { 4413 4414 /* Find end of this exclusion name */ 4415 if ((p = strchr(pExclude, '!')) != NULL) 4416 { 4417 *p = '\0'; 4418 } 4419 4420 /* Which exclusion name is this? */ 4421 if (StrCaseCmp(pExclude, "nt_sec_desc.revision") == 0) { 4422 exclude_nt_revision = True; 4423 } 4424 else if (StrCaseCmp(pExclude, "nt_sec_desc.owner") == 0) { 4425 exclude_nt_owner = True; 4426 } 4427 else if (StrCaseCmp(pExclude, "nt_sec_desc.group") == 0) { 4428 exclude_nt_group = True; 4429 } 4430 else if (StrCaseCmp(pExclude, "nt_sec_desc.acl") == 0) { 4431 exclude_nt_acl = True; 4432 } 4433 else if (StrCaseCmp(pExclude, "dos_attr.mode") == 0) { 4434 exclude_dos_mode = True; 4435 } 4436 else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) { 4437 exclude_dos_size = True; 4438 } 4439 else if (excl_attr_strings.create_time_attr != NULL && 4440 StrCaseCmp(pExclude, 4441 excl_attr_strings.change_time_attr) == 0) { 4442 exclude_dos_create_time = True; 4443 } 4444 else if (StrCaseCmp(pExclude, 4445 excl_attr_strings.access_time_attr) == 0) { 4446 exclude_dos_access_time = True; 4447 } 4448 else if (StrCaseCmp(pExclude, 4449 excl_attr_strings.write_time_attr) == 0) { 4450 exclude_dos_write_time = True; 4451 } 4452 else if (StrCaseCmp(pExclude, 4453 excl_attr_strings.change_time_attr) == 0) { 4454 exclude_dos_change_time = True; 4455 } 4456 else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) { 4457 exclude_dos_inode = True; 4458 } 4459 else { 4460 DEBUG(5, ("cacl_get received unknown exclusion: %s\n", 4461 pExclude)); 4462 errno = ENOATTR; 4463 return -1; 4464 } 4465 } 4466 } 4467 4468 n_used = 0; 4469 4470 /* 4471 * If we are (possibly) talking to an NT or new system and some NT 4472 * attributes have been requested... 4473 */ 4474 if (ipc_cli && (all || some_nt || all_nt_acls)) { 4475 /* Point to the portion after "system.nt_sec_desc." */ 4476 name += 19; /* if (all) this will be invalid but unused */ 4477 4478 /* ... then obtain any NT attributes which were requested */ 4479 fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); 4480 4481 if (fnum == -1) { 4482 DEBUG(5, ("cacl_get failed to open %s: %s\n", 4483 filename, cli_errstr(cli))); 4484 errno = 0; 4485 return -1; 4486 } 4487 4488 sd = cli_query_secdesc(cli, fnum, ctx); 4489 4490 if (!sd) { 4491 DEBUG(5, 4492 ("cacl_get Failed to query old descriptor\n")); 4493 errno = 0; 4494 return -1; 4495 } 4496 4497 cli_close(cli, fnum); 4498 4499 if (! exclude_nt_revision) { 4500 if (all || all_nt) { 4501 if (determine_size) { 4502 p = talloc_asprintf(ctx, 4503 "REVISION:%d", 4504 sd->revision); 4505 if (!p) { 4506 errno = ENOMEM; 4507 return -1; 4508 } 4509 n = strlen(p); 4510 } else { 4511 n = snprintf(buf, bufsize, 4512 "REVISION:%d", 4513 sd->revision); 4514 } 4515 } else if (StrCaseCmp(name, "revision") == 0) { 4516 if (determine_size) { 4517 p = talloc_asprintf(ctx, "%d", 4518 sd->revision); 4519 if (!p) { 4520 errno = ENOMEM; 4521 return -1; 4522 } 4523 n = strlen(p); 4524 } else { 4525 n = snprintf(buf, bufsize, "%d", 4526 sd->revision); 4527 } 4528 } 4529 4530 if (!determine_size && n > bufsize) { 4531 errno = ERANGE; 4532 return -1; 4533 } 4534 buf += n; 4535 n_used += n; 4536 bufsize -= n; 4537 } 4538 4539 if (! exclude_nt_owner) { 4540 /* Get owner and group sid */ 4541 if (sd->owner_sid) { 4542 convert_sid_to_string(ipc_cli, pol, 4543 sidstr, 4544 numeric, 4545 sd->owner_sid); 4546 } else { 4547 fstrcpy(sidstr, ""); 4548 } 4549 4550 if (all || all_nt) { 4551 if (determine_size) { 4552 p = talloc_asprintf(ctx, ",OWNER:%s", 4553 sidstr); 4554 if (!p) { 4555 errno = ENOMEM; 4556 return -1; 4557 } 4558 n = strlen(p); 4559 } else if (sidstr[0] != '\0') { 4560 n = snprintf(buf, bufsize, 4561 ",OWNER:%s", sidstr); 4562 } 4563 } else if (StrnCaseCmp(name, "owner", 5) == 0) { 4564 if (determine_size) { 4565 p = talloc_asprintf(ctx, "%s", sidstr); 4566 if (!p) { 4567 errno = ENOMEM; 4568 return -1; 4569 } 4570 n = strlen(p); 4571 } else { 4572 n = snprintf(buf, bufsize, "%s", 4573 sidstr); 4574 } 4575 } 4576 4577 if (!determine_size && n > bufsize) { 4578 errno = ERANGE; 4579 return -1; 4580 } 4581 buf += n; 4582 n_used += n; 4583 bufsize -= n; 4584 } 4585 4586 if (! exclude_nt_group) { 4587 if (sd->group_sid) { 4588 convert_sid_to_string(ipc_cli, pol, 4589 sidstr, numeric, 4590 sd->group_sid); 4591 } else { 4592 fstrcpy(sidstr, ""); 4593 } 4594 4595 if (all || all_nt) { 4596 if (determine_size) { 4597 p = talloc_asprintf(ctx, ",GROUP:%s", 4598 sidstr); 4599 if (!p) { 4600 errno = ENOMEM; 4601 return -1; 4602 } 4603 n = strlen(p); 4604 } else if (sidstr[0] != '\0') { 4605 n = snprintf(buf, bufsize, 4606 ",GROUP:%s", sidstr); 4607 } 4608 } else if (StrnCaseCmp(name, "group", 5) == 0) { 4609 if (determine_size) { 4610 p = talloc_asprintf(ctx, "%s", sidstr); 4611 if (!p) { 4612 errno = ENOMEM; 4613 return -1; 4614 } 4615 n = strlen(p); 4616 } else { 4617 n = snprintf(buf, bufsize, 4618 "%s", sidstr); 4619 } 4620 } 4621 4622 if (!determine_size && n > bufsize) { 4623 errno = ERANGE; 4624 return -1; 4625 } 4626 buf += n; 4627 n_used += n; 4628 bufsize -= n; 4629 } 4630 4631 if (! exclude_nt_acl) { 4632 /* Add aces to value buffer */ 4633 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { 4634 4635 SEC_ACE *ace = &sd->dacl->aces[i]; 4636 convert_sid_to_string(ipc_cli, pol, 4637 sidstr, numeric, 4638 &ace->trustee); 4639 4640 if (all || all_nt) { 4641 if (determine_size) { 4642 p = talloc_asprintf( 4643 ctx, 4644 ",ACL:" 4645 "%s:%d/%d/0x%08x", 4646 sidstr, 4647 ace->type, 4648 ace->flags, 4649 ace->access_mask); 4650 if (!p) { 4651 errno = ENOMEM; 4652 return -1; 4653 } 4654 n = strlen(p); 4655 } else { 4656 n = snprintf( 4657 buf, bufsize, 4658 ",ACL:%s:%d/%d/0x%08x", 4659 sidstr, 4660 ace->type, 4661 ace->flags, 4662 ace->access_mask); 4663 } 4664 } else if ((StrnCaseCmp(name, "acl", 3) == 0 && 4665 StrCaseCmp(name+3, sidstr) == 0) || 4666 (StrnCaseCmp(name, "acl+", 4) == 0 && 4667 StrCaseCmp(name+4, sidstr) == 0)) { 4668 if (determine_size) { 4669 p = talloc_asprintf( 4670 ctx, 4671 "%d/%d/0x%08x", 4672 ace->type, 4673 ace->flags, 4674 ace->access_mask); 4675 if (!p) { 4676 errno = ENOMEM; 4677 return -1; 4678 } 4679 n = strlen(p); 4680 } else { 4681 n = snprintf(buf, bufsize, 4682 "%d/%d/0x%08x", 4683 ace->type, 4684 ace->flags, 4685 ace->access_mask); 4686 } 4687 } else if (all_nt_acls) { 4688 if (determine_size) { 4689 p = talloc_asprintf( 4690 ctx, 4691 "%s%s:%d/%d/0x%08x", 4692 i ? "," : "", 4693 sidstr, 4694 ace->type, 4695 ace->flags, 4696 ace->access_mask); 4697 if (!p) { 4698 errno = ENOMEM; 4699 return -1; 4700 } 4701 n = strlen(p); 4702 } else { 4703 n = snprintf(buf, bufsize, 4704 "%s%s:%d/%d/0x%08x", 4705 i ? "," : "", 4706 sidstr, 4707 ace->type, 4708 ace->flags, 4709 ace->access_mask); 4710 } 4711 } 4712 if (!determine_size && n > bufsize) { 4713 errno = ERANGE; 4714 return -1; 4715 } 4716 buf += n; 4717 n_used += n; 4718 bufsize -= n; 4719 } 4720 } 4721 4722 /* Restore name pointer to its original value */ 4723 name -= 19; 4724 } 4725 4726 if (all || some_dos) { 4727 /* Point to the portion after "system.dos_attr." */ 4728 name += 16; /* if (all) this will be invalid but unused */ 4729 4730 /* Obtain the DOS attributes */ 4731 if (!smbc_getatr(context, srv, filename, &mode, &size, 4732 &create_time_ts, 4733 &access_time_ts, 4734 &write_time_ts, 4735 &change_time_ts, 4736 &ino)) { 4737 4738 errno = smbc_errno(context, srv->cli); 4739 return -1; 4740 4741 } 4742 4743 create_time = convert_timespec_to_time_t(create_time_ts); 4744 access_time = convert_timespec_to_time_t(access_time_ts); 4745 write_time = convert_timespec_to_time_t(write_time_ts); 4746 change_time = convert_timespec_to_time_t(change_time_ts); 4747 4748 if (! exclude_dos_mode) { 4749 if (all || all_dos) { 4750 if (determine_size) { 4751 p = talloc_asprintf(ctx, 4752 "%sMODE:0x%x", 4753 (ipc_cli && 4754 (all || some_nt) 4755 ? "," 4756 : ""), 4757 mode); 4758 if (!p) { 4759 errno = ENOMEM; 4760 return -1; 4761 } 4762 n = strlen(p); 4763 } else { 4764 n = snprintf(buf, bufsize, 4765 "%sMODE:0x%x", 4766 (ipc_cli && 4767 (all || some_nt) 4768 ? "," 4769 : ""), 4770 mode); 4771 } 4772 } else if (StrCaseCmp(name, "mode") == 0) { 4773 if (determine_size) { 4774 p = talloc_asprintf(ctx, "0x%x", mode); 4775 if (!p) { 4776 errno = ENOMEM; 4777 return -1; 4778 } 4779 n = strlen(p); 4780 } else { 4781 n = snprintf(buf, bufsize, 4782 "0x%x", mode); 4783 } 4784 } 4785 4786 if (!determine_size && n > bufsize) { 4787 errno = ERANGE; 4788 return -1; 4789 } 4790 buf += n; 4791 n_used += n; 4792 bufsize -= n; 4793 } 4794 4795 if (! exclude_dos_size) { 4796 if (all || all_dos) { 4797 if (determine_size) { 4798 p = talloc_asprintf( 4799 ctx, 4800 ",SIZE:%.0f", 4801 (double)size); 4802 if (!p) { 4803 errno = ENOMEM; 4804 return -1; 4805 } 4806 n = strlen(p); 4807 } else { 4808 n = snprintf(buf, bufsize, 4809 ",SIZE:%.0f", 4810 (double)size); 4811 } 4812 } else if (StrCaseCmp(name, "size") == 0) { 4813 if (determine_size) { 4814 p = talloc_asprintf( 4815 ctx, 4816 "%.0f", 4817 (double)size); 4818 if (!p) { 4819 errno = ENOMEM; 4820 return -1; 4821 } 4822 n = strlen(p); 4823 } else { 4824 n = snprintf(buf, bufsize, 4825 "%.0f", 4826 (double)size); 4827 } 4828 } 4829 4830 if (!determine_size && n > bufsize) { 4831 errno = ERANGE; 4832 return -1; 4833 } 4834 buf += n; 4835 n_used += n; 4836 bufsize -= n; 4837 } 4838 4839 if (! exclude_dos_create_time && 4840 attr_strings.create_time_attr != NULL) { 4841 if (all || all_dos) { 4842 if (determine_size) { 4843 p = talloc_asprintf(ctx, 4844 ",%s:%lu", 4845 attr_strings.create_time_attr, 4846 create_time); 4847 if (!p) { 4848 errno = ENOMEM; 4849 return -1; 4850 } 4851 n = strlen(p); 4852 } else { 4853 n = snprintf(buf, bufsize, 4854 ",%s:%lu", 4855 attr_strings.create_time_attr, 4856 create_time); 4857 } 4858 } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) { 4859 if (determine_size) { 4860 p = talloc_asprintf(ctx, "%lu", create_time); 4861 if (!p) { 4862 errno = ENOMEM; 4863 return -1; 4864 } 4865 n = strlen(p); 4866 } else { 4867 n = snprintf(buf, bufsize, 4868 "%lu", create_time); 4869 } 4870 } 4871 4872 if (!determine_size && n > bufsize) { 4873 errno = ERANGE; 4874 return -1; 4875 } 4876 buf += n; 4877 n_used += n; 4878 bufsize -= n; 4879 } 4880 4881 if (! exclude_dos_access_time) { 4882 if (all || all_dos) { 4883 if (determine_size) { 4884 p = talloc_asprintf(ctx, 4885 ",%s:%lu", 4886 attr_strings.access_time_attr, 4887 access_time); 4888 if (!p) { 4889 errno = ENOMEM; 4890 return -1; 4891 } 4892 n = strlen(p); 4893 } else { 4894 n = snprintf(buf, bufsize, 4895 ",%s:%lu", 4896 attr_strings.access_time_attr, 4897 access_time); 4898 } 4899 } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) { 4900 if (determine_size) { 4901 p = talloc_asprintf(ctx, "%lu", access_time); 4902 if (!p) { 4903 errno = ENOMEM; 4904 return -1; 4905 } 4906 n = strlen(p); 4907 } else { 4908 n = snprintf(buf, bufsize, 4909 "%lu", access_time); 4910 } 4911 } 4912 4913 if (!determine_size && n > bufsize) { 4914 errno = ERANGE; 4915 return -1; 4916 } 4917 buf += n; 4918 n_used += n; 4919 bufsize -= n; 4920 } 4921 4922 if (! exclude_dos_write_time) { 4923 if (all || all_dos) { 4924 if (determine_size) { 4925 p = talloc_asprintf(ctx, 4926 ",%s:%lu", 4927 attr_strings.write_time_attr, 4928 write_time); 4929 if (!p) { 4930 errno = ENOMEM; 4931 return -1; 4932 } 4933 n = strlen(p); 4934 } else { 4935 n = snprintf(buf, bufsize, 4936 ",%s:%lu", 4937 attr_strings.write_time_attr, 4938 write_time); 4939 } 4940 } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) { 4941 if (determine_size) { 4942 p = talloc_asprintf(ctx, "%lu", write_time); 4943 if (!p) { 4944 errno = ENOMEM; 4945 return -1; 4946 } 4947 n = strlen(p); 4948 } else { 4949 n = snprintf(buf, bufsize, 4950 "%lu", write_time); 4951 } 4952 } 4953 4954 if (!determine_size && n > bufsize) { 4955 errno = ERANGE; 4956 return -1; 4957 } 4958 buf += n; 4959 n_used += n; 4960 bufsize -= n; 4961 } 4962 4963 if (! exclude_dos_change_time) { 4964 if (all || all_dos) { 4965 if (determine_size) { 4966 p = talloc_asprintf(ctx, 4967 ",%s:%lu", 4968 attr_strings.change_time_attr, 4969 change_time); 4970 if (!p) { 4971 errno = ENOMEM; 4972 return -1; 4973 } 4974 n = strlen(p); 4975 } else { 4976 n = snprintf(buf, bufsize, 4977 ",%s:%lu", 4978 attr_strings.change_time_attr, 4979 change_time); 4980 } 4981 } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) { 4982 if (determine_size) { 4983 p = talloc_asprintf(ctx, "%lu", change_time); 4984 if (!p) { 4985 errno = ENOMEM; 4986 return -1; 4987 } 4988 n = strlen(p); 4989 } else { 4990 n = snprintf(buf, bufsize, 4991 "%lu", change_time); 4992 } 4993 } 4994 4995 if (!determine_size && n > bufsize) { 4996 errno = ERANGE; 4997 return -1; 4998 } 4999 buf += n; 5000 n_used += n; 5001 bufsize -= n; 5002 } 5003 5004 if (! exclude_dos_inode) { 5005 if (all || all_dos) { 5006 if (determine_size) { 5007 p = talloc_asprintf( 5008 ctx, 5009 ",INODE:%.0f", 5010 (double)ino); 5011 if (!p) { 5012 errno = ENOMEM; 5013 return -1; 5014 } 5015 n = strlen(p); 5016 } else { 5017 n = snprintf(buf, bufsize, 5018 ",INODE:%.0f", 5019 (double) ino); 5020 } 5021 } else if (StrCaseCmp(name, "inode") == 0) { 5022 if (determine_size) { 5023 p = talloc_asprintf( 5024 ctx, 5025 "%.0f", 5026 (double) ino); 5027 if (!p) { 5028 errno = ENOMEM; 5029 return -1; 5030 } 5031 n = strlen(p); 5032 } else { 5033 n = snprintf(buf, bufsize, 5034 "%.0f", 5035 (double) ino); 5036 } 5037 } 5038 5039 if (!determine_size && n > bufsize) { 5040 errno = ERANGE; 5041 return -1; 5042 } 5043 buf += n; 5044 n_used += n; 5045 bufsize -= n; 5046 } 5047 5048 /* Restore name pointer to its original value */ 5049 name -= 16; 5050 } 5051 5052 if (n_used == 0) { 5053 errno = ENOATTR; 5054 return -1; 5055 } 5056 5057 return n_used; 5058} 5059 5060 5061/***************************************************** 5062set the ACLs on a file given an ascii description 5063*******************************************************/ 5064static int 5065cacl_set(TALLOC_CTX *ctx, 5066 struct cli_state *cli, 5067 struct cli_state *ipc_cli, 5068 POLICY_HND *pol, 5069 const char *filename, 5070 const char *the_acl, 5071 int mode, 5072 int flags) 5073{ 5074 int fnum; 5075 int err = 0; 5076 SEC_DESC *sd = NULL, *old; 5077 SEC_ACL *dacl = NULL; 5078 DOM_SID *owner_sid = NULL; 5079 DOM_SID *group_sid = NULL; 5080 uint32 i, j; 5081 size_t sd_size; 5082 int ret = 0; 5083 char *p; 5084 BOOL numeric = True; 5085 5086 /* the_acl will be null for REMOVE_ALL operations */ 5087 if (the_acl) { 5088 numeric = ((p = strchr(the_acl, ':')) != NULL && 5089 p > the_acl && 5090 p[-1] != '+'); 5091 5092 /* if this is to set the entire ACL... */ 5093 if (*the_acl == '*') { 5094 /* ... then increment past the first colon */ 5095 the_acl = p + 1; 5096 } 5097 5098 sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, 5099 CONST_DISCARD(char *, the_acl)); 5100 5101 if (!sd) { 5102 errno = EINVAL; 5103 return -1; 5104 } 5105 } 5106 5107 /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller 5108 that doesn't deref sd */ 5109 5110 if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) { 5111 errno = EINVAL; 5112 return -1; 5113 } 5114 5115 /* The desired access below is the only one I could find that works 5116 with NT4, W2KP and Samba */ 5117 5118 fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); 5119 5120 if (fnum == -1) { 5121 DEBUG(5, ("cacl_set failed to open %s: %s\n", 5122 filename, cli_errstr(cli))); 5123 errno = 0; 5124 return -1; 5125 } 5126 5127 old = cli_query_secdesc(cli, fnum, ctx); 5128 5129 if (!old) { 5130 DEBUG(5, ("cacl_set Failed to query old descriptor\n")); 5131 errno = 0; 5132 return -1; 5133 } 5134 5135 cli_close(cli, fnum); 5136 5137 switch (mode) { 5138 case SMBC_XATTR_MODE_REMOVE_ALL: 5139 old->dacl->num_aces = 0; 5140 SAFE_FREE(old->dacl->aces); 5141 SAFE_FREE(old->dacl); 5142 old->dacl = NULL; 5143 dacl = old->dacl; 5144 break; 5145 5146 case SMBC_XATTR_MODE_REMOVE: 5147 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { 5148 BOOL found = False; 5149 5150 for (j=0;old->dacl && j<old->dacl->num_aces;j++) { 5151 if (sec_ace_equal(&sd->dacl->aces[i], 5152 &old->dacl->aces[j])) { 5153 uint32 k; 5154 for (k=j; k<old->dacl->num_aces-1;k++) { 5155 old->dacl->aces[k] = 5156 old->dacl->aces[k+1]; 5157 } 5158 old->dacl->num_aces--; 5159 if (old->dacl->num_aces == 0) { 5160 SAFE_FREE(old->dacl->aces); 5161 SAFE_FREE(old->dacl); 5162 old->dacl = NULL; 5163 } 5164 found = True; 5165 dacl = old->dacl; 5166 break; 5167 } 5168 } 5169 5170 if (!found) { 5171 err = ENOATTR; 5172 ret = -1; 5173 goto failed; 5174 } 5175 } 5176 break; 5177 5178 case SMBC_XATTR_MODE_ADD: 5179 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { 5180 BOOL found = False; 5181 5182 for (j=0;old->dacl && j<old->dacl->num_aces;j++) { 5183 if (sid_equal(&sd->dacl->aces[i].trustee, 5184 &old->dacl->aces[j].trustee)) { 5185 if (!(flags & SMBC_XATTR_FLAG_CREATE)) { 5186 err = EEXIST; 5187 ret = -1; 5188 goto failed; 5189 } 5190 old->dacl->aces[j] = sd->dacl->aces[i]; 5191 ret = -1; 5192 found = True; 5193 } 5194 } 5195 5196 if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) { 5197 err = ENOATTR; 5198 ret = -1; 5199 goto failed; 5200 } 5201 5202 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { 5203 add_ace(&old->dacl, &sd->dacl->aces[i], ctx); 5204 } 5205 } 5206 dacl = old->dacl; 5207 break; 5208 5209 case SMBC_XATTR_MODE_SET: 5210 old = sd; 5211 owner_sid = old->owner_sid; 5212 group_sid = old->group_sid; 5213 dacl = old->dacl; 5214 break; 5215 5216 case SMBC_XATTR_MODE_CHOWN: 5217 owner_sid = sd->owner_sid; 5218 break; 5219 5220 case SMBC_XATTR_MODE_CHGRP: 5221 group_sid = sd->group_sid; 5222 break; 5223 } 5224 5225 /* Denied ACE entries must come before allowed ones */ 5226 sort_acl(old->dacl); 5227 5228 /* Create new security descriptor and set it */ 5229 sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, 5230 owner_sid, group_sid, NULL, dacl, &sd_size); 5231 5232 fnum = cli_nt_create(cli, filename, 5233 WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS); 5234 5235 if (fnum == -1) { 5236 DEBUG(5, ("cacl_set failed to open %s: %s\n", 5237 filename, cli_errstr(cli))); 5238 errno = 0; 5239 return -1; 5240 } 5241 5242 if (!cli_set_secdesc(cli, fnum, sd)) { 5243 DEBUG(5, ("ERROR: secdesc set failed: %s\n", cli_errstr(cli))); 5244 ret = -1; 5245 } 5246 5247 /* Clean up */ 5248 5249 failed: 5250 cli_close(cli, fnum); 5251 5252 if (err != 0) { 5253 errno = err; 5254 } 5255 5256 return ret; 5257} 5258 5259 5260static int 5261smbc_setxattr_ctx(SMBCCTX *context, 5262 const char *fname, 5263 const char *name, 5264 const void *value, 5265 size_t size, 5266 int flags) 5267{ 5268 int ret; 5269 int ret2; 5270 SMBCSRV *srv; 5271 SMBCSRV *ipc_srv; 5272 fstring server; 5273 fstring share; 5274 fstring user; 5275 fstring password; 5276 fstring workgroup; 5277 pstring path; 5278 TALLOC_CTX *ctx; 5279 POLICY_HND pol; 5280 DOS_ATTR_DESC *dad; 5281 struct { 5282 const char * create_time_attr; 5283 const char * access_time_attr; 5284 const char * write_time_attr; 5285 const char * change_time_attr; 5286 } attr_strings; 5287 5288 if (!context || !context->internal || 5289 !context->internal->_initialized) { 5290 5291 errno = EINVAL; /* Best I can think of ... */ 5292 return -1; 5293 5294 } 5295 5296 if (!fname) { 5297 5298 errno = EINVAL; 5299 return -1; 5300 5301 } 5302 5303 DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n", 5304 fname, name, (int) size, (const char*)value)); 5305 5306 if (smbc_parse_path(context, fname, 5307 workgroup, sizeof(workgroup), 5308 server, sizeof(server), 5309 share, sizeof(share), 5310 path, sizeof(path), 5311 user, sizeof(user), 5312 password, sizeof(password), 5313 NULL, 0)) { 5314 errno = EINVAL; 5315 return -1; 5316 } 5317 5318 if (user[0] == (char)0) fstrcpy(user, context->user); 5319 5320 srv = smbc_server(context, True, 5321 server, share, workgroup, user, password); 5322 if (!srv) { 5323 return -1; /* errno set by smbc_server */ 5324 } 5325 5326 if (! srv->no_nt_session) { 5327 ipc_srv = smbc_attr_server(context, server, share, 5328 workgroup, user, password, 5329 &pol); 5330 if (! ipc_srv) { 5331 srv->no_nt_session = True; 5332 } 5333 } else { 5334 ipc_srv = NULL; 5335 } 5336 5337 ctx = talloc_init("smbc_setxattr"); 5338 if (!ctx) { 5339 errno = ENOMEM; 5340 return -1; 5341 } 5342 5343 /* 5344 * Are they asking to set the entire set of known attributes? 5345 */ 5346 if (StrCaseCmp(name, "system.*") == 0 || 5347 StrCaseCmp(name, "system.*+") == 0) { 5348 /* Yup. */ 5349 char *namevalue = 5350 talloc_asprintf(ctx, "%s:%s", 5351 name+7, (const char *) value); 5352 if (! namevalue) { 5353 errno = ENOMEM; 5354 ret = -1; 5355 return -1; 5356 } 5357 5358 if (ipc_srv) { 5359 ret = cacl_set(ctx, srv->cli, 5360 ipc_srv->cli, &pol, path, 5361 namevalue, 5362 (*namevalue == '*' 5363 ? SMBC_XATTR_MODE_SET 5364 : SMBC_XATTR_MODE_ADD), 5365 flags); 5366 } else { 5367 ret = 0; 5368 } 5369 5370 /* get a DOS Attribute Descriptor with current attributes */ 5371 dad = dos_attr_query(context, ctx, path, srv); 5372 if (dad) { 5373 /* Overwrite old with new, using what was provided */ 5374 dos_attr_parse(context, dad, srv, namevalue); 5375 5376 /* Set the new DOS attributes */ 5377 if (! smbc_setatr(context, srv, path, 5378 dad->create_time, 5379 dad->access_time, 5380 dad->write_time, 5381 dad->change_time, 5382 dad->mode)) { 5383 5384 /* cause failure if NT failed too */ 5385 dad = NULL; 5386 } 5387 } 5388 5389 /* we only fail if both NT and DOS sets failed */ 5390 if (ret < 0 && ! dad) { 5391 ret = -1; /* in case dad was null */ 5392 } 5393 else { 5394 ret = 0; 5395 } 5396 5397 talloc_destroy(ctx); 5398 return ret; 5399 } 5400 5401 /* 5402 * Are they asking to set an access control element or to set 5403 * the entire access control list? 5404 */ 5405 if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || 5406 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || 5407 StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || 5408 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || 5409 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { 5410 5411 /* Yup. */ 5412 char *namevalue = 5413 talloc_asprintf(ctx, "%s:%s", 5414 name+19, (const char *) value); 5415 5416 if (! ipc_srv) { 5417 ret = -1; /* errno set by smbc_server() */ 5418 } 5419 else if (! namevalue) { 5420 errno = ENOMEM; 5421 ret = -1; 5422 } else { 5423 ret = cacl_set(ctx, srv->cli, 5424 ipc_srv->cli, &pol, path, 5425 namevalue, 5426 (*namevalue == '*' 5427 ? SMBC_XATTR_MODE_SET 5428 : SMBC_XATTR_MODE_ADD), 5429 flags); 5430 } 5431 talloc_destroy(ctx); 5432 return ret; 5433 } 5434 5435 /* 5436 * Are they asking to set the owner? 5437 */ 5438 if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || 5439 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) { 5440 5441 /* Yup. */ 5442 char *namevalue = 5443 talloc_asprintf(ctx, "%s:%s", 5444 name+19, (const char *) value); 5445 5446 if (! ipc_srv) { 5447 5448 ret = -1; /* errno set by smbc_server() */ 5449 } 5450 else if (! namevalue) { 5451 errno = ENOMEM; 5452 ret = -1; 5453 } else { 5454 ret = cacl_set(ctx, srv->cli, 5455 ipc_srv->cli, &pol, path, 5456 namevalue, SMBC_XATTR_MODE_CHOWN, 0); 5457 } 5458 talloc_destroy(ctx); 5459 return ret; 5460 } 5461 5462 /* 5463 * Are they asking to set the group? 5464 */ 5465 if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || 5466 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) { 5467 5468 /* Yup. */ 5469 char *namevalue = 5470 talloc_asprintf(ctx, "%s:%s", 5471 name+19, (const char *) value); 5472 5473 if (! ipc_srv) { 5474 /* errno set by smbc_server() */ 5475 ret = -1; 5476 } 5477 else if (! namevalue) { 5478 errno = ENOMEM; 5479 ret = -1; 5480 } else { 5481 ret = cacl_set(ctx, srv->cli, 5482 ipc_srv->cli, &pol, path, 5483 namevalue, SMBC_XATTR_MODE_CHOWN, 0); 5484 } 5485 talloc_destroy(ctx); 5486 return ret; 5487 } 5488 5489 /* Determine whether to use old-style or new-style attribute names */ 5490 if (context->internal->_full_time_names) { 5491 /* new-style names */ 5492 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; 5493 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; 5494 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; 5495 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; 5496 } else { 5497 /* old-style names */ 5498 attr_strings.create_time_attr = NULL; 5499 attr_strings.access_time_attr = "system.dos_attr.A_TIME"; 5500 attr_strings.write_time_attr = "system.dos_attr.M_TIME"; 5501 attr_strings.change_time_attr = "system.dos_attr.C_TIME"; 5502 } 5503 5504 /* 5505 * Are they asking to set a DOS attribute? 5506 */ 5507 if (StrCaseCmp(name, "system.dos_attr.*") == 0 || 5508 StrCaseCmp(name, "system.dos_attr.mode") == 0 || 5509 (attr_strings.create_time_attr != NULL && 5510 StrCaseCmp(name, attr_strings.create_time_attr) == 0) || 5511 StrCaseCmp(name, attr_strings.access_time_attr) == 0 || 5512 StrCaseCmp(name, attr_strings.write_time_attr) == 0 || 5513 StrCaseCmp(name, attr_strings.change_time_attr) == 0) { 5514 5515 /* get a DOS Attribute Descriptor with current attributes */ 5516 dad = dos_attr_query(context, ctx, path, srv); 5517 if (dad) { 5518 char *namevalue = 5519 talloc_asprintf(ctx, "%s:%s", 5520 name+16, (const char *) value); 5521 if (! namevalue) { 5522 errno = ENOMEM; 5523 ret = -1; 5524 } else { 5525 /* Overwrite old with provided new params */ 5526 dos_attr_parse(context, dad, srv, namevalue); 5527 5528 /* Set the new DOS attributes */ 5529 ret2 = smbc_setatr(context, srv, path, 5530 dad->create_time, 5531 dad->access_time, 5532 dad->write_time, 5533 dad->change_time, 5534 dad->mode); 5535 5536 /* ret2 has True (success) / False (failure) */ 5537 if (ret2) { 5538 ret = 0; 5539 } else { 5540 ret = -1; 5541 } 5542 } 5543 } else { 5544 ret = -1; 5545 } 5546 5547 talloc_destroy(ctx); 5548 return ret; 5549 } 5550 5551 /* Unsupported attribute name */ 5552 talloc_destroy(ctx); 5553 errno = EINVAL; 5554 return -1; 5555} 5556 5557static int 5558smbc_getxattr_ctx(SMBCCTX *context, 5559 const char *fname, 5560 const char *name, 5561 const void *value, 5562 size_t size) 5563{ 5564 int ret; 5565 SMBCSRV *srv; 5566 SMBCSRV *ipc_srv; 5567 fstring server; 5568 fstring share; 5569 fstring user; 5570 fstring password; 5571 fstring workgroup; 5572 pstring path; 5573 TALLOC_CTX *ctx; 5574 POLICY_HND pol; 5575 struct { 5576 const char * create_time_attr; 5577 const char * access_time_attr; 5578 const char * write_time_attr; 5579 const char * change_time_attr; 5580 } attr_strings; 5581 5582 5583 if (!context || !context->internal || 5584 !context->internal->_initialized) { 5585 5586 errno = EINVAL; /* Best I can think of ... */ 5587 return -1; 5588 5589 } 5590 5591 if (!fname) { 5592 5593 errno = EINVAL; 5594 return -1; 5595 5596 } 5597 5598 DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name)); 5599 5600 if (smbc_parse_path(context, fname, 5601 workgroup, sizeof(workgroup), 5602 server, sizeof(server), 5603 share, sizeof(share), 5604 path, sizeof(path), 5605 user, sizeof(user), 5606 password, sizeof(password), 5607 NULL, 0)) { 5608 errno = EINVAL; 5609 return -1; 5610 } 5611 5612 if (user[0] == (char)0) fstrcpy(user, context->user); 5613 5614 srv = smbc_server(context, True, 5615 server, share, workgroup, user, password); 5616 if (!srv) { 5617 return -1; /* errno set by smbc_server */ 5618 } 5619 5620 if (! srv->no_nt_session) { 5621 ipc_srv = smbc_attr_server(context, server, share, 5622 workgroup, user, password, 5623 &pol); 5624 if (! ipc_srv) { 5625 srv->no_nt_session = True; 5626 } 5627 } else { 5628 ipc_srv = NULL; 5629 } 5630 5631 ctx = talloc_init("smbc:getxattr"); 5632 if (!ctx) { 5633 errno = ENOMEM; 5634 return -1; 5635 } 5636 5637 /* Determine whether to use old-style or new-style attribute names */ 5638 if (context->internal->_full_time_names) { 5639 /* new-style names */ 5640 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; 5641 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; 5642 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; 5643 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; 5644 } else { 5645 /* old-style names */ 5646 attr_strings.create_time_attr = NULL; 5647 attr_strings.access_time_attr = "system.dos_attr.A_TIME"; 5648 attr_strings.write_time_attr = "system.dos_attr.M_TIME"; 5649 attr_strings.change_time_attr = "system.dos_attr.C_TIME"; 5650 } 5651 5652 /* Are they requesting a supported attribute? */ 5653 if (StrCaseCmp(name, "system.*") == 0 || 5654 StrnCaseCmp(name, "system.*!", 9) == 0 || 5655 StrCaseCmp(name, "system.*+") == 0 || 5656 StrnCaseCmp(name, "system.*+!", 10) == 0 || 5657 StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || 5658 StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 || 5659 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || 5660 StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 || 5661 StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || 5662 StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || 5663 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || 5664 StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || 5665 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || 5666 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || 5667 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 || 5668 StrCaseCmp(name, "system.dos_attr.*") == 0 || 5669 StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 || 5670 StrCaseCmp(name, "system.dos_attr.mode") == 0 || 5671 StrCaseCmp(name, "system.dos_attr.size") == 0 || 5672 (attr_strings.create_time_attr != NULL && 5673 StrCaseCmp(name, attr_strings.create_time_attr) == 0) || 5674 StrCaseCmp(name, attr_strings.access_time_attr) == 0 || 5675 StrCaseCmp(name, attr_strings.write_time_attr) == 0 || 5676 StrCaseCmp(name, attr_strings.change_time_attr) == 0 || 5677 StrCaseCmp(name, "system.dos_attr.inode") == 0) { 5678 5679 /* Yup. */ 5680 ret = cacl_get(context, ctx, srv, 5681 ipc_srv == NULL ? NULL : ipc_srv->cli, 5682 &pol, path, 5683 CONST_DISCARD(char *, name), 5684 CONST_DISCARD(char *, value), size); 5685 if (ret < 0 && errno == 0) { 5686 errno = smbc_errno(context, srv->cli); 5687 } 5688 talloc_destroy(ctx); 5689 return ret; 5690 } 5691 5692 /* Unsupported attribute name */ 5693 talloc_destroy(ctx); 5694 errno = EINVAL; 5695 return -1; 5696} 5697 5698 5699static int 5700smbc_removexattr_ctx(SMBCCTX *context, 5701 const char *fname, 5702 const char *name) 5703{ 5704 int ret; 5705 SMBCSRV *srv; 5706 SMBCSRV *ipc_srv; 5707 fstring server; 5708 fstring share; 5709 fstring user; 5710 fstring password; 5711 fstring workgroup; 5712 pstring path; 5713 TALLOC_CTX *ctx; 5714 POLICY_HND pol; 5715 5716 if (!context || !context->internal || 5717 !context->internal->_initialized) { 5718 5719 errno = EINVAL; /* Best I can think of ... */ 5720 return -1; 5721 5722 } 5723 5724 if (!fname) { 5725 5726 errno = EINVAL; 5727 return -1; 5728 5729 } 5730 5731 DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name)); 5732 5733 if (smbc_parse_path(context, fname, 5734 workgroup, sizeof(workgroup), 5735 server, sizeof(server), 5736 share, sizeof(share), 5737 path, sizeof(path), 5738 user, sizeof(user), 5739 password, sizeof(password), 5740 NULL, 0)) { 5741 errno = EINVAL; 5742 return -1; 5743 } 5744 5745 if (user[0] == (char)0) fstrcpy(user, context->user); 5746 5747 srv = smbc_server(context, True, 5748 server, share, workgroup, user, password); 5749 if (!srv) { 5750 return -1; /* errno set by smbc_server */ 5751 } 5752 5753 if (! srv->no_nt_session) { 5754 ipc_srv = smbc_attr_server(context, server, share, 5755 workgroup, user, password, 5756 &pol); 5757 if (! ipc_srv) { 5758 srv->no_nt_session = True; 5759 } 5760 } else { 5761 ipc_srv = NULL; 5762 } 5763 5764 if (! ipc_srv) { 5765 return -1; /* errno set by smbc_attr_server */ 5766 } 5767 5768 ctx = talloc_init("smbc_removexattr"); 5769 if (!ctx) { 5770 errno = ENOMEM; 5771 return -1; 5772 } 5773 5774 /* Are they asking to set the entire ACL? */ 5775 if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || 5776 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) { 5777 5778 /* Yup. */ 5779 ret = cacl_set(ctx, srv->cli, 5780 ipc_srv->cli, &pol, path, 5781 NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0); 5782 talloc_destroy(ctx); 5783 return ret; 5784 } 5785 5786 /* 5787 * Are they asking to remove one or more spceific security descriptor 5788 * attributes? 5789 */ 5790 if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || 5791 StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || 5792 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || 5793 StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || 5794 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || 5795 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || 5796 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { 5797 5798 /* Yup. */ 5799 ret = cacl_set(ctx, srv->cli, 5800 ipc_srv->cli, &pol, path, 5801 name + 19, SMBC_XATTR_MODE_REMOVE, 0); 5802 talloc_destroy(ctx); 5803 return ret; 5804 } 5805 5806 /* Unsupported attribute name */ 5807 talloc_destroy(ctx); 5808 errno = EINVAL; 5809 return -1; 5810} 5811 5812static int 5813smbc_listxattr_ctx(SMBCCTX *context, 5814 const char *fname, 5815 char *list, 5816 size_t size) 5817{ 5818 /* 5819 * This isn't quite what listxattr() is supposed to do. This returns 5820 * the complete set of attribute names, always, rather than only those 5821 * attribute names which actually exist for a file. Hmmm... 5822 */ 5823 const char supported_old[] = 5824 "system.*\0" 5825 "system.*+\0" 5826 "system.nt_sec_desc.revision\0" 5827 "system.nt_sec_desc.owner\0" 5828 "system.nt_sec_desc.owner+\0" 5829 "system.nt_sec_desc.group\0" 5830 "system.nt_sec_desc.group+\0" 5831 "system.nt_sec_desc.acl.*\0" 5832 "system.nt_sec_desc.acl\0" 5833 "system.nt_sec_desc.acl+\0" 5834 "system.nt_sec_desc.*\0" 5835 "system.nt_sec_desc.*+\0" 5836 "system.dos_attr.*\0" 5837 "system.dos_attr.mode\0" 5838 "system.dos_attr.c_time\0" 5839 "system.dos_attr.a_time\0" 5840 "system.dos_attr.m_time\0" 5841 ; 5842 const char supported_new[] = 5843 "system.*\0" 5844 "system.*+\0" 5845 "system.nt_sec_desc.revision\0" 5846 "system.nt_sec_desc.owner\0" 5847 "system.nt_sec_desc.owner+\0" 5848 "system.nt_sec_desc.group\0" 5849 "system.nt_sec_desc.group+\0" 5850 "system.nt_sec_desc.acl.*\0" 5851 "system.nt_sec_desc.acl\0" 5852 "system.nt_sec_desc.acl+\0" 5853 "system.nt_sec_desc.*\0" 5854 "system.nt_sec_desc.*+\0" 5855 "system.dos_attr.*\0" 5856 "system.dos_attr.mode\0" 5857 "system.dos_attr.create_time\0" 5858 "system.dos_attr.access_time\0" 5859 "system.dos_attr.write_time\0" 5860 "system.dos_attr.change_time\0" 5861 ; 5862 const char * supported; 5863 5864 if (context->internal->_full_time_names) { 5865 supported = supported_new; 5866 } else { 5867 supported = supported_old; 5868 } 5869 5870 if (size == 0) { 5871 return sizeof(supported); 5872 } 5873 5874 if (sizeof(supported) > size) { 5875 errno = ERANGE; 5876 return -1; 5877 } 5878 5879 /* this can't be strcpy() because there are embedded null characters */ 5880 memcpy(list, supported, sizeof(supported)); 5881 return sizeof(supported); 5882} 5883 5884 5885/* 5886 * Open a print file to be written to by other calls 5887 */ 5888 5889static SMBCFILE * 5890smbc_open_print_job_ctx(SMBCCTX *context, 5891 const char *fname) 5892{ 5893 fstring server; 5894 fstring share; 5895 fstring user; 5896 fstring password; 5897 pstring path; 5898 5899 if (!context || !context->internal || 5900 !context->internal->_initialized) { 5901 5902 errno = EINVAL; 5903 return NULL; 5904 5905 } 5906 5907 if (!fname) { 5908 5909 errno = EINVAL; 5910 return NULL; 5911 5912 } 5913 5914 DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname)); 5915 5916 if (smbc_parse_path(context, fname, 5917 NULL, 0, 5918 server, sizeof(server), 5919 share, sizeof(share), 5920 path, sizeof(path), 5921 user, sizeof(user), 5922 password, sizeof(password), 5923 NULL, 0)) { 5924 errno = EINVAL; 5925 return NULL; 5926 } 5927 5928 /* What if the path is empty, or the file exists? */ 5929 5930 return context->open(context, fname, O_WRONLY, 666); 5931 5932} 5933 5934/* 5935 * Routine to print a file on a remote server ... 5936 * 5937 * We open the file, which we assume to be on a remote server, and then 5938 * copy it to a print file on the share specified by printq. 5939 */ 5940 5941static int 5942smbc_print_file_ctx(SMBCCTX *c_file, 5943 const char *fname, 5944 SMBCCTX *c_print, 5945 const char *printq) 5946{ 5947 SMBCFILE *fid1; 5948 SMBCFILE *fid2; 5949 int bytes; 5950 int saverr; 5951 int tot_bytes = 0; 5952 char buf[4096]; 5953 5954 if (!c_file || !c_file->internal->_initialized || !c_print || 5955 !c_print->internal->_initialized) { 5956 5957 errno = EINVAL; 5958 return -1; 5959 5960 } 5961 5962 if (!fname && !printq) { 5963 5964 errno = EINVAL; 5965 return -1; 5966 5967 } 5968 5969 /* Try to open the file for reading ... */ 5970 5971 if ((long)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) { 5972 5973 DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno)); 5974 return -1; /* smbc_open sets errno */ 5975 5976 } 5977 5978 /* Now, try to open the printer file for writing */ 5979 5980 if ((long)(fid2 = c_print->open_print_job(c_print, printq)) < 0) { 5981 5982 saverr = errno; /* Save errno */ 5983 c_file->close_fn(c_file, fid1); 5984 errno = saverr; 5985 return -1; 5986 5987 } 5988 5989 while ((bytes = c_file->read(c_file, fid1, buf, sizeof(buf))) > 0) { 5990 5991 tot_bytes += bytes; 5992 5993 if ((c_print->write(c_print, fid2, buf, bytes)) < 0) { 5994 5995 saverr = errno; 5996 c_file->close_fn(c_file, fid1); 5997 c_print->close_fn(c_print, fid2); 5998 errno = saverr; 5999 6000 } 6001 6002 } 6003 6004 saverr = errno; 6005 6006 c_file->close_fn(c_file, fid1); /* We have to close these anyway */ 6007 c_print->close_fn(c_print, fid2); 6008 6009 if (bytes < 0) { 6010 6011 errno = saverr; 6012 return -1; 6013 6014 } 6015 6016 return tot_bytes; 6017 6018} 6019 6020/* 6021 * Routine to list print jobs on a printer share ... 6022 */ 6023 6024static int 6025smbc_list_print_jobs_ctx(SMBCCTX *context, 6026 const char *fname, 6027 smbc_list_print_job_fn fn) 6028{ 6029 SMBCSRV *srv; 6030 fstring server; 6031 fstring share; 6032 fstring user; 6033 fstring password; 6034 fstring workgroup; 6035 pstring path; 6036 6037 if (!context || !context->internal || 6038 !context->internal->_initialized) { 6039 6040 errno = EINVAL; 6041 return -1; 6042 6043 } 6044 6045 if (!fname) { 6046 6047 errno = EINVAL; 6048 return -1; 6049 6050 } 6051 6052 DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname)); 6053 6054 if (smbc_parse_path(context, fname, 6055 workgroup, sizeof(workgroup), 6056 server, sizeof(server), 6057 share, sizeof(share), 6058 path, sizeof(path), 6059 user, sizeof(user), 6060 password, sizeof(password), 6061 NULL, 0)) { 6062 errno = EINVAL; 6063 return -1; 6064 } 6065 6066 if (user[0] == (char)0) fstrcpy(user, context->user); 6067 6068 srv = smbc_server(context, True, 6069 server, share, workgroup, user, password); 6070 6071 if (!srv) { 6072 6073 return -1; /* errno set by smbc_server */ 6074 6075 } 6076 6077 if (cli_print_queue(srv->cli, 6078 (void (*)(struct print_job_info *))fn) < 0) { 6079 6080 errno = smbc_errno(context, srv->cli); 6081 return -1; 6082 6083 } 6084 6085 return 0; 6086 6087} 6088 6089/* 6090 * Delete a print job from a remote printer share 6091 */ 6092 6093static int 6094smbc_unlink_print_job_ctx(SMBCCTX *context, 6095 const char *fname, 6096 int id) 6097{ 6098 SMBCSRV *srv; 6099 fstring server; 6100 fstring share; 6101 fstring user; 6102 fstring password; 6103 fstring workgroup; 6104 pstring path; 6105 int err; 6106 6107 if (!context || !context->internal || 6108 !context->internal->_initialized) { 6109 6110 errno = EINVAL; 6111 return -1; 6112 6113 } 6114 6115 if (!fname) { 6116 6117 errno = EINVAL; 6118 return -1; 6119 6120 } 6121 6122 DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname)); 6123 6124 if (smbc_parse_path(context, fname, 6125 workgroup, sizeof(workgroup), 6126 server, sizeof(server), 6127 share, sizeof(share), 6128 path, sizeof(path), 6129 user, sizeof(user), 6130 password, sizeof(password), 6131 NULL, 0)) { 6132 errno = EINVAL; 6133 return -1; 6134 } 6135 6136 if (user[0] == (char)0) fstrcpy(user, context->user); 6137 6138 srv = smbc_server(context, True, 6139 server, share, workgroup, user, password); 6140 6141 if (!srv) { 6142 6143 return -1; /* errno set by smbc_server */ 6144 6145 } 6146 6147 if ((err = cli_printjob_del(srv->cli, id)) != 0) { 6148 6149 if (err < 0) 6150 errno = smbc_errno(context, srv->cli); 6151 else if (err == ERRnosuchprintjob) 6152 errno = EINVAL; 6153 return -1; 6154 6155 } 6156 6157 return 0; 6158 6159} 6160 6161/* 6162 * Get a new empty handle to fill in with your own info 6163 */ 6164SMBCCTX * 6165smbc_new_context(void) 6166{ 6167 SMBCCTX *context; 6168 6169 context = SMB_MALLOC_P(SMBCCTX); 6170 if (!context) { 6171 errno = ENOMEM; 6172 return NULL; 6173 } 6174 6175 ZERO_STRUCTP(context); 6176 6177 context->internal = SMB_MALLOC_P(struct smbc_internal_data); 6178 if (!context->internal) { 6179 SAFE_FREE(context); 6180 errno = ENOMEM; 6181 return NULL; 6182 } 6183 6184 ZERO_STRUCTP(context->internal); 6185 6186 6187 /* ADD REASONABLE DEFAULTS */ 6188 context->debug = 0; 6189 context->timeout = 20000; /* 20 seconds */ 6190 6191 context->options.browse_max_lmb_count = 3; /* # LMBs to query */ 6192 context->options.urlencode_readdir_entries = False;/* backward compat */ 6193 context->options.one_share_per_server = False;/* backward compat */ 6194 context->internal->_share_mode = SMBC_SHAREMODE_DENY_NONE; 6195 /* backward compat */ 6196 6197 context->open = smbc_open_ctx; 6198 context->creat = smbc_creat_ctx; 6199 context->read = smbc_read_ctx; 6200 context->write = smbc_write_ctx; 6201 context->close_fn = smbc_close_ctx; 6202 context->unlink = smbc_unlink_ctx; 6203 context->rename = smbc_rename_ctx; 6204 context->lseek = smbc_lseek_ctx; 6205 context->stat = smbc_stat_ctx; 6206 context->fstat = smbc_fstat_ctx; 6207 context->opendir = smbc_opendir_ctx; 6208 context->closedir = smbc_closedir_ctx; 6209 context->readdir = smbc_readdir_ctx; 6210 context->getdents = smbc_getdents_ctx; 6211 context->mkdir = smbc_mkdir_ctx; 6212 context->rmdir = smbc_rmdir_ctx; 6213 context->telldir = smbc_telldir_ctx; 6214 context->lseekdir = smbc_lseekdir_ctx; 6215 context->fstatdir = smbc_fstatdir_ctx; 6216 context->chmod = smbc_chmod_ctx; 6217 context->utimes = smbc_utimes_ctx; 6218 context->setxattr = smbc_setxattr_ctx; 6219 context->getxattr = smbc_getxattr_ctx; 6220 context->removexattr = smbc_removexattr_ctx; 6221 context->listxattr = smbc_listxattr_ctx; 6222 context->open_print_job = smbc_open_print_job_ctx; 6223 context->print_file = smbc_print_file_ctx; 6224 context->list_print_jobs = smbc_list_print_jobs_ctx; 6225 context->unlink_print_job = smbc_unlink_print_job_ctx; 6226 6227 context->callbacks.check_server_fn = smbc_check_server; 6228 context->callbacks.remove_unused_server_fn = smbc_remove_unused_server; 6229 6230 smbc_default_cache_functions(context); 6231 6232 return context; 6233} 6234 6235/* 6236 * Free a context 6237 * 6238 * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed 6239 * and thus you'll be leaking memory if not handled properly. 6240 * 6241 */ 6242int 6243smbc_free_context(SMBCCTX *context, 6244 int shutdown_ctx) 6245{ 6246 if (!context) { 6247 errno = EBADF; 6248 return 1; 6249 } 6250 6251 if (shutdown_ctx) { 6252 SMBCFILE * f; 6253 DEBUG(1,("Performing aggressive shutdown.\n")); 6254 6255 f = context->internal->_files; 6256 while (f) { 6257 context->close_fn(context, f); 6258 f = f->next; 6259 } 6260 context->internal->_files = NULL; 6261 6262 /* First try to remove the servers the nice way. */ 6263 if (context->callbacks.purge_cached_fn(context)) { 6264 SMBCSRV * s; 6265 SMBCSRV * next; 6266 DEBUG(1, ("Could not purge all servers, " 6267 "Nice way shutdown failed.\n")); 6268 s = context->internal->_servers; 6269 while (s) { 6270 DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", 6271 s, s->cli->fd)); 6272 cli_shutdown(s->cli); 6273 context->callbacks.remove_cached_srv_fn(context, 6274 s); 6275 next = s->next; 6276 DLIST_REMOVE(context->internal->_servers, s); 6277 SAFE_FREE(s); 6278 s = next; 6279 } 6280 context->internal->_servers = NULL; 6281 } 6282 } 6283 else { 6284 /* This is the polite way */ 6285 if (context->callbacks.purge_cached_fn(context)) { 6286 DEBUG(1, ("Could not purge all servers, " 6287 "free_context failed.\n")); 6288 errno = EBUSY; 6289 return 1; 6290 } 6291 if (context->internal->_servers) { 6292 DEBUG(1, ("Active servers in context, " 6293 "free_context failed.\n")); 6294 errno = EBUSY; 6295 return 1; 6296 } 6297 if (context->internal->_files) { 6298 DEBUG(1, ("Active files in context, " 6299 "free_context failed.\n")); 6300 errno = EBUSY; 6301 return 1; 6302 } 6303 } 6304 6305 /* Things we have to clean up */ 6306 SAFE_FREE(context->workgroup); 6307 SAFE_FREE(context->netbios_name); 6308 SAFE_FREE(context->user); 6309 6310 DEBUG(3, ("Context %p succesfully freed\n", context)); 6311 SAFE_FREE(context->internal); 6312 SAFE_FREE(context); 6313 return 0; 6314} 6315 6316 6317/* 6318 * Each time the context structure is changed, we have binary backward 6319 * compatibility issues. Instead of modifying the public portions of the 6320 * context structure to add new options, instead, we put them in the internal 6321 * portion of the context structure and provide a set function for these new 6322 * options. 6323 */ 6324void 6325smbc_option_set(SMBCCTX *context, 6326 char *option_name, 6327 ... /* option_value */) 6328{ 6329 va_list ap; 6330 union { 6331 int i; 6332 BOOL b; 6333 smbc_get_auth_data_with_context_fn auth_fn; 6334 void *v; 6335 } option_value; 6336 6337 va_start(ap, option_name); 6338 6339 if (strcmp(option_name, "debug_to_stderr") == 0) { 6340 /* 6341 * Log to standard error instead of standard output. 6342 */ 6343 option_value.b = (BOOL) va_arg(ap, int); 6344 context->internal->_debug_stderr = option_value.b; 6345 6346 } else if (strcmp(option_name, "full_time_names") == 0) { 6347 /* 6348 * Use new-style time attribute names, e.g. WRITE_TIME rather 6349 * than the old-style names such as M_TIME. This allows also 6350 * setting/getting CREATE_TIME which was previously 6351 * unimplemented. (Note that the old C_TIME was supposed to 6352 * be CHANGE_TIME but was confused and sometimes referred to 6353 * CREATE_TIME.) 6354 */ 6355 option_value.b = (BOOL) va_arg(ap, int); 6356 context->internal->_full_time_names = option_value.b; 6357 6358 } else if (strcmp(option_name, "open_share_mode") == 0) { 6359 /* 6360 * The share mode to use for files opened with 6361 * smbc_open_ctx(). The default is SMBC_SHAREMODE_DENY_NONE. 6362 */ 6363 option_value.i = va_arg(ap, int); 6364 context->internal->_share_mode = 6365 (smbc_share_mode) option_value.i; 6366 6367 } else if (strcmp(option_name, "auth_function") == 0) { 6368 /* 6369 * Use the new-style authentication function which includes 6370 * the context. 6371 */ 6372 option_value.auth_fn = 6373 va_arg(ap, smbc_get_auth_data_with_context_fn); 6374 context->internal->_auth_fn_with_context = 6375 option_value.auth_fn; 6376 } else if (strcmp(option_name, "user_data") == 0) { 6377 /* 6378 * Save a user data handle which may be retrieved by the user 6379 * with smbc_option_get() 6380 */ 6381 option_value.v = va_arg(ap, void *); 6382 context->internal->_user_data = option_value.v; 6383 } 6384 6385 va_end(ap); 6386} 6387 6388 6389/* 6390 * Retrieve the current value of an option 6391 */ 6392void * 6393smbc_option_get(SMBCCTX *context, 6394 char *option_name) 6395{ 6396 if (strcmp(option_name, "debug_stderr") == 0) { 6397 /* 6398 * Log to standard error instead of standard output. 6399 */ 6400#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 6401 return (void *) (intptr_t) context->internal->_debug_stderr; 6402#else 6403 return (void *) context->internal->_debug_stderr; 6404#endif 6405 } else if (strcmp(option_name, "full_time_names") == 0) { 6406 /* 6407 * Use new-style time attribute names, e.g. WRITE_TIME rather 6408 * than the old-style names such as M_TIME. This allows also 6409 * setting/getting CREATE_TIME which was previously 6410 * unimplemented. (Note that the old C_TIME was supposed to 6411 * be CHANGE_TIME but was confused and sometimes referred to 6412 * CREATE_TIME.) 6413 */ 6414#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 6415 return (void *) (intptr_t) context->internal->_full_time_names; 6416#else 6417 return (void *) context->internal->_full_time_names; 6418#endif 6419 6420 } else if (strcmp(option_name, "auth_function") == 0) { 6421 /* 6422 * Use the new-style authentication function which includes 6423 * the context. 6424 */ 6425 return (void *) context->internal->_auth_fn_with_context; 6426 } else if (strcmp(option_name, "user_data") == 0) { 6427 /* 6428 * Save a user data handle which may be retrieved by the user 6429 * with smbc_option_get() 6430 */ 6431 return context->internal->_user_data; 6432 } 6433 6434 return NULL; 6435} 6436 6437 6438/* 6439 * Initialise the library etc 6440 * 6441 * We accept a struct containing handle information. 6442 * valid values for info->debug from 0 to 100, 6443 * and insist that info->fn must be non-null. 6444 */ 6445SMBCCTX * 6446smbc_init_context(SMBCCTX *context) 6447{ 6448 pstring conf; 6449 int pid; 6450 char *user = NULL; 6451 char *home = NULL; 6452 6453 if (!context || !context->internal) { 6454 errno = EBADF; 6455 return NULL; 6456 } 6457 6458 /* Do not initialise the same client twice */ 6459 if (context->internal->_initialized) { 6460 return 0; 6461 } 6462 6463 if ((!context->callbacks.auth_fn && 6464 !context->internal->_auth_fn_with_context) || 6465 context->debug < 0 || 6466 context->debug > 100) { 6467 6468 errno = EINVAL; 6469 return NULL; 6470 6471 } 6472 6473 if (!smbc_initialized) { 6474 /* 6475 * Do some library-wide intializations the first time we get 6476 * called 6477 */ 6478 BOOL conf_loaded = False; 6479 6480 /* Set this to what the user wants */ 6481 DEBUGLEVEL = context->debug; 6482 6483 load_case_tables(); 6484 6485 setup_logging("libsmbclient", True); 6486 if (context->internal->_debug_stderr) { 6487 dbf = x_stderr; 6488 x_setbuf(x_stderr, NULL); 6489 } 6490 6491 /* Here we would open the smb.conf file if needed ... */ 6492 6493 in_client = True; /* FIXME, make a param */ 6494 6495 home = getenv("HOME"); 6496 if (home) { 6497 slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home); 6498 if (lp_load(conf, True, False, False, True)) { 6499 conf_loaded = True; 6500 } else { 6501 DEBUG(5, ("Could not load config file: %s\n", 6502 conf)); 6503 } 6504 } 6505 6506 if (!conf_loaded) { 6507 /* 6508 * Well, if that failed, try the dyn_CONFIGFILE 6509 * Which points to the standard locn, and if that 6510 * fails, silently ignore it and use the internal 6511 * defaults ... 6512 */ 6513 6514 if (!lp_load(dyn_CONFIGFILE, True, False, False, False)) { 6515 DEBUG(5, ("Could not load config file: %s\n", 6516 dyn_CONFIGFILE)); 6517 } else if (home) { 6518 /* 6519 * We loaded the global config file. Now lets 6520 * load user-specific modifications to the 6521 * global config. 6522 */ 6523 slprintf(conf, sizeof(conf), 6524 "%s/.smb/smb.conf.append", home); 6525 if (!lp_load(conf, True, False, False, False)) { 6526 DEBUG(10, 6527 ("Could not append config file: " 6528 "%s\n", 6529 conf)); 6530 } 6531 } 6532 } 6533 6534 load_interfaces(); /* Load the list of interfaces ... */ 6535 6536 reopen_logs(); /* Get logging working ... */ 6537 6538 /* 6539 * Block SIGPIPE (from lib/util_sock.c: write()) 6540 * It is not needed and should not stop execution 6541 */ 6542 BlockSignals(True, SIGPIPE); 6543 6544 /* Done with one-time initialisation */ 6545 smbc_initialized = 1; 6546 6547 } 6548 6549 if (!context->user) { 6550 /* 6551 * FIXME: Is this the best way to get the user info? 6552 */ 6553 user = getenv("USER"); 6554 /* walk around as "guest" if no username can be found */ 6555 if (!user) context->user = SMB_STRDUP("guest"); 6556 else context->user = SMB_STRDUP(user); 6557 } 6558 6559 if (!context->netbios_name) { 6560 /* 6561 * We try to get our netbios name from the config. If that 6562 * fails we fall back on constructing our netbios name from 6563 * our hostname etc 6564 */ 6565 if (global_myname()) { 6566 context->netbios_name = SMB_STRDUP(global_myname()); 6567 } 6568 else { 6569 /* 6570 * Hmmm, I want to get hostname as well, but I am too 6571 * lazy for the moment 6572 */ 6573 pid = sys_getpid(); 6574 context->netbios_name = (char *)SMB_MALLOC(17); 6575 if (!context->netbios_name) { 6576 errno = ENOMEM; 6577 return NULL; 6578 } 6579 slprintf(context->netbios_name, 16, 6580 "smbc%s%d", context->user, pid); 6581 } 6582 } 6583 6584 DEBUG(1, ("Using netbios name %s.\n", context->netbios_name)); 6585 6586 if (!context->workgroup) { 6587 if (lp_workgroup()) { 6588 context->workgroup = SMB_STRDUP(lp_workgroup()); 6589 } 6590 else { 6591 /* TODO: Think about a decent default workgroup */ 6592 context->workgroup = SMB_STRDUP("samba"); 6593 } 6594 } 6595 6596 DEBUG(1, ("Using workgroup %s.\n", context->workgroup)); 6597 6598 /* shortest timeout is 1 second */ 6599 if (context->timeout > 0 && context->timeout < 1000) 6600 context->timeout = 1000; 6601 6602 /* 6603 * FIXME: Should we check the function pointers here? 6604 */ 6605 6606 context->internal->_initialized = True; 6607 6608 return context; 6609} 6610 6611 6612/* Return the verion of samba, and thus libsmbclient */ 6613const char * 6614smbc_version(void) 6615{ 6616 return samba_version_string(); 6617} 6618