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 29 30/* 31 * DOS Attribute values (used internally) 32 */ 33typedef struct DOS_ATTR_DESC 34{ 35 int mode; 36 unsigned long long size; 37 time_t a_time; 38 time_t c_time; 39 time_t m_time; 40 unsigned long long inode; 41} DOS_ATTR_DESC; 42 43 44/* 45 * Internal flags for extended attributes 46 */ 47 48/* internal mode values */ 49#define SMBC_XATTR_MODE_ADD 1 50#define SMBC_XATTR_MODE_REMOVE 2 51#define SMBC_XATTR_MODE_REMOVE_ALL 3 52#define SMBC_XATTR_MODE_SET 4 53#define SMBC_XATTR_MODE_CHOWN 5 54#define SMBC_XATTR_MODE_CHGRP 6 55 56#define CREATE_ACCESS_READ READ_CONTROL_ACCESS 57 58/*We should test for this in configure ... */ 59#ifndef ENOTSUP 60#define ENOTSUP EOPNOTSUPP 61#endif 62 63/* 64 * Functions exported by libsmb_cache.c that we need here 65 */ 66int smbc_default_cache_functions(SMBCCTX *context); 67 68/* 69 * check if an element is part of the list. 70 * FIXME: Does not belong here ! 71 * Can anyone put this in a macro in dlinklist.h ? 72 * -- Tom 73 */ 74static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) { 75 if (!p || !list) return False; 76 do { 77 if (p == list) return True; 78 list = list->next; 79 } while (list); 80 return False; 81} 82 83extern BOOL in_client; 84 85/* 86 * Is the logging working / configfile read ? 87 */ 88static int smbc_initialized = 0; 89 90static int 91hex2int( unsigned int _char ) 92{ 93 if ( _char >= 'A' && _char <='F') 94 return _char - 'A' + 10; 95 if ( _char >= 'a' && _char <='f') 96 return _char - 'a' + 10; 97 if ( _char >= '0' && _char <='9') 98 return _char - '0'; 99 return -1; 100} 101 102/* 103 * smbc_urldecode() 104 * 105 * Convert strings of %xx to their single character equivalent. Each 'x' must 106 * be a valid hexadecimal digit, or that % sequence is left undecoded. 107 * 108 * dest may, but need not be, the same pointer as src. 109 * 110 * Returns the number of % sequences which could not be converted due to lack 111 * of two following hexadecimal digits. 112 */ 113int 114smbc_urldecode(char *dest, char * src, size_t max_dest_len) 115{ 116 int old_length = strlen(src); 117 int i = 0; 118 int err_count = 0; 119 pstring temp; 120 char * p; 121 122 if ( old_length == 0 ) { 123 return 0; 124 } 125 126 p = temp; 127 while ( i < old_length ) { 128 unsigned char character = src[ i++ ]; 129 130 if (character == '%') { 131 int a = i+1 < old_length ? hex2int( src[i] ) : -1; 132 int b = i+1 < old_length ? hex2int( src[i+1] ) : -1; 133 134 /* Replace valid sequence */ 135 if (a != -1 && b != -1) { 136 137 /* Replace valid %xx sequence with %dd */ 138 character = (a * 16) + b; 139 140 if (character == '\0') { 141 break; /* Stop at %00 */ 142 } 143 144 i += 2; 145 } else { 146 147 err_count++; 148 } 149 } 150 151 *p++ = character; 152 } 153 154 *p = '\0'; 155 156 strncpy(dest, temp, max_dest_len); 157 158 return err_count; 159} 160 161/* 162 * smbc_urlencode() 163 * 164 * Convert any characters not specifically allowed in a URL into their %xx 165 * equivalent. 166 * 167 * Returns the remaining buffer length. 168 */ 169int 170smbc_urlencode(char * dest, char * src, int max_dest_len) 171{ 172 char hex[] = "0123456789ABCDEF"; 173 174 for (; *src != '\0' && max_dest_len >= 3; src++) { 175 176 if ((*src < '0' && 177 *src != '-' && 178 *src != '.') || 179 (*src > '9' && 180 *src < 'A') || 181 (*src > 'Z' && 182 *src < 'a' && 183 *src != '_') || 184 (*src > 'z')) { 185 *dest++ = '%'; 186 *dest++ = hex[(*src >> 4) & 0x0f]; 187 *dest++ = hex[*src & 0x0f]; 188 max_dest_len -= 3; 189 } else { 190 *dest++ = *src; 191 max_dest_len--; 192 } 193 } 194 195 *dest++ = '\0'; 196 max_dest_len--; 197 198 return max_dest_len; 199} 200 201/* 202 * Function to parse a path and turn it into components 203 * 204 * The general format of an SMB URI is explain in Christopher Hertel's CIFS 205 * book, at http://ubiqx.org/cifs/Appendix-D.html. We accept a subset of the 206 * general format ("smb:" only; we do not look for "cifs:"). 207 * 208 * 209 * We accept: 210 * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]][?options] 211 * 212 * Meaning of URLs: 213 * 214 * smb:// Show all workgroups. 215 * 216 * The method of locating the list of workgroups varies 217 * depending upon the setting of the context variable 218 * context->options.browse_max_lmb_count. This value 219 * determine the maximum number of local master browsers to 220 * query for the list of workgroups. In order to ensure that 221 * a complete list of workgroups is obtained, all master 222 * browsers must be queried, but if there are many 223 * workgroups, the time spent querying can begin to add up. 224 * For small networks (not many workgroups), it is suggested 225 * that this variable be set to 0, indicating query all local 226 * master browsers. When the network has many workgroups, a 227 * reasonable setting for this variable might be around 3. 228 * 229 * smb://name/ if name<1D> or name<1B> exists, list servers in 230 * workgroup, else, if name<20> exists, list all shares 231 * for server ... 232 * 233 * If "options" are provided, this function returns the entire option list as a 234 * string, for later parsing by the caller. Note that currently, no options 235 * are supported. 236 */ 237 238static const char *smbc_prefix = "smb:"; 239 240static int 241smbc_parse_path(SMBCCTX *context, 242 const char *fname, 243 char *server, int server_len, 244 char *share, int share_len, 245 char *path, int path_len, 246 char *user, int user_len, 247 char *password, int password_len, 248 char *options, int options_len) 249{ 250 static pstring s; 251 pstring userinfo; 252 const char *p; 253 char *q, *r; 254 int len; 255 256 server[0] = share[0] = path[0] = user[0] = password[0] = (char)0; 257 if (options != NULL && options_len > 0) { 258 options[0] = (char)0; 259 } 260 pstrcpy(s, fname); 261 262 /* see if it has the right prefix */ 263 len = strlen(smbc_prefix); 264 if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) { 265 return -1; /* What about no smb: ? */ 266 } 267 268 p = s + len; 269 270 /* Watch the test below, we are testing to see if we should exit */ 271 272 if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) { 273 274 DEBUG(1, ("Invalid path (does not begin with smb://")); 275 return -1; 276 277 } 278 279 p += 2; /* Skip the double slash */ 280 281 /* See if any options were specified */ 282 if ((q = strrchr(p, '?')) != NULL ) { 283 /* There are options. Null terminate here and point to them */ 284 *q++ = '\0'; 285 286 DEBUG(4, ("Found options '%s'", q)); 287 288 /* Copy the options */ 289 if (options != NULL && options_len > 0) { 290 safe_strcpy(options, q, options_len - 1); 291 } 292 } 293 294 if (*p == (char)0) 295 goto decoding; 296 297 if (*p == '/') { 298 299 strncpy(server, context->workgroup, 300 (strlen(context->workgroup) < 16)?strlen(context->workgroup):16); 301 return 0; 302 303 } 304 305 /* 306 * ok, its for us. Now parse out the server, share etc. 307 * 308 * However, we want to parse out [[domain;]user[:password]@] if it 309 * exists ... 310 */ 311 312 /* check that '@' occurs before '/', if '/' exists at all */ 313 q = strchr_m(p, '@'); 314 r = strchr_m(p, '/'); 315 if (q && (!r || q < r)) { 316 pstring username, passwd, domain; 317 const char *u = userinfo; 318 319 next_token(&p, userinfo, "@", sizeof(fstring)); 320 321 username[0] = passwd[0] = domain[0] = 0; 322 323 if (strchr_m(u, ';')) { 324 325 next_token(&u, domain, ";", sizeof(fstring)); 326 327 } 328 329 if (strchr_m(u, ':')) { 330 331 next_token(&u, username, ":", sizeof(fstring)); 332 333 pstrcpy(passwd, u); 334 335 } 336 else { 337 338 pstrcpy(username, u); 339 340 } 341 342 if (username[0]) 343 strncpy(user, username, user_len); /* FIXME, domain */ 344 345 if (passwd[0]) 346 strncpy(password, passwd, password_len); 347 348 } 349 350 if (!next_token(&p, server, "/", sizeof(fstring))) { 351 352 return -1; 353 354 } 355 356 if (*p == (char)0) goto decoding; /* That's it ... */ 357 358 if (!next_token(&p, share, "/", sizeof(fstring))) { 359 360 return -1; 361 362 } 363 364 safe_strcpy(path, p, path_len - 1); 365 366 all_string_sub(path, "/", "\\", 0); 367 368 decoding: 369 (void) smbc_urldecode(path, path, path_len); 370 (void) smbc_urldecode(server, server, server_len); 371 (void) smbc_urldecode(share, share, share_len); 372 (void) smbc_urldecode(user, user, user_len); 373 (void) smbc_urldecode(password, password, password_len); 374 375 return 0; 376} 377 378/* 379 * Verify that the options specified in a URL are valid 380 */ 381static int smbc_check_options(char *server, char *share, char *path, char *options) 382{ 383 DEBUG(4, ("smbc_check_options(): server='%s' share='%s' path='%s' options='%s'\n", server, share, path, options)); 384 385 /* No options at all is always ok */ 386 if (! *options) return 0; 387 388 /* Currently, we don't support any options. */ 389 return -1; 390} 391 392/* 393 * Convert an SMB error into a UNIX error ... 394 */ 395static int smbc_errno(SMBCCTX *context, struct cli_state *c) 396{ 397 int ret = cli_errno(c); 398 399 if (cli_is_dos_error(c)) { 400 uint8 eclass; 401 uint32 ecode; 402 403 cli_dos_error(c, &eclass, &ecode); 404 405 DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", 406 (int)eclass, (int)ecode, (int)ecode, ret)); 407 } else { 408 NTSTATUS status; 409 410 status = cli_nt_error(c); 411 412 DEBUG(3,("smbc errno %s -> %d\n", 413 nt_errstr(status), ret)); 414 } 415 416 return ret; 417} 418 419/* 420 * Check a server_fd. 421 * returns 0 if the server is in shape. Returns 1 on error 422 * 423 * Also useable outside libsmbclient to enable external cache 424 * to do some checks too. 425 */ 426int smbc_check_server(SMBCCTX * context, SMBCSRV * server) 427{ 428 if ( send_keepalive(server->cli.fd) == False ) 429 return 1; 430 431 /* connection is ok */ 432 return 0; 433} 434 435/* 436 * Remove a server from the cached server list it's unused. 437 * On success, 0 is returned. 1 is returned if the server could not be removed. 438 * 439 * Also useable outside libsmbclient 440 */ 441int smbc_remove_unused_server(SMBCCTX * context, SMBCSRV * srv) 442{ 443 SMBCFILE * file; 444 445 /* are we being fooled ? */ 446 if (!context || !context->internal || 447 !context->internal->_initialized || !srv) return 1; 448 449 450 /* Check all open files/directories for a relation with this server */ 451 for (file = context->internal->_files; file; file=file->next) { 452 if (file->srv == srv) { 453 /* Still used */ 454 DEBUG(3, ("smbc_remove_usused_server: %p still used by %p.\n", 455 srv, file)); 456 return 1; 457 } 458 } 459 460 DLIST_REMOVE(context->internal->_servers, srv); 461 462 cli_shutdown(&srv->cli); 463 464 DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); 465 466 context->callbacks.remove_cached_srv_fn(context, srv); 467 468 return 0; 469} 470 471SMBCSRV *find_server(SMBCCTX *context, 472 const char *server, 473 const char *share, 474 fstring workgroup, 475 fstring username, 476 fstring password) 477{ 478 SMBCSRV *srv; 479 int auth_called = 0; 480 481 check_server_cache: 482 483 srv = context->callbacks.get_cached_srv_fn(context, server, share, 484 workgroup, username); 485 486 if (!auth_called && !srv && (!username[0] || !password[0])) { 487 context->callbacks.auth_fn(server, share, 488 workgroup, sizeof(fstring), 489 username, sizeof(fstring), 490 password, sizeof(fstring)); 491 /* 492 * However, smbc_auth_fn may have picked up info relating to 493 * an existing connection, so try for an existing connection 494 * again ... 495 */ 496 auth_called = 1; 497 goto check_server_cache; 498 499 } 500 501 if (srv) { 502 if (context->callbacks.check_server_fn(context, srv)) { 503 /* 504 * This server is no good anymore 505 * Try to remove it and check for more possible 506 * servers in the cache 507 */ 508 if (context->callbacks.remove_unused_server_fn(context, 509 srv)) { 510 /* 511 * We could not remove the server completely, 512 * remove it from the cache so we will not get 513 * it again. It will be removed when the last 514 * file/dir is closed. 515 */ 516 context->callbacks.remove_cached_srv_fn(context, 517 srv); 518 } 519 520 /* 521 * Maybe there are more cached connections to this 522 * server 523 */ 524 goto check_server_cache; 525 } 526 527 return srv; 528 } 529 530 return NULL; 531} 532 533/* 534 * Connect to a server, possibly on an existing connection 535 * 536 * Here, what we want to do is: If the server and username 537 * match an existing connection, reuse that, otherwise, establish a 538 * new connection. 539 * 540 * If we have to create a new connection, call the auth_fn to get the 541 * info we need, unless the username and password were passed in. 542 */ 543 544SMBCSRV *smbc_server(SMBCCTX *context, 545 const char *server, const char *share, 546 fstring workgroup, fstring username, 547 fstring password) 548{ 549 SMBCSRV *srv=NULL; 550 struct cli_state c; 551 struct nmb_name called, calling; 552 const char *server_n = server; 553 pstring ipenv; 554 struct in_addr ip; 555 int tried_reverse = 0; 556 int port_try_first; 557 int port_try_next; 558 559 zero_ip(&ip); 560 ZERO_STRUCT(c); 561 562 if (server[0] == 0) { 563 errno = EPERM; 564 return NULL; 565 } 566 567 srv = find_server(context, server, share, 568 workgroup, username, password); 569 570 /* 571 * If we found a connection and we're only allowed one share per 572 * server... 573 */ 574 if (srv && *share != '\0' && context->options.one_share_per_server) { 575 576 /* 577 * ... then if there's no current connection to the share, 578 * connect to it. find_server(), or rather the function 579 * pointed to by context->callbacks.get_cached_srv_fn which 580 * was called by find_server(), will have issued a tree 581 * disconnect if the requested share is not the same as the 582 * one that was already connected. 583 */ 584 if (srv->cli.cnum == (uint16) -1) { 585 /* Ensure we have accurate auth info */ 586 context->callbacks.auth_fn(server, share, 587 workgroup, sizeof(fstring), 588 username, sizeof(fstring), 589 password, sizeof(fstring)); 590 591 if (! cli_send_tconX(&srv->cli, share, "?????", 592 password, strlen(password)+1)) { 593 594 errno = smbc_errno(context, &srv->cli); 595 cli_shutdown(&srv->cli); 596 context->callbacks.remove_cached_srv_fn(context, srv); 597 srv = NULL; 598 } 599 600 /* Regenerate the dev value since it's based on both server and share */ 601 if (srv) { 602 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); 603 } 604 } 605 } 606 607 /* If we have a connection... */ 608 if (srv) { 609 610 /* ... then we're done here. Give 'em what they came for. */ 611 return srv; 612 } 613 614 make_nmb_name(&calling, context->netbios_name, 0x0); 615 make_nmb_name(&called , server, 0x20); 616 617 DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server)); 618 619 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); 620 621 again: 622 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); 623 624 zero_ip(&ip); 625 626 /* have to open a new connection */ 627 if (!cli_initialise(&c)) { 628 errno = ENOMEM; 629 return NULL; 630 } 631 632 if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) { 633 c.use_kerberos = True; 634 } 635 if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { 636 c.fallback_after_kerberos = True; 637 } 638 639 c.timeout = context->timeout; 640 641 /* 642 * Force use of port 139 for first try if share is $IPC, empty, or 643 * null, so browse lists can work 644 */ 645 if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) 646 { 647 port_try_first = 139; 648 port_try_next = 445; 649 } 650 else 651 { 652 port_try_first = 445; 653 port_try_next = 139; 654 } 655 656 c.port = port_try_first; 657 658 if (!cli_connect(&c, server_n, &ip)) { 659 660 /* First connection attempt failed. Try alternate port. */ 661 c.port = port_try_next; 662 663 if (!cli_connect(&c, server_n, &ip)) { 664 cli_shutdown(&c); 665 errno = ETIMEDOUT; 666 return NULL; 667 } 668 } 669 670 if (!cli_session_request(&c, &calling, &called)) { 671 cli_shutdown(&c); 672 if (strcmp(called.name, "*SMBSERVER")) { 673 make_nmb_name(&called , "*SMBSERVER", 0x20); 674 goto again; 675 } 676 else { /* Try one more time, but ensure we don't loop */ 677 678 /* Only try this if server is an IP address ... */ 679 680 if (is_ipaddress(server) && !tried_reverse) { 681 fstring remote_name; 682 struct in_addr rem_ip; 683 684 if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) { 685 DEBUG(4, ("Could not convert IP address %s to struct in_addr\n", server)); 686 errno = ETIMEDOUT; 687 return NULL; 688 } 689 690 tried_reverse++; /* Yuck */ 691 692 if (name_status_find("*", 0, 0, rem_ip, remote_name)) { 693 make_nmb_name(&called, remote_name, 0x20); 694 goto again; 695 } 696 697 698 } 699 } 700 errno = ETIMEDOUT; 701 return NULL; 702 } 703 704 DEBUG(4,(" session request ok\n")); 705 706 if (!cli_negprot(&c)) { 707 cli_shutdown(&c); 708 errno = ETIMEDOUT; 709 return NULL; 710 } 711 712 if (!cli_session_setup(&c, username, 713 password, strlen(password), 714 password, strlen(password), 715 workgroup) && 716 /* Try an anonymous login if it failed and this was allowed by flags. */ 717 ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || 718 !cli_session_setup(&c, "", "", 1,"", 0, workgroup))) { 719 cli_shutdown(&c); 720 errno = EPERM; 721 return NULL; 722 } 723 724 DEBUG(4,(" session setup ok\n")); 725 726 if (!cli_send_tconX(&c, share, "?????", 727 password, strlen(password)+1)) { 728 errno = smbc_errno(context, &c); 729 cli_shutdown(&c); 730 return NULL; 731 } 732 733 DEBUG(4,(" tconx ok\n")); 734 735 /* 736 * Ok, we have got a nice connection 737 * Let's find a free server_fd 738 */ 739 740 srv = SMB_MALLOC_P(SMBCSRV); 741 if (!srv) { 742 errno = ENOMEM; 743 goto failed; 744 } 745 746 ZERO_STRUCTP(srv); 747 srv->cli = c; 748 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); 749 750 /* now add it to the cache (internal or external) */ 751 /* Let the cache function set errno if it wants to */ 752 errno = 0; 753 if (context->callbacks.add_cached_srv_fn(context, srv, server, share, workgroup, username)) { 754 int saved_errno = errno; 755 DEBUG(3, (" Failed to add server to cache\n")); 756 errno = saved_errno; 757 if (errno == 0) { 758 errno = ENOMEM; 759 } 760 goto failed; 761 } 762 763 DEBUG(2, ("Server connect ok: //%s/%s: %p\n", 764 server, share, srv)); 765 766 DLIST_ADD(context->internal->_servers, srv); 767 return srv; 768 769 failed: 770 cli_shutdown(&c); 771 if (!srv) return NULL; 772 773 SAFE_FREE(srv); 774 return NULL; 775} 776 777/* 778 * Connect to a server for getting/setting attributes, possibly on an existing 779 * connection. This works similarly to smbc_server(). 780 */ 781SMBCSRV *smbc_attr_server(SMBCCTX *context, 782 const char *server, const char *share, 783 fstring workgroup, 784 fstring username, fstring password, 785 POLICY_HND *pol) 786{ 787 struct in_addr ip; 788 struct cli_state *ipc_cli; 789 NTSTATUS nt_status; 790 SMBCSRV *ipc_srv=NULL; 791 792 /* 793 * See if we've already created this special connection. Reference our 794 * "special" share name '*IPC$', which is an impossible real share name 795 * due to the leading asterisk. 796 */ 797 ipc_srv = find_server(context, server, "*IPC$", 798 workgroup, username, password); 799 if (!ipc_srv) { 800 801 /* We didn't find a cached connection. Get the password */ 802 if (*password == '\0') { 803 /* ... then retrieve it now. */ 804 context->callbacks.auth_fn(server, share, 805 workgroup, sizeof(fstring), 806 username, sizeof(fstring), 807 password, sizeof(fstring)); 808 } 809 810 zero_ip(&ip); 811 nt_status = cli_full_connection(&ipc_cli, 812 global_myname(), server, 813 &ip, 0, "IPC$", "?????", 814 username, workgroup, 815 password, 0, 816 Undefined, NULL); 817 if (! NT_STATUS_IS_OK(nt_status)) { 818 DEBUG(1,("cli_full_connection failed! (%s)\n", 819 nt_errstr(nt_status))); 820 errno = ENOTSUP; 821 return NULL; 822 } 823 824 if (!cli_nt_session_open(ipc_cli, PI_LSARPC)) { 825 DEBUG(1, ("cli_nt_session_open fail!\n")); 826 errno = ENOTSUP; 827 cli_shutdown(ipc_cli); 828 return NULL; 829 } 830 831 /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED, 832 but NT sends 0x2000000 so we might as well do it too. */ 833 834 nt_status = cli_lsa_open_policy(ipc_cli, 835 ipc_cli->mem_ctx, 836 True, 837 GENERIC_EXECUTE_ACCESS, 838 pol); 839 840 if (!NT_STATUS_IS_OK(nt_status)) { 841 errno = smbc_errno(context, ipc_cli); 842 cli_shutdown(ipc_cli); 843 return NULL; 844 } 845 846 ipc_srv = SMB_MALLOC_P(SMBCSRV); 847 if (!ipc_srv) { 848 errno = ENOMEM; 849 cli_shutdown(ipc_cli); 850 return NULL; 851 } 852 853 ZERO_STRUCTP(ipc_srv); 854 ipc_srv->cli = *ipc_cli; 855 856 free(ipc_cli); 857 858 /* now add it to the cache (internal or external) */ 859 860 errno = 0; /* let cache function set errno if it likes */ 861 if (context->callbacks.add_cached_srv_fn(context, ipc_srv, 862 server, 863 "*IPC$", 864 workgroup, 865 username)) { 866 DEBUG(3, (" Failed to add server to cache\n")); 867 if (errno == 0) { 868 errno = ENOMEM; 869 } 870 cli_shutdown(&ipc_srv->cli); 871 free(ipc_srv); 872 return NULL; 873 } 874 875 DLIST_ADD(context->internal->_servers, ipc_srv); 876 } 877 878 return ipc_srv; 879} 880 881/* 882 * Routine to open() a file ... 883 */ 884 885static SMBCFILE *smbc_open_ctx(SMBCCTX *context, const char *fname, int flags, mode_t mode) 886{ 887 fstring server, share, user, password, workgroup; 888 pstring path; 889 SMBCSRV *srv = NULL; 890 SMBCFILE *file = NULL; 891 int fd; 892 893 if (!context || !context->internal || 894 !context->internal->_initialized) { 895 896 errno = EINVAL; /* Best I can think of ... */ 897 return NULL; 898 899 } 900 901 if (!fname) { 902 903 errno = EINVAL; 904 return NULL; 905 906 } 907 908 if (smbc_parse_path(context, fname, 909 server, sizeof(server), 910 share, sizeof(share), 911 path, sizeof(path), 912 user, sizeof(user), 913 password, sizeof(password), 914 NULL, 0)) { 915 errno = EINVAL; 916 return NULL; 917 } 918 919 if (user[0] == (char)0) fstrcpy(user, context->user); 920 921 fstrcpy(workgroup, context->workgroup); 922 923 srv = smbc_server(context, server, share, workgroup, user, password); 924 925 if (!srv) { 926 927 if (errno == EPERM) errno = EACCES; 928 return NULL; /* smbc_server sets errno */ 929 930 } 931 932 /* Hmmm, the test for a directory is suspect here ... FIXME */ 933 934 if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') { 935 936 fd = -1; 937 938 } 939 else { 940 941 file = SMB_MALLOC_P(SMBCFILE); 942 943 if (!file) { 944 945 errno = ENOMEM; 946 return NULL; 947 948 } 949 950 ZERO_STRUCTP(file); 951 952 if ((fd = cli_open(&srv->cli, path, flags, DENY_NONE)) < 0) { 953 954 /* Handle the error ... */ 955 956 SAFE_FREE(file); 957 errno = smbc_errno(context, &srv->cli); 958 return NULL; 959 960 } 961 962 /* Fill in file struct */ 963 964 file->cli_fd = fd; 965 file->fname = SMB_STRDUP(fname); 966 file->srv = srv; 967 file->offset = 0; 968 file->file = True; 969 970 DLIST_ADD(context->internal->_files, file); 971 return file; 972 973 } 974 975 /* Check if opendir needed ... */ 976 977 if (fd == -1) { 978 int eno = 0; 979 980 eno = smbc_errno(context, &srv->cli); 981 file = context->opendir(context, fname); 982 if (!file) errno = eno; 983 return file; 984 985 } 986 987 errno = EINVAL; /* FIXME, correct errno ? */ 988 return NULL; 989 990} 991 992/* 993 * Routine to create a file 994 */ 995 996static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */ 997 998static SMBCFILE *smbc_creat_ctx(SMBCCTX *context, const char *path, mode_t mode) 999{ 1000 1001 if (!context || !context->internal || 1002 !context->internal->_initialized) { 1003 1004 errno = EINVAL; 1005 return NULL; 1006 1007 } 1008 1009 return smbc_open_ctx(context, path, creat_bits, mode); 1010} 1011 1012/* 1013 * Routine to read() a file ... 1014 */ 1015 1016static ssize_t smbc_read_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t count) 1017{ 1018 int ret; 1019 1020 if (!context || !context->internal || 1021 !context->internal->_initialized) { 1022 1023 errno = EINVAL; 1024 return -1; 1025 1026 } 1027 1028 DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count)); 1029 1030 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1031 1032 errno = EBADF; 1033 return -1; 1034 1035 } 1036 1037 /* Check that the buffer exists ... */ 1038 1039 if (buf == NULL) { 1040 1041 errno = EINVAL; 1042 return -1; 1043 1044 } 1045 1046 ret = cli_read(&file->srv->cli, file->cli_fd, buf, file->offset, count); 1047 1048 if (ret < 0) { 1049 1050 errno = smbc_errno(context, &file->srv->cli); 1051 return -1; 1052 1053 } 1054 1055 file->offset += ret; 1056 1057 DEBUG(4, (" --> %d\n", ret)); 1058 1059 return ret; /* Success, ret bytes of data ... */ 1060 1061} 1062 1063/* 1064 * Routine to write() a file ... 1065 */ 1066 1067static ssize_t smbc_write_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t count) 1068{ 1069 int ret; 1070 1071 if (!context || !context->internal || 1072 !context->internal->_initialized) { 1073 1074 errno = EINVAL; 1075 return -1; 1076 1077 } 1078 1079 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1080 1081 errno = EBADF; 1082 return -1; 1083 1084 } 1085 1086 /* Check that the buffer exists ... */ 1087 1088 if (buf == NULL) { 1089 1090 errno = EINVAL; 1091 return -1; 1092 1093 } 1094 1095 ret = cli_write(&file->srv->cli, file->cli_fd, 0, buf, file->offset, count); 1096 1097 if (ret <= 0) { 1098 1099 errno = smbc_errno(context, &file->srv->cli); 1100 return -1; 1101 1102 } 1103 1104 file->offset += ret; 1105 1106 return ret; /* Success, 0 bytes of data ... */ 1107} 1108 1109/* 1110 * Routine to close() a file ... 1111 */ 1112 1113static int smbc_close_ctx(SMBCCTX *context, SMBCFILE *file) 1114{ 1115 SMBCSRV *srv; 1116 1117 if (!context || !context->internal || 1118 !context->internal->_initialized) { 1119 1120 errno = EINVAL; 1121 return -1; 1122 1123 } 1124 1125 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1126 1127 errno = EBADF; 1128 return -1; 1129 1130 } 1131 1132 /* IS a dir ... */ 1133 if (!file->file) { 1134 1135 return context->closedir(context, file); 1136 1137 } 1138 1139 if (!cli_close(&file->srv->cli, file->cli_fd)) { 1140 1141 DEBUG(3, ("cli_close failed on %s. purging server.\n", 1142 file->fname)); 1143 /* Deallocate slot and remove the server 1144 * from the server cache if unused */ 1145 errno = smbc_errno(context, &file->srv->cli); 1146 srv = file->srv; 1147 DLIST_REMOVE(context->internal->_files, file); 1148 SAFE_FREE(file->fname); 1149 SAFE_FREE(file); 1150 context->callbacks.remove_unused_server_fn(context, srv); 1151 1152 return -1; 1153 1154 } 1155 1156 DLIST_REMOVE(context->internal->_files, file); 1157 SAFE_FREE(file->fname); 1158 SAFE_FREE(file); 1159 1160 return 0; 1161} 1162 1163/* 1164 * Get info from an SMB server on a file. Use a qpathinfo call first 1165 * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo 1166 */ 1167static BOOL smbc_getatr(SMBCCTX * context, SMBCSRV *srv, char *path, 1168 uint16 *mode, size_t *size, 1169 time_t *c_time, time_t *a_time, time_t *m_time, 1170 SMB_INO_T *ino) 1171{ 1172 1173 if (!context || !context->internal || 1174 !context->internal->_initialized) { 1175 1176 errno = EINVAL; 1177 return -1; 1178 1179 } 1180 1181 DEBUG(4,("smbc_getatr: sending qpathinfo\n")); 1182 1183 if (!srv->no_pathinfo2 && 1184 cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL, 1185 size, mode, ino)) return True; 1186 1187 /* if this is NT then don't bother with the getatr */ 1188 if (srv->cli.capabilities & CAP_NT_SMBS) { 1189 errno = EPERM; 1190 return False; 1191 } 1192 1193 if (cli_getatr(&srv->cli, path, mode, size, m_time)) { 1194 a_time = c_time = m_time; 1195 srv->no_pathinfo2 = True; 1196 return True; 1197 } 1198 1199 errno = EPERM; 1200 return False; 1201 1202} 1203 1204/* 1205 * Routine to unlink() a file 1206 */ 1207 1208static int smbc_unlink_ctx(SMBCCTX *context, const char *fname) 1209{ 1210 fstring server, share, user, password, workgroup; 1211 pstring path; 1212 SMBCSRV *srv = NULL; 1213 1214 if (!context || !context->internal || 1215 !context->internal->_initialized) { 1216 1217 errno = EINVAL; /* Best I can think of ... */ 1218 return -1; 1219 1220 } 1221 1222 if (!fname) { 1223 1224 errno = EINVAL; 1225 return -1; 1226 1227 } 1228 1229 if (smbc_parse_path(context, fname, 1230 server, sizeof(server), 1231 share, sizeof(share), 1232 path, sizeof(path), 1233 user, sizeof(user), 1234 password, sizeof(password), 1235 NULL, 0)) { 1236 errno = EINVAL; 1237 return -1; 1238 } 1239 1240 if (user[0] == (char)0) fstrcpy(user, context->user); 1241 1242 fstrcpy(workgroup, context->workgroup); 1243 1244 srv = smbc_server(context, server, share, workgroup, user, password); 1245 1246 if (!srv) { 1247 1248 return -1; /* smbc_server sets errno */ 1249 1250 } 1251 1252 /* if (strncmp(srv->cli.dev, "LPT", 3) == 0) { 1253 1254 int job = smbc_stat_printjob(srv, path, NULL, NULL); 1255 if (job == -1) { 1256 1257 return -1; 1258 1259 } 1260 if ((err = cli_printjob_del(&srv->cli, job)) != 0) { 1261 1262 1263 return -1; 1264 1265 } 1266 } else */ 1267 1268 if (!cli_unlink(&srv->cli, path)) { 1269 1270 errno = smbc_errno(context, &srv->cli); 1271 1272 if (errno == EACCES) { /* Check if the file is a directory */ 1273 1274 int saverr = errno; 1275 size_t size = 0; 1276 uint16 mode = 0; 1277 time_t m_time = 0, a_time = 0, c_time = 0; 1278 SMB_INO_T ino = 0; 1279 1280 if (!smbc_getatr(context, srv, path, &mode, &size, 1281 &c_time, &a_time, &m_time, &ino)) { 1282 1283 /* Hmmm, bad error ... What? */ 1284 1285 errno = smbc_errno(context, &srv->cli); 1286 return -1; 1287 1288 } 1289 else { 1290 1291 if (IS_DOS_DIR(mode)) 1292 errno = EISDIR; 1293 else 1294 errno = saverr; /* Restore this */ 1295 1296 } 1297 } 1298 1299 return -1; 1300 1301 } 1302 1303 return 0; /* Success ... */ 1304 1305} 1306 1307/* 1308 * Routine to rename() a file 1309 */ 1310 1311static int smbc_rename_ctx(SMBCCTX *ocontext, const char *oname, 1312 SMBCCTX *ncontext, const char *nname) 1313{ 1314 fstring server1, share1, server2, share2, user1, user2, password1, password2, workgroup; 1315 pstring path1, path2; 1316 SMBCSRV *srv = NULL; 1317 1318 if (!ocontext || !ncontext || 1319 !ocontext->internal || !ncontext->internal || 1320 !ocontext->internal->_initialized || 1321 !ncontext->internal->_initialized) { 1322 1323 errno = EINVAL; /* Best I can think of ... */ 1324 return -1; 1325 1326 } 1327 1328 if (!oname || !nname) { 1329 1330 errno = EINVAL; 1331 return -1; 1332 1333 } 1334 1335 DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname)); 1336 1337 smbc_parse_path(ocontext, oname, 1338 server1, sizeof(server1), 1339 share1, sizeof(share1), 1340 path1, sizeof(path1), 1341 user1, sizeof(user1), 1342 password1, sizeof(password1), 1343 NULL, 0); 1344 1345 if (user1[0] == (char)0) fstrcpy(user1, ocontext->user); 1346 1347 smbc_parse_path(ncontext, nname, 1348 server2, sizeof(server2), 1349 share2, sizeof(share2), 1350 path2, sizeof(path2), 1351 user2, sizeof(user2), 1352 password2, sizeof(password2), 1353 NULL, 0); 1354 1355 if (user2[0] == (char)0) fstrcpy(user2, ncontext->user); 1356 1357 if (strcmp(server1, server2) || strcmp(share1, share2) || 1358 strcmp(user1, user2)) { 1359 1360 /* Can't rename across file systems, or users?? */ 1361 1362 errno = EXDEV; 1363 return -1; 1364 1365 } 1366 1367 fstrcpy(workgroup, ocontext->workgroup); 1368 /* HELP !!! Which workgroup should I use ? Or are they always the same -- Tom */ 1369 srv = smbc_server(ocontext, server1, share1, workgroup, user1, password1); 1370 if (!srv) { 1371 1372 return -1; 1373 1374 } 1375 1376 if (!cli_rename(&srv->cli, path1, path2)) { 1377 int eno = smbc_errno(ocontext, &srv->cli); 1378 1379 if (eno != EEXIST || 1380 !cli_unlink(&srv->cli, path2) || 1381 !cli_rename(&srv->cli, path1, path2)) { 1382 1383 errno = eno; 1384 return -1; 1385 1386 } 1387 } 1388 1389 return 0; /* Success */ 1390 1391} 1392 1393/* 1394 * A routine to lseek() a file 1395 */ 1396 1397static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence) 1398{ 1399 size_t size; 1400 1401 if (!context || !context->internal || 1402 !context->internal->_initialized) { 1403 1404 errno = EINVAL; 1405 return -1; 1406 1407 } 1408 1409 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1410 1411 errno = EBADF; 1412 return -1; 1413 1414 } 1415 1416 if (!file->file) { 1417 1418 errno = EINVAL; 1419 return -1; /* Can't lseek a dir ... */ 1420 1421 } 1422 1423 switch (whence) { 1424 case SEEK_SET: 1425 file->offset = offset; 1426 break; 1427 1428 case SEEK_CUR: 1429 file->offset += offset; 1430 break; 1431 1432 case SEEK_END: 1433 if (!cli_qfileinfo(&file->srv->cli, file->cli_fd, NULL, &size, NULL, NULL, 1434 NULL, NULL, NULL)) 1435 { 1436 SMB_BIG_UINT b_size = size; 1437 if (!cli_getattrE(&file->srv->cli, file->cli_fd, NULL, &b_size, NULL, NULL, 1438 NULL)) 1439 { 1440 errno = EINVAL; 1441 return -1; 1442 } else 1443 size = b_size; 1444 } 1445 file->offset = size + offset; 1446 break; 1447 1448 default: 1449 errno = EINVAL; 1450 break; 1451 1452 } 1453 1454 return file->offset; 1455 1456} 1457 1458/* 1459 * Generate an inode number from file name for those things that need it 1460 */ 1461 1462static 1463ino_t smbc_inode(SMBCCTX *context, const char *name) 1464{ 1465 1466 if (!context || !context->internal || 1467 !context->internal->_initialized) { 1468 1469 errno = EINVAL; 1470 return -1; 1471 1472 } 1473 1474 if (!*name) return 2; /* FIXME, why 2 ??? */ 1475 return (ino_t)str_checksum(name); 1476 1477} 1478 1479/* 1480 * Routine to put basic stat info into a stat structure ... Used by stat and 1481 * fstat below. 1482 */ 1483 1484static 1485int smbc_setup_stat(SMBCCTX *context, struct stat *st, char *fname, size_t size, int mode) 1486{ 1487 1488 st->st_mode = 0; 1489 1490 if (IS_DOS_DIR(mode)) { 1491 st->st_mode = SMBC_DIR_MODE; 1492 } else { 1493 st->st_mode = SMBC_FILE_MODE; 1494 } 1495 1496 if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR; 1497 if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP; 1498 if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH; 1499 if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR; 1500 1501 st->st_size = size; 1502#ifdef HAVE_STAT_ST_BLKSIZE 1503 st->st_blksize = 512; 1504#endif 1505#ifdef HAVE_STAT_ST_BLOCKS 1506 st->st_blocks = (size+511)/512; 1507#endif 1508 st->st_uid = getuid(); 1509 st->st_gid = getgid(); 1510 1511 if (IS_DOS_DIR(mode)) { 1512 st->st_nlink = 2; 1513 } else { 1514 st->st_nlink = 1; 1515 } 1516 1517 if (st->st_ino == 0) { 1518 st->st_ino = smbc_inode(context, fname); 1519 } 1520 1521 return True; /* FIXME: Is this needed ? */ 1522 1523} 1524 1525/* 1526 * Routine to stat a file given a name 1527 */ 1528 1529static int smbc_stat_ctx(SMBCCTX *context, const char *fname, struct stat *st) 1530{ 1531 SMBCSRV *srv; 1532 fstring server, share, user, password, workgroup; 1533 pstring path; 1534 time_t m_time = 0, a_time = 0, c_time = 0; 1535 size_t size = 0; 1536 uint16 mode = 0; 1537 SMB_INO_T ino = 0; 1538 1539 if (!context || !context->internal || 1540 !context->internal->_initialized) { 1541 1542 errno = EINVAL; /* Best I can think of ... */ 1543 return -1; 1544 1545 } 1546 1547 if (!fname) { 1548 1549 errno = EINVAL; 1550 return -1; 1551 1552 } 1553 1554 DEBUG(4, ("smbc_stat(%s)\n", fname)); 1555 1556 if (smbc_parse_path(context, fname, 1557 server, sizeof(server), 1558 share, sizeof(share), 1559 path, sizeof(path), 1560 user, sizeof(user), 1561 password, sizeof(password), 1562 NULL, 0)) { 1563 errno = EINVAL; 1564 return -1; 1565 } 1566 1567 if (user[0] == (char)0) fstrcpy(user, context->user); 1568 1569 fstrcpy(workgroup, context->workgroup); 1570 1571 srv = smbc_server(context, server, share, workgroup, user, password); 1572 1573 if (!srv) { 1574 return -1; /* errno set by smbc_server */ 1575 } 1576 1577 if (!smbc_getatr(context, srv, path, &mode, &size, 1578 &c_time, &a_time, &m_time, &ino)) { 1579 1580 errno = smbc_errno(context, &srv->cli); 1581 return -1; 1582 1583 } 1584 1585 st->st_ino = ino; 1586 1587 smbc_setup_stat(context, st, path, size, mode); 1588 1589 st->st_atime = a_time; 1590 st->st_ctime = c_time; 1591 st->st_mtime = m_time; 1592 st->st_dev = srv->dev; 1593 1594 return 0; 1595 1596} 1597 1598/* 1599 * Routine to stat a file given an fd 1600 */ 1601 1602static int smbc_fstat_ctx(SMBCCTX *context, SMBCFILE *file, struct stat *st) 1603{ 1604 time_t c_time, a_time, m_time; 1605 size_t size; 1606 uint16 mode; 1607 SMB_INO_T ino = 0; 1608 1609 if (!context || !context->internal || 1610 !context->internal->_initialized) { 1611 1612 errno = EINVAL; 1613 return -1; 1614 1615 } 1616 1617 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { 1618 1619 errno = EBADF; 1620 return -1; 1621 1622 } 1623 1624 if (!file->file) { 1625 1626 return context->fstatdir(context, file, st); 1627 1628 } 1629 1630 if (!cli_qfileinfo(&file->srv->cli, file->cli_fd, 1631 &mode, &size, &c_time, &a_time, &m_time, NULL, &ino)) { 1632 SMB_BIG_UINT b_size = size; 1633 if (!cli_getattrE(&file->srv->cli, file->cli_fd, 1634 &mode, &b_size, &c_time, &a_time, &m_time)) { 1635 1636 errno = EINVAL; 1637 return -1; 1638 } else 1639 size = b_size; 1640 1641 } 1642 1643 st->st_ino = ino; 1644 1645 smbc_setup_stat(context, st, file->fname, size, mode); 1646 1647 st->st_atime = a_time; 1648 st->st_ctime = c_time; 1649 st->st_mtime = m_time; 1650 st->st_dev = file->srv->dev; 1651 1652 return 0; 1653 1654} 1655 1656/* 1657 * Routine to open a directory 1658 * We accept the URL syntax explained in smbc_parse_path(), above. 1659 */ 1660 1661static void smbc_remove_dir(SMBCFILE *dir) 1662{ 1663 struct smbc_dir_list *d,*f; 1664 1665 d = dir->dir_list; 1666 while (d) { 1667 1668 f = d; d = d->next; 1669 1670 SAFE_FREE(f->dirent); 1671 SAFE_FREE(f); 1672 1673 } 1674 1675 dir->dir_list = dir->dir_end = dir->dir_next = NULL; 1676 1677} 1678 1679static int add_dirent(SMBCFILE *dir, const char *name, const char *comment, uint32 type) 1680{ 1681 struct smbc_dirent *dirent; 1682 int size; 1683 int name_length = (name == NULL ? 0 : strlen(name)); 1684 int comment_len = (comment == NULL ? 0 : strlen(comment)); 1685 1686 /* 1687 * Allocate space for the dirent, which must be increased by the 1688 * size of the name and the comment and 1 each for the null terminator. 1689 */ 1690 1691 size = sizeof(struct smbc_dirent) + name_length + comment_len + 2; 1692 1693 dirent = SMB_MALLOC(size); 1694 1695 if (!dirent) { 1696 1697 dir->dir_error = ENOMEM; 1698 return -1; 1699 1700 } 1701 1702 ZERO_STRUCTP(dirent); 1703 1704 if (dir->dir_list == NULL) { 1705 1706 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list); 1707 if (!dir->dir_list) { 1708 1709 SAFE_FREE(dirent); 1710 dir->dir_error = ENOMEM; 1711 return -1; 1712 1713 } 1714 ZERO_STRUCTP(dir->dir_list); 1715 1716 dir->dir_end = dir->dir_next = dir->dir_list; 1717 } 1718 else { 1719 1720 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list); 1721 1722 if (!dir->dir_end->next) { 1723 1724 SAFE_FREE(dirent); 1725 dir->dir_error = ENOMEM; 1726 return -1; 1727 1728 } 1729 ZERO_STRUCTP(dir->dir_end->next); 1730 1731 dir->dir_end = dir->dir_end->next; 1732 } 1733 1734 dir->dir_end->next = NULL; 1735 dir->dir_end->dirent = dirent; 1736 1737 dirent->smbc_type = type; 1738 dirent->namelen = name_length; 1739 dirent->commentlen = comment_len; 1740 dirent->dirlen = size; 1741 1742 strncpy(dirent->name, (name?name:""), dirent->namelen + 1); 1743 1744 dirent->comment = (char *)(&dirent->name + dirent->namelen + 1); 1745 strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1); 1746 1747 return 0; 1748 1749} 1750 1751static void 1752list_unique_wg_fn(const char *name, uint32 type, const char *comment, void *state) 1753{ 1754 SMBCFILE *dir = (SMBCFILE *)state; 1755 struct smbc_dir_list *dir_list; 1756 struct smbc_dirent *dirent; 1757 int dirent_type; 1758 int do_remove = 0; 1759 1760 dirent_type = dir->dir_type; 1761 1762 if (add_dirent(dir, name, comment, dirent_type) < 0) { 1763 1764 /* An error occurred, what do we do? */ 1765 /* FIXME: Add some code here */ 1766 } 1767 1768 /* Point to the one just added */ 1769 dirent = dir->dir_end->dirent; 1770 1771 /* See if this was a duplicate */ 1772 for (dir_list = dir->dir_list; 1773 dir_list != dir->dir_end; 1774 dir_list = dir_list->next) { 1775 if (! do_remove && 1776 strcmp(dir_list->dirent->name, dirent->name) == 0) { 1777 /* Duplicate. End end of list need to be removed. */ 1778 do_remove = 1; 1779 } 1780 1781 if (do_remove && dir_list->next == dir->dir_end) { 1782 /* Found the end of the list. Remove it. */ 1783 dir->dir_end = dir_list; 1784 free(dir_list->next); 1785 dir_list->next = NULL; 1786 break; 1787 } 1788 } 1789} 1790 1791static void 1792list_fn(const char *name, uint32 type, const char *comment, void *state) 1793{ 1794 SMBCFILE *dir = (SMBCFILE *)state; 1795 int dirent_type; 1796 1797 /* We need to process the type a little ... */ 1798 1799 if (dir->dir_type == SMBC_FILE_SHARE) { 1800 1801 switch (type) { 1802 case 0: /* Directory tree */ 1803 dirent_type = SMBC_FILE_SHARE; 1804 break; 1805 1806 case 1: 1807 dirent_type = SMBC_PRINTER_SHARE; 1808 break; 1809 1810 case 2: 1811 dirent_type = SMBC_COMMS_SHARE; 1812 break; 1813 1814 case 3: 1815 dirent_type = SMBC_IPC_SHARE; 1816 break; 1817 1818 default: 1819 dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */ 1820 break; 1821 } 1822 } 1823 else dirent_type = dir->dir_type; 1824 1825 if (add_dirent(dir, name, comment, dirent_type) < 0) { 1826 1827 /* An error occurred, what do we do? */ 1828 /* FIXME: Add some code here */ 1829 1830 } 1831} 1832 1833static void 1834dir_list_fn(const char *mnt, file_info *finfo, const char *mask, void *state) 1835{ 1836 1837 if (add_dirent((SMBCFILE *)state, finfo->name, "", 1838 (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) { 1839 1840 /* Handle an error ... */ 1841 1842 /* FIXME: Add some code ... */ 1843 1844 } 1845 1846} 1847 1848static SMBCFILE *smbc_opendir_ctx(SMBCCTX *context, const char *fname) 1849{ 1850 fstring server, share, user, password, options; 1851 pstring workgroup; 1852 pstring path; 1853 SMBCSRV *srv = NULL; 1854 SMBCFILE *dir = NULL; 1855 struct in_addr rem_ip; 1856 1857 if (!context || !context->internal || 1858 !context->internal->_initialized) { 1859 DEBUG(4, ("no valid context\n")); 1860 errno = EINVAL + 8192; 1861 return NULL; 1862 1863 } 1864 1865 if (!fname) { 1866 DEBUG(4, ("no valid fname\n")); 1867 errno = EINVAL + 8193; 1868 return NULL; 1869 } 1870 1871 if (smbc_parse_path(context, fname, 1872 server, sizeof(server), 1873 share, sizeof(share), 1874 path, sizeof(path), 1875 user, sizeof(user), 1876 password, sizeof(password), 1877 options, sizeof(options))) { 1878 DEBUG(4, ("no valid path\n")); 1879 errno = EINVAL + 8194; 1880 return NULL; 1881 } 1882 1883 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' path='%s' options='%s'\n", fname, server, share, path, options)); 1884 1885 /* Ensure the options are valid */ 1886 if (smbc_check_options(server, share, path, options)) { 1887 DEBUG(4, ("unacceptable options (%s)\n", options)); 1888 errno = EINVAL + 8195; 1889 return NULL; 1890 } 1891 1892 if (user[0] == (char)0) fstrcpy(user, context->user); 1893 1894 pstrcpy(workgroup, context->workgroup); 1895 1896 dir = SMB_MALLOC_P(SMBCFILE); 1897 1898 if (!dir) { 1899 1900 errno = ENOMEM; 1901 return NULL; 1902 1903 } 1904 1905 ZERO_STRUCTP(dir); 1906 1907 dir->cli_fd = 0; 1908 dir->fname = SMB_STRDUP(fname); 1909 dir->srv = NULL; 1910 dir->offset = 0; 1911 dir->file = False; 1912 dir->dir_list = dir->dir_next = dir->dir_end = NULL; 1913 1914 if (server[0] == (char)0) { 1915 1916 int i; 1917 int count; 1918 int max_lmb_count; 1919 struct ip_service *ip_list; 1920 struct ip_service server_addr; 1921 struct user_auth_info u_info; 1922 struct cli_state *cli; 1923 1924 if (share[0] != (char)0 || path[0] != (char)0) { 1925 1926 errno = EINVAL + 8196; 1927 if (dir) { 1928 SAFE_FREE(dir->fname); 1929 SAFE_FREE(dir); 1930 } 1931 return NULL; 1932 } 1933 1934 /* Determine how many local master browsers to query */ 1935 max_lmb_count = (context->options.browse_max_lmb_count == 0 1936 ? INT_MAX 1937 : context->options.browse_max_lmb_count); 1938 1939 pstrcpy(u_info.username, user); 1940 pstrcpy(u_info.password, password); 1941 1942 /* 1943 * We have server and share and path empty but options 1944 * requesting that we scan all master browsers for their list 1945 * of workgroups/domains. This implies that we must first try 1946 * broadcast queries to find all master browsers, and if that 1947 * doesn't work, then try our other methods which return only 1948 * a single master browser. 1949 */ 1950 1951 if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { 1952 if (!find_master_ip(workgroup, &server_addr.ip)) { 1953 1954 errno = ENOENT; 1955 return NULL; 1956 } 1957 1958 ip_list = &server_addr; 1959 count = 1; 1960 } 1961 1962 for (i = 0; i < count && i < max_lmb_count; i++) { 1963 DEBUG(99, ("Found master browser %s\n", inet_ntoa(ip_list[i].ip))); 1964 1965 cli = get_ipc_connect_master_ip(&ip_list[i], workgroup, &u_info); 1966 /* cli == NULL is the master browser refused to talk or 1967 could not be found */ 1968 if ( !cli ) 1969 continue; 1970 1971 fstrcpy(server, cli->desthost); 1972 cli_shutdown(cli); 1973 1974 DEBUG(4, ("using workgroup %s %s\n", workgroup, server)); 1975 1976 /* 1977 * For each returned master browser IP address, get a 1978 * connection to IPC$ on the server if we do not 1979 * already have one, and determine the 1980 * workgroups/domains that it knows about. 1981 */ 1982 1983 srv = smbc_server(context, server, 1984 "IPC$", workgroup, user, password); 1985 if (!srv) { 1986 1987 if (dir) { 1988 SAFE_FREE(dir->fname); 1989 SAFE_FREE(dir); 1990 } 1991 return NULL; 1992 } 1993 1994 dir->srv = srv; 1995 dir->dir_type = SMBC_WORKGROUP; 1996 1997 /* Now, list the stuff ... */ 1998 1999 if (!cli_NetServerEnum(&srv->cli, workgroup, SV_TYPE_DOMAIN_ENUM, list_unique_wg_fn, 2000 (void *)dir)) { 2001 2002 if (dir) { 2003 SAFE_FREE(dir->fname); 2004 SAFE_FREE(dir); 2005 } 2006 2007 return NULL; 2008 2009 } 2010 } 2011 } else { 2012 /* 2013 * Server not an empty string ... Check the rest and see what 2014 * gives 2015 */ 2016 if (share[0] == (char)0) { 2017 2018 if (path[0] != (char)0) { /* Should not have empty share with path */ 2019 2020 errno = EINVAL + 8197; 2021 if (dir) { 2022 SAFE_FREE(dir->fname); 2023 SAFE_FREE(dir); 2024 } 2025 return NULL; 2026 2027 } 2028 2029 /* Check to see if <server><1D>, <server><1B>, or <server><20> translates */ 2030 /* However, we check to see if <server> is an IP address first */ 2031 2032 if (!is_ipaddress(server) && /* Not an IP addr so check next */ 2033 (resolve_name(server, &rem_ip, 0x1d) || /* Found LMB */ 2034 resolve_name(server, &rem_ip, 0x1b) )) { /* Found DMB */ 2035 fstring buserver; 2036 2037 dir->dir_type = SMBC_SERVER; 2038 2039 /* 2040 * Get the backup list ... 2041 */ 2042 2043 2044 if (!name_status_find(server, 0, 0, rem_ip, buserver)) { 2045 2046 DEBUG(0, ("Could not get name of local/domain master browser for server %s\n", server)); 2047 errno = EPERM; /* FIXME, is this correct */ 2048 return NULL; 2049 2050 } 2051 2052 /* 2053 * Get a connection to IPC$ on the server if we do not already have one 2054 */ 2055 2056 srv = smbc_server(context, buserver, "IPC$", workgroup, user, password); 2057 2058 if (!srv) { 2059 DEBUG(0, ("got no contact to IPC$\n")); 2060 if (dir) { 2061 SAFE_FREE(dir->fname); 2062 SAFE_FREE(dir); 2063 } 2064 return NULL; 2065 2066 } 2067 2068 dir->srv = srv; 2069 2070 /* Now, list the servers ... */ 2071 2072 if (!cli_NetServerEnum(&srv->cli, server, 0x0000FFFE, list_fn, 2073 (void *)dir)) { 2074 2075 if (dir) { 2076 SAFE_FREE(dir->fname); 2077 SAFE_FREE(dir); 2078 } 2079 return NULL; 2080 2081 } 2082 } 2083 else { 2084 2085 if (resolve_name(server, &rem_ip, 0x20)) { 2086 2087 /* Now, list the shares ... */ 2088 2089 dir->dir_type = SMBC_FILE_SHARE; 2090 2091 srv = smbc_server(context, server, "IPC$", workgroup, user, password); 2092 2093 if (!srv) { 2094 2095 if (dir) { 2096 SAFE_FREE(dir->fname); 2097 SAFE_FREE(dir); 2098 } 2099 return NULL; 2100 2101 } 2102 2103 dir->srv = srv; 2104 2105 /* Now, list the servers ... */ 2106 2107 if (cli_RNetShareEnum(&srv->cli, list_fn, 2108 (void *)dir) < 0) { 2109 2110 errno = cli_errno(&srv->cli); 2111 if (dir) { 2112 SAFE_FREE(dir->fname); 2113 SAFE_FREE(dir); 2114 } 2115 return NULL; 2116 2117 } 2118 2119 } 2120 else { 2121 2122 errno = ECONNREFUSED; /* Neither the workgroup nor server exists */ 2123 if (dir) { 2124 SAFE_FREE(dir->fname); 2125 SAFE_FREE(dir); 2126 } 2127 return NULL; 2128 2129 } 2130 2131 } 2132 2133 } 2134 else { /* The server and share are specified ... work from there ... */ 2135 2136 /* Well, we connect to the server and list the directory */ 2137 2138 dir->dir_type = SMBC_FILE_SHARE; 2139 2140 srv = smbc_server(context, server, share, workgroup, user, password); 2141 2142 if (!srv) { 2143 2144 if (dir) { 2145 SAFE_FREE(dir->fname); 2146 SAFE_FREE(dir); 2147 } 2148 return NULL; 2149 2150 } 2151 2152 dir->srv = srv; 2153 2154 /* Now, list the files ... */ 2155 2156 pstrcat(path, "\\*"); 2157 2158 if (cli_list(&srv->cli, path, aDIR | aSYSTEM | aHIDDEN, dir_list_fn, 2159 (void *)dir) < 0) { 2160 2161 if (dir) { 2162 SAFE_FREE(dir->fname); 2163 SAFE_FREE(dir); 2164 } 2165 errno = smbc_errno(context, &srv->cli); 2166 return NULL; 2167 2168 } 2169 } 2170 2171 } 2172 2173 DLIST_ADD(context->internal->_files, dir); 2174 return dir; 2175 2176} 2177 2178/* 2179 * Routine to close a directory 2180 */ 2181 2182static int smbc_closedir_ctx(SMBCCTX *context, SMBCFILE *dir) 2183{ 2184 2185 if (!context || !context->internal || 2186 !context->internal->_initialized) { 2187 2188 errno = EINVAL; 2189 return -1; 2190 2191 } 2192 2193 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 2194 2195 errno = EBADF; 2196 return -1; 2197 2198 } 2199 2200 smbc_remove_dir(dir); /* Clean it up */ 2201 2202 DLIST_REMOVE(context->internal->_files, dir); 2203 2204 if (dir) { 2205 2206 SAFE_FREE(dir->fname); 2207 SAFE_FREE(dir); /* Free the space too */ 2208 } 2209 2210 return 0; 2211 2212} 2213 2214static void smbc_readdir_internal(SMBCCTX * context, 2215 struct smbc_dirent *dest, 2216 struct smbc_dirent *src, 2217 int max_namebuf_len) 2218{ 2219 if (context->options.urlencode_readdir_entries) { 2220 2221 /* url-encode the name. get back remaining buffer space */ 2222 max_namebuf_len = 2223 smbc_urlencode(dest->name, src->name, max_namebuf_len); 2224 2225 /* We now know the name length */ 2226 dest->namelen = strlen(dest->name); 2227 2228 /* Save the pointer to the beginning of the comment */ 2229 dest->comment = dest->name + dest->namelen + 1; 2230 2231 /* Copy the comment */ 2232 strncpy(dest->comment, src->comment, max_namebuf_len); 2233 2234 /* Ensure the comment is null terminated */ 2235 if (max_namebuf_len > src->commentlen) { 2236 dest->comment[src->commentlen] = '\0'; 2237 } else { 2238 dest->comment[max_namebuf_len - 1] = '\0'; 2239 } 2240 2241 /* Save other fields */ 2242 dest->smbc_type = src->smbc_type; 2243 dest->commentlen = strlen(dest->comment); 2244 dest->dirlen = ((dest->comment + dest->commentlen + 1) - 2245 (char *) dest); 2246 } else { 2247 2248 /* No encoding. Just copy the entry as is. */ 2249 memcpy(dest, src, src->dirlen); 2250 dest->comment = (char *)(&dest->name + src->namelen + 1); 2251 } 2252 2253} 2254 2255/* 2256 * Routine to get a directory entry 2257 */ 2258 2259struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir) 2260{ 2261 int maxlen; 2262 struct smbc_dirent *dirp, *dirent; 2263 2264 /* Check that all is ok first ... */ 2265 2266 if (!context || !context->internal || 2267 !context->internal->_initialized) { 2268 2269 errno = EINVAL; 2270 DEBUG(0, ("Invalid context in smbc_readdir_ctx()\n")); 2271 return NULL; 2272 2273 } 2274 2275 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 2276 2277 errno = EBADF; 2278 DEBUG(0, ("Invalid dir in smbc_readdir_ctx()\n")); 2279 return NULL; 2280 2281 } 2282 2283 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 2284 2285 errno = ENOTDIR; 2286 DEBUG(0, ("Found file vs directory in smbc_readdir_ctx()\n")); 2287 return NULL; 2288 2289 } 2290 2291 if (!dir->dir_next) { 2292 return NULL; 2293 } 2294 2295 dirent = dir->dir_next->dirent; 2296 if (!dirent) { 2297 2298 errno = ENOENT; 2299 return NULL; 2300 2301 } 2302 2303 dirp = (struct smbc_dirent *)context->internal->_dirent; 2304 maxlen = (sizeof(context->internal->_dirent) - 2305 sizeof(struct smbc_dirent)); 2306 2307 smbc_readdir_internal(context, dirp, dirent, maxlen); 2308 2309 dir->dir_next = dir->dir_next->next; 2310 2311 return dirp; 2312} 2313 2314/* 2315 * Routine to get directory entries 2316 */ 2317 2318static int smbc_getdents_ctx(SMBCCTX *context, 2319 SMBCFILE *dir, 2320 struct smbc_dirent *dirp, 2321 int count) 2322{ 2323 int rem = count; 2324 int reqd; 2325 int maxlen; 2326 char *ndir = (char *)dirp; 2327 struct smbc_dir_list *dirlist; 2328 2329 /* Check that all is ok first ... */ 2330 2331 if (!context || !context->internal || 2332 !context->internal->_initialized) { 2333 2334 errno = EINVAL; 2335 return -1; 2336 2337 } 2338 2339 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 2340 2341 errno = EBADF; 2342 return -1; 2343 2344 } 2345 2346 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 2347 2348 errno = ENOTDIR; 2349 return -1; 2350 2351 } 2352 2353 /* 2354 * Now, retrieve the number of entries that will fit in what was passed 2355 * We have to figure out if the info is in the list, or we need to 2356 * send a request to the server to get the info. 2357 */ 2358 2359 while ((dirlist = dir->dir_next)) { 2360 struct smbc_dirent *dirent; 2361 2362 if (!dirlist->dirent) { 2363 2364 errno = ENOENT; /* Bad error */ 2365 return -1; 2366 2367 } 2368 2369 /* Do urlencoding of next entry, if so selected */ 2370 dirent = (struct smbc_dirent *)context->internal->_dirent; 2371 maxlen = (sizeof(context->internal->_dirent) - 2372 sizeof(struct smbc_dirent)); 2373 smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen); 2374 2375 reqd = dirent->dirlen; 2376 2377 if (rem < reqd) { 2378 2379 if (rem < count) { /* We managed to copy something */ 2380 2381 errno = 0; 2382 return count - rem; 2383 2384 } 2385 else { /* Nothing copied ... */ 2386 2387 errno = EINVAL; /* Not enough space ... */ 2388 return -1; 2389 2390 } 2391 2392 } 2393 2394 memcpy(ndir, dirent, reqd); /* Copy the data in ... */ 2395 2396 ((struct smbc_dirent *)ndir)->comment = 2397 (char *)(&((struct smbc_dirent *)ndir)->name + 2398 dirent->namelen + 2399 1); 2400 2401 ndir += reqd; 2402 2403 rem -= reqd; 2404 2405 dir->dir_next = dirlist = dirlist -> next; 2406 } 2407 2408 if (rem == count) 2409 return 0; 2410 else 2411 return count - rem; 2412 2413} 2414 2415/* 2416 * Routine to create a directory ... 2417 */ 2418 2419static int smbc_mkdir_ctx(SMBCCTX *context, const char *fname, mode_t mode) 2420{ 2421 SMBCSRV *srv; 2422 fstring server, share, user, password, workgroup; 2423 pstring path; 2424 2425 if (!context || !context->internal || 2426 !context->internal->_initialized) { 2427 2428 errno = EINVAL; 2429 return -1; 2430 2431 } 2432 2433 if (!fname) { 2434 2435 errno = EINVAL; 2436 return -1; 2437 2438 } 2439 2440 DEBUG(4, ("smbc_mkdir(%s)\n", fname)); 2441 2442 if (smbc_parse_path(context, fname, 2443 server, sizeof(server), 2444 share, sizeof(share), 2445 path, sizeof(path), 2446 user, sizeof(user), 2447 password, sizeof(password), 2448 NULL, 0)) { 2449 errno = EINVAL; 2450 return -1; 2451 } 2452 2453 if (user[0] == (char)0) fstrcpy(user, context->user); 2454 2455 fstrcpy(workgroup, context->workgroup); 2456 2457 srv = smbc_server(context, server, share, workgroup, user, password); 2458 2459 if (!srv) { 2460 2461 return -1; /* errno set by smbc_server */ 2462 2463 } 2464 2465 if (!cli_mkdir(&srv->cli, path)) { 2466 2467 errno = smbc_errno(context, &srv->cli); 2468 return -1; 2469 2470 } 2471 2472 return 0; 2473 2474} 2475 2476/* 2477 * Our list function simply checks to see if a directory is not empty 2478 */ 2479 2480static int smbc_rmdir_dirempty = True; 2481 2482static void rmdir_list_fn(const char *mnt, file_info *finfo, const char *mask, void *state) 2483{ 2484 2485 if (strncmp(finfo->name, ".", 1) != 0 && strncmp(finfo->name, "..", 2) != 0) 2486 smbc_rmdir_dirempty = False; 2487 2488} 2489 2490/* 2491 * Routine to remove a directory 2492 */ 2493 2494static int smbc_rmdir_ctx(SMBCCTX *context, const char *fname) 2495{ 2496 SMBCSRV *srv; 2497 fstring server, share, user, password, workgroup; 2498 pstring path; 2499 2500 if (!context || !context->internal || 2501 !context->internal->_initialized) { 2502 2503 errno = EINVAL; 2504 return -1; 2505 2506 } 2507 2508 if (!fname) { 2509 2510 errno = EINVAL; 2511 return -1; 2512 2513 } 2514 2515 DEBUG(4, ("smbc_rmdir(%s)\n", fname)); 2516 2517 if (smbc_parse_path(context, fname, 2518 server, sizeof(server), 2519 share, sizeof(share), 2520 path, sizeof(path), 2521 user, sizeof(user), 2522 password, sizeof(password), 2523 NULL, 0)) 2524 { 2525 errno = EINVAL; 2526 return -1; 2527 } 2528 2529 if (user[0] == (char)0) fstrcpy(user, context->user); 2530 2531 fstrcpy(workgroup, context->workgroup); 2532 2533 srv = smbc_server(context, server, share, workgroup, user, password); 2534 2535 if (!srv) { 2536 2537 return -1; /* errno set by smbc_server */ 2538 2539 } 2540 2541 /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) { 2542 2543 mode = aDIR | aRONLY; 2544 2545 } 2546 else if (strncmp(srv->cli.dev, "LPT", 3) == 0) { 2547 2548 if (strcmp(path, "\\") == 0) { 2549 2550 mode = aDIR | aRONLY; 2551 2552 } 2553 else { 2554 2555 mode = aRONLY; 2556 smbc_stat_printjob(srv, path, &size, &m_time); 2557 c_time = a_time = m_time; 2558 2559 } 2560 else { */ 2561 2562 if (!cli_rmdir(&srv->cli, path)) { 2563 2564 errno = smbc_errno(context, &srv->cli); 2565 2566 if (errno == EACCES) { /* Check if the dir empty or not */ 2567 2568 pstring lpath; /* Local storage to avoid buffer overflows */ 2569 2570 smbc_rmdir_dirempty = True; /* Make this so ... */ 2571 2572 pstrcpy(lpath, path); 2573 pstrcat(lpath, "\\*"); 2574 2575 if (cli_list(&srv->cli, lpath, aDIR | aSYSTEM | aHIDDEN, rmdir_list_fn, 2576 NULL) < 0) { 2577 2578 /* Fix errno to ignore latest error ... */ 2579 2580 DEBUG(5, ("smbc_rmdir: cli_list returned an error: %d\n", 2581 smbc_errno(context, &srv->cli))); 2582 errno = EACCES; 2583 2584 } 2585 2586 if (smbc_rmdir_dirempty) 2587 errno = EACCES; 2588 else 2589 errno = ENOTEMPTY; 2590 2591 } 2592 2593 return -1; 2594 2595 } 2596 2597 return 0; 2598 2599} 2600 2601/* 2602 * Routine to return the current directory position 2603 */ 2604 2605static off_t smbc_telldir_ctx(SMBCCTX *context, SMBCFILE *dir) 2606{ 2607 off_t ret_val; /* Squash warnings about cast */ 2608 2609 if (!context || !context->internal || 2610 !context->internal->_initialized) { 2611 2612 errno = EINVAL; 2613 return -1; 2614 2615 } 2616 2617 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { 2618 2619 errno = EBADF; 2620 return -1; 2621 2622 } 2623 2624 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 2625 2626 errno = ENOTDIR; 2627 return -1; 2628 2629 } 2630 2631 /* 2632 * We return the pointer here as the offset 2633 */ 2634 ret_val = (int)dir->dir_next; 2635 return ret_val; 2636 2637} 2638 2639/* 2640 * A routine to run down the list and see if the entry is OK 2641 */ 2642 2643struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, 2644 struct smbc_dirent *dirent) 2645{ 2646 2647 /* Run down the list looking for what we want */ 2648 2649 if (dirent) { 2650 2651 struct smbc_dir_list *tmp = list; 2652 2653 while (tmp) { 2654 2655 if (tmp->dirent == dirent) 2656 return tmp; 2657 2658 tmp = tmp->next; 2659 2660 } 2661 2662 } 2663 2664 return NULL; /* Not found, or an error */ 2665 2666} 2667 2668 2669/* 2670 * Routine to seek on a directory 2671 */ 2672 2673static int smbc_lseekdir_ctx(SMBCCTX *context, SMBCFILE *dir, off_t offset) 2674{ 2675 long int l_offset = offset; /* Handle problems of size */ 2676 struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset; 2677 struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL; 2678 2679 if (!context || !context->internal || 2680 !context->internal->_initialized) { 2681 2682 errno = EINVAL; 2683 return -1; 2684 2685 } 2686 2687 if (dir->file != False) { /* FIXME, should be dir, perhaps */ 2688 2689 errno = ENOTDIR; 2690 return -1; 2691 2692 } 2693 2694 /* Now, check what we were passed and see if it is OK ... */ 2695 2696 if (dirent == NULL) { /* Seek to the begining of the list */ 2697 2698 dir->dir_next = dir->dir_list; 2699 return 0; 2700 2701 } 2702 2703 /* Now, run down the list and make sure that the entry is OK */ 2704 /* This may need to be changed if we change the format of the list */ 2705 2706 if ((list_ent = smbc_check_dir_ent(dir->dir_list, dirent)) == NULL) { 2707 2708 errno = EINVAL; /* Bad entry */ 2709 return -1; 2710 2711 } 2712 2713 dir->dir_next = list_ent; 2714 2715 return 0; 2716 2717} 2718 2719/* 2720 * Routine to fstat a dir 2721 */ 2722 2723static int smbc_fstatdir_ctx(SMBCCTX *context, SMBCFILE *dir, struct stat *st) 2724{ 2725 2726 if (!context || !context->internal || 2727 !context->internal->_initialized) { 2728 2729 errno = EINVAL; 2730 return -1; 2731 2732 } 2733 2734 /* No code yet ... */ 2735 2736 return 0; 2737 2738} 2739 2740int smbc_chmod_ctx(SMBCCTX *context, const char *fname, mode_t newmode) 2741{ 2742 SMBCSRV *srv; 2743 fstring server, share, user, password, workgroup; 2744 pstring path; 2745 uint16 mode; 2746 2747 if (!context || !context->internal || 2748 !context->internal->_initialized) { 2749 2750 errno = EINVAL; /* Best I can think of ... */ 2751 return -1; 2752 2753 } 2754 2755 if (!fname) { 2756 2757 errno = EINVAL; 2758 return -1; 2759 2760 } 2761 2762 DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode)); 2763 2764 if (smbc_parse_path(context, fname, 2765 server, sizeof(server), 2766 share, sizeof(share), 2767 path, sizeof(path), 2768 user, sizeof(user), 2769 password, sizeof(password), 2770 NULL, 0)) { 2771 errno = EINVAL; 2772 return -1; 2773 } 2774 2775 if (user[0] == (char)0) fstrcpy(user, context->user); 2776 2777 fstrcpy(workgroup, context->workgroup); 2778 2779 srv = smbc_server(context, server, share, workgroup, user, password); 2780 2781 if (!srv) { 2782 return -1; /* errno set by smbc_server */ 2783 } 2784 2785 mode = 0; 2786 2787 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; 2788 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; 2789 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; 2790 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; 2791 2792 if (!cli_setatr(&srv->cli, path, mode, 0)) { 2793 errno = smbc_errno(context, &srv->cli); 2794 return -1; 2795 } 2796 2797 return 0; 2798} 2799 2800int smbc_utimes_ctx(SMBCCTX *context, const char *fname, struct timeval *tbuf) 2801{ 2802 SMBCSRV *srv; 2803 fstring server, share, user, password, workgroup; 2804 pstring path; 2805 uint16 mode; 2806 time_t t = (tbuf == NULL ? time(NULL) : tbuf->tv_sec); 2807 2808 if (!context || !context->internal || 2809 !context->internal->_initialized) { 2810 2811 errno = EINVAL; /* Best I can think of ... */ 2812 return -1; 2813 2814 } 2815 2816 if (!fname) { 2817 2818 errno = EINVAL; 2819 return -1; 2820 2821 } 2822 2823 DEBUG(4, ("smbc_utimes(%s, [%s])\n", fname, ctime(&t))); 2824 2825 if (smbc_parse_path(context, fname, 2826 server, sizeof(server), 2827 share, sizeof(share), 2828 path, sizeof(path), 2829 user, sizeof(user), 2830 password, sizeof(password), 2831 NULL, 0)) { 2832 errno = EINVAL; 2833 return -1; 2834 } 2835 2836 if (user[0] == (char)0) fstrcpy(user, context->user); 2837 2838 fstrcpy(workgroup, context->workgroup); 2839 2840 srv = smbc_server(context, server, share, workgroup, user, password); 2841 2842 if (!srv) { 2843 return -1; /* errno set by smbc_server */ 2844 } 2845 2846 if (!smbc_getatr(context, srv, path, 2847 &mode, NULL, 2848 NULL, NULL, NULL, 2849 NULL)) { 2850 return -1; 2851 } 2852 2853 if (!cli_setatr(&srv->cli, path, mode, t)) { 2854 /* some servers always refuse directory changes */ 2855 if (!(mode & aDIR)) { 2856 errno = smbc_errno(context, &srv->cli); 2857 return -1; 2858 } 2859 } 2860 2861 return 0; 2862} 2863 2864 2865/* The MSDN is contradictory over the ordering of ACE entries in an ACL. 2866 However NT4 gives a "The information may have been modified by a 2867 computer running Windows NT 5.0" if denied ACEs do not appear before 2868 allowed ACEs. */ 2869 2870static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2) 2871{ 2872 if (sec_ace_equal(ace1, ace2)) 2873 return 0; 2874 2875 if (ace1->type != ace2->type) 2876 return ace2->type - ace1->type; 2877 2878 if (sid_compare(&ace1->trustee, &ace2->trustee)) 2879 return sid_compare(&ace1->trustee, &ace2->trustee); 2880 2881 if (ace1->flags != ace2->flags) 2882 return ace1->flags - ace2->flags; 2883 2884 if (ace1->info.mask != ace2->info.mask) 2885 return ace1->info.mask - ace2->info.mask; 2886 2887 if (ace1->size != ace2->size) 2888 return ace1->size - ace2->size; 2889 2890 return memcmp(ace1, ace2, sizeof(SEC_ACE)); 2891} 2892 2893 2894static void sort_acl(SEC_ACL *the_acl) 2895{ 2896 uint32 i; 2897 if (!the_acl) return; 2898 2899 qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]), QSORT_CAST ace_compare); 2900 2901 for (i=1;i<the_acl->num_aces;) { 2902 if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) { 2903 int j; 2904 for (j=i; j<the_acl->num_aces-1; j++) { 2905 the_acl->ace[j] = the_acl->ace[j+1]; 2906 } 2907 the_acl->num_aces--; 2908 } else { 2909 i++; 2910 } 2911 } 2912} 2913 2914/* convert a SID to a string, either numeric or username/group */ 2915static void convert_sid_to_string(struct cli_state *ipc_cli, 2916 POLICY_HND *pol, 2917 fstring str, 2918 BOOL numeric, 2919 DOM_SID *sid) 2920{ 2921 char **domains = NULL; 2922 char **names = NULL; 2923 uint32 *types = NULL; 2924 2925 sid_to_string(str, sid); 2926 2927 if (numeric) return; /* no lookup desired */ 2928 2929 /* Ask LSA to convert the sid to a name */ 2930 2931 if (!NT_STATUS_IS_OK(cli_lsa_lookup_sids(ipc_cli, ipc_cli->mem_ctx, 2932 pol, 1, sid, &domains, 2933 &names, &types)) || 2934 !domains || !domains[0] || !names || !names[0]) { 2935 return; 2936 } 2937 2938 /* Converted OK */ 2939 2940 slprintf(str, sizeof(fstring) - 1, "%s%s%s", 2941 domains[0], lp_winbind_separator(), 2942 names[0]); 2943} 2944 2945/* convert a string to a SID, either numeric or username/group */ 2946static BOOL convert_string_to_sid(struct cli_state *ipc_cli, 2947 POLICY_HND *pol, 2948 BOOL numeric, 2949 DOM_SID *sid, 2950 const char *str) 2951{ 2952 uint32 *types = NULL; 2953 DOM_SID *sids = NULL; 2954 BOOL result = True; 2955 2956 if (numeric) { 2957 if (strncmp(str, "S-", 2) == 0) { 2958 return string_to_sid(sid, str); 2959 } 2960 2961 result = False; 2962 goto done; 2963 } 2964 2965 if (!NT_STATUS_IS_OK(cli_lsa_lookup_names(ipc_cli, ipc_cli->mem_ctx, 2966 pol, 1, &str, &sids, 2967 &types))) { 2968 result = False; 2969 goto done; 2970 } 2971 2972 sid_copy(sid, &sids[0]); 2973 done: 2974 2975 return result; 2976} 2977 2978 2979/* parse an ACE in the same format as print_ace() */ 2980static BOOL parse_ace(struct cli_state *ipc_cli, 2981 POLICY_HND *pol, 2982 SEC_ACE *ace, 2983 BOOL numeric, 2984 char *str) 2985{ 2986 char *p; 2987 const char *cp; 2988 fstring tok; 2989 unsigned atype, aflags, amask; 2990 DOM_SID sid; 2991 SEC_ACCESS mask; 2992 const struct perm_value *v; 2993 struct perm_value { 2994 const char *perm; 2995 uint32 mask; 2996 }; 2997 2998 /* These values discovered by inspection */ 2999 static const struct perm_value special_values[] = { 3000 { "R", 0x00120089 }, 3001 { "W", 0x00120116 }, 3002 { "X", 0x001200a0 }, 3003 { "D", 0x00010000 }, 3004 { "P", 0x00040000 }, 3005 { "O", 0x00080000 }, 3006 { NULL, 0 }, 3007 }; 3008 3009 static const struct perm_value standard_values[] = { 3010 { "READ", 0x001200a9 }, 3011 { "CHANGE", 0x001301bf }, 3012 { "FULL", 0x001f01ff }, 3013 { NULL, 0 }, 3014 }; 3015 3016 3017 ZERO_STRUCTP(ace); 3018 p = strchr_m(str,':'); 3019 if (!p) return False; 3020 *p = '\0'; 3021 p++; 3022 /* Try to parse numeric form */ 3023 3024 if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 && 3025 convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { 3026 goto done; 3027 } 3028 3029 /* Try to parse text form */ 3030 3031 if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { 3032 return False; 3033 } 3034 3035 cp = p; 3036 if (!next_token(&cp, tok, "/", sizeof(fstring))) { 3037 return False; 3038 } 3039 3040 if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { 3041 atype = SEC_ACE_TYPE_ACCESS_ALLOWED; 3042 } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) { 3043 atype = SEC_ACE_TYPE_ACCESS_DENIED; 3044 } else { 3045 return False; 3046 } 3047 3048 /* Only numeric form accepted for flags at present */ 3049 3050 if (!(next_token(&cp, tok, "/", sizeof(fstring)) && 3051 sscanf(tok, "%i", &aflags))) { 3052 return False; 3053 } 3054 3055 if (!next_token(&cp, tok, "/", sizeof(fstring))) { 3056 return False; 3057 } 3058 3059 if (strncmp(tok, "0x", 2) == 0) { 3060 if (sscanf(tok, "%i", &amask) != 1) { 3061 return False; 3062 } 3063 goto done; 3064 } 3065 3066 for (v = standard_values; v->perm; v++) { 3067 if (strcmp(tok, v->perm) == 0) { 3068 amask = v->mask; 3069 goto done; 3070 } 3071 } 3072 3073 p = tok; 3074 3075 while(*p) { 3076 BOOL found = False; 3077 3078 for (v = special_values; v->perm; v++) { 3079 if (v->perm[0] == *p) { 3080 amask |= v->mask; 3081 found = True; 3082 } 3083 } 3084 3085 if (!found) return False; 3086 p++; 3087 } 3088 3089 if (*p) { 3090 return False; 3091 } 3092 3093 done: 3094 mask.mask = amask; 3095 init_sec_ace(ace, &sid, atype, mask, aflags); 3096 return True; 3097} 3098 3099/* add an ACE to a list of ACEs in a SEC_ACL */ 3100static BOOL add_ace(SEC_ACL **the_acl, SEC_ACE *ace, TALLOC_CTX *ctx) 3101{ 3102 SEC_ACL *new; 3103 SEC_ACE *aces; 3104 if (! *the_acl) { 3105 (*the_acl) = make_sec_acl(ctx, 3, 1, ace); 3106 return True; 3107 } 3108 3109 aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces); 3110 memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE)); 3111 memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE)); 3112 new = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces); 3113 SAFE_FREE(aces); 3114 (*the_acl) = new; 3115 return True; 3116} 3117 3118 3119/* parse a ascii version of a security descriptor */ 3120static SEC_DESC *sec_desc_parse(TALLOC_CTX *ctx, 3121 struct cli_state *ipc_cli, 3122 POLICY_HND *pol, 3123 BOOL numeric, 3124 char *str) 3125{ 3126 const char *p = str; 3127 fstring tok; 3128 SEC_DESC *ret; 3129 size_t sd_size; 3130 DOM_SID *grp_sid=NULL, *owner_sid=NULL; 3131 SEC_ACL *dacl=NULL; 3132 int revision=1; 3133 3134 while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { 3135 3136 if (StrnCaseCmp(tok,"REVISION:", 9) == 0) { 3137 revision = strtol(tok+9, NULL, 16); 3138 continue; 3139 } 3140 3141 if (StrnCaseCmp(tok,"OWNER:", 6) == 0) { 3142 owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 3143 if (!owner_sid || 3144 !convert_string_to_sid(ipc_cli, pol, 3145 numeric, 3146 owner_sid, tok+6)) { 3147 DEBUG(5, ("Failed to parse owner sid\n")); 3148 return NULL; 3149 } 3150 continue; 3151 } 3152 3153 if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) { 3154 owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 3155 if (!owner_sid || 3156 !convert_string_to_sid(ipc_cli, pol, 3157 False, 3158 owner_sid, tok+7)) { 3159 DEBUG(5, ("Failed to parse owner sid\n")); 3160 return NULL; 3161 } 3162 continue; 3163 } 3164 3165 if (StrnCaseCmp(tok,"GROUP:", 6) == 0) { 3166 grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 3167 if (!grp_sid || 3168 !convert_string_to_sid(ipc_cli, pol, 3169 numeric, 3170 grp_sid, tok+6)) { 3171 DEBUG(5, ("Failed to parse group sid\n")); 3172 return NULL; 3173 } 3174 continue; 3175 } 3176 3177 if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) { 3178 grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); 3179 if (!grp_sid || 3180 !convert_string_to_sid(ipc_cli, pol, 3181 False, 3182 grp_sid, tok+6)) { 3183 DEBUG(5, ("Failed to parse group sid\n")); 3184 return NULL; 3185 } 3186 continue; 3187 } 3188 3189 if (StrnCaseCmp(tok,"ACL:", 4) == 0) { 3190 SEC_ACE ace; 3191 if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) { 3192 DEBUG(5, ("Failed to parse ACL %s\n", tok)); 3193 return NULL; 3194 } 3195 if(!add_ace(&dacl, &ace, ctx)) { 3196 DEBUG(5, ("Failed to add ACL %s\n", tok)); 3197 return NULL; 3198 } 3199 continue; 3200 } 3201 3202 if (StrnCaseCmp(tok,"ACL+:", 5) == 0) { 3203 SEC_ACE ace; 3204 if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) { 3205 DEBUG(5, ("Failed to parse ACL %s\n", tok)); 3206 return NULL; 3207 } 3208 if(!add_ace(&dacl, &ace, ctx)) { 3209 DEBUG(5, ("Failed to add ACL %s\n", tok)); 3210 return NULL; 3211 } 3212 continue; 3213 } 3214 3215 DEBUG(5, ("Failed to parse security descriptor\n")); 3216 return NULL; 3217 } 3218 3219 ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, 3220 owner_sid, grp_sid, NULL, dacl, &sd_size); 3221 3222 SAFE_FREE(grp_sid); 3223 SAFE_FREE(owner_sid); 3224 3225 return ret; 3226} 3227 3228 3229/* Obtain the current dos attributes */ 3230static DOS_ATTR_DESC *dos_attr_query(SMBCCTX *context, 3231 TALLOC_CTX *ctx, 3232 const char *filename, 3233 SMBCSRV *srv) 3234{ 3235 time_t m_time = 0, a_time = 0, c_time = 0; 3236 size_t size = 0; 3237 uint16 mode = 0; 3238 SMB_INO_T inode = 0; 3239 DOS_ATTR_DESC *ret; 3240 3241 ret = talloc(ctx, sizeof(DOS_ATTR_DESC)); 3242 if (!ret) { 3243 errno = ENOMEM; 3244 return NULL; 3245 } 3246 3247 /* Obtain the DOS attributes */ 3248 if (!smbc_getatr(context, srv, filename, &mode, &size, 3249 &c_time, &a_time, &m_time, &inode)) { 3250 3251 errno = smbc_errno(context, &srv->cli); 3252 DEBUG(5, ("dos_attr_query Failed to query old attributes\n")); 3253 return NULL; 3254 3255 } 3256 3257 ret->mode = mode; 3258 ret->size = size; 3259 ret->a_time = a_time; 3260 ret->c_time = c_time; 3261 ret->m_time = m_time; 3262 ret->inode = inode; 3263 3264 return ret; 3265} 3266 3267 3268/* parse a ascii version of a security descriptor */ 3269static void dos_attr_parse(SMBCCTX *context, 3270 DOS_ATTR_DESC *dad, 3271 SMBCSRV *srv, 3272 char *str) 3273{ 3274 const char *p = str; 3275 fstring tok; 3276 3277 while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { 3278 3279 if (StrnCaseCmp(tok, "MODE:", 5) == 0) { 3280 dad->mode = strtol(tok+5, NULL, 16); 3281 continue; 3282 } 3283 3284 if (StrnCaseCmp(tok, "SIZE:", 5) == 0) { 3285 dad->size = strtoll(tok+5, NULL, 10); 3286 continue; 3287 } 3288 3289 if (StrnCaseCmp(tok, "A_TIME:", 7) == 0) { 3290 dad->a_time = strtoll(tok+7, NULL, 10); 3291 continue; 3292 } 3293 3294 if (StrnCaseCmp(tok, "C_TIME:", 7) == 0) { 3295 dad->c_time = strtoll(tok+7, NULL, 10); 3296 continue; 3297 } 3298 3299 if (StrnCaseCmp(tok, "M_TIME:", 7) == 0) { 3300 dad->m_time = strtoll(tok+7, NULL, 10); 3301 continue; 3302 } 3303 3304 if (StrnCaseCmp(tok, "INODE:", 6) == 0) { 3305 dad->inode = strtoll(tok+6, NULL, 10); 3306 continue; 3307 } 3308 } 3309} 3310 3311 3312/***************************************************** 3313retrieve the acls for a file 3314*******************************************************/ 3315static int cacl_get(SMBCCTX *context, TALLOC_CTX *ctx, SMBCSRV *srv, 3316 struct cli_state *ipc_cli, POLICY_HND *pol, 3317 char *filename, char *name, char *buf, int bufsize) 3318{ 3319 uint32 i; 3320 int n = 0; 3321 int n_used; 3322 BOOL all; 3323 BOOL all_nt; 3324 BOOL all_dos; 3325 BOOL some_nt; 3326 BOOL some_dos; 3327 BOOL numeric = True; 3328 BOOL determine_size = (bufsize == 0); 3329 int fnum = -1; 3330 SEC_DESC *sd; 3331 fstring sidstr; 3332 char *p; 3333 time_t m_time = 0, a_time = 0, c_time = 0; 3334 size_t size = 0; 3335 uint16 mode = 0; 3336 SMB_INO_T ino = 0; 3337 struct cli_state *cli = &srv->cli; 3338 3339 all = (StrnCaseCmp(name, "system.*", 8) == 0); 3340 all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0); 3341 all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0); 3342 some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0); 3343 some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0); 3344 numeric = (* (name + strlen(name) - 1) != '+'); 3345 3346 n_used = 0; 3347 3348 /* 3349 * If we are (possibly) talking to an NT or new system and some NT 3350 * attributes have been requested... 3351 */ 3352 if (ipc_cli && (all || some_nt)) { 3353 /* Point to the portion after "system.nt_sec_desc." */ 3354 name += 19; /* if (all) this will be invalid but unused */ 3355 3356 /* ... then obtain any NT attributes which were requested */ 3357 fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); 3358 3359 if (fnum == -1) { 3360 DEBUG(5, ("cacl_get failed to open %s: %s\n", 3361 filename, cli_errstr(cli))); 3362 errno = 0; 3363 return -1; 3364 } 3365 3366 sd = cli_query_secdesc(cli, fnum, ctx); 3367 3368 if (!sd) { 3369 DEBUG(5, 3370 ("cacl_get Failed to query old descriptor\n")); 3371 errno = 0; 3372 return -1; 3373 } 3374 3375 cli_close(cli, fnum); 3376 3377 if (all || all_nt) { 3378 if (determine_size) { 3379 p = talloc_asprintf(ctx, 3380 "REVISION:%d", 3381 sd->revision); 3382 if (!p) { 3383 errno = ENOMEM; 3384 return -1; 3385 } 3386 n = strlen(p); 3387 } else { 3388 n = snprintf(buf, bufsize, 3389 "REVISION:%d", sd->revision); 3390 } 3391 } else if (StrCaseCmp(name, "revision") == 0) { 3392 if (determine_size) { 3393 p = talloc_asprintf(ctx, "%d", sd->revision); 3394 if (!p) { 3395 errno = ENOMEM; 3396 return -1; 3397 } 3398 n = strlen(p); 3399 } else { 3400 n = snprintf(buf, bufsize, "%d", sd->revision); 3401 } 3402 } 3403 3404 if (!determine_size && n > bufsize) { 3405 errno = ERANGE; 3406 return -1; 3407 } 3408 buf += n; 3409 n_used += n; 3410 bufsize -= n; 3411 3412 /* Get owner and group sid */ 3413 3414 if (sd->owner_sid) { 3415 convert_sid_to_string(ipc_cli, pol, 3416 sidstr, numeric, sd->owner_sid); 3417 } else { 3418 fstrcpy(sidstr, ""); 3419 } 3420 3421 if (all || all_nt) { 3422 if (determine_size) { 3423 p = talloc_asprintf(ctx, ",OWNER:%s", sidstr); 3424 if (!p) { 3425 errno = ENOMEM; 3426 return -1; 3427 } 3428 n = strlen(p); 3429 } else { 3430 n = snprintf(buf, bufsize, 3431 ",OWNER:%s", sidstr); 3432 } 3433 } else if (StrnCaseCmp(name, "owner", 5) == 0) { 3434 if (determine_size) { 3435 p = talloc_asprintf(ctx, "%s", sidstr); 3436 if (!p) { 3437 errno = ENOMEM; 3438 return -1; 3439 } 3440 n = strlen(p); 3441 } else { 3442 n = snprintf(buf, bufsize, "%s", sidstr); 3443 } 3444 } 3445 3446 if (!determine_size && n > bufsize) { 3447 errno = ERANGE; 3448 return -1; 3449 } 3450 buf += n; 3451 n_used += n; 3452 bufsize -= n; 3453 3454 if (sd->grp_sid) { 3455 convert_sid_to_string(ipc_cli, pol, 3456 sidstr, numeric, sd->grp_sid); 3457 } else { 3458 fstrcpy(sidstr, ""); 3459 } 3460 3461 if (all || all_nt) { 3462 if (determine_size) { 3463 p = talloc_asprintf(ctx, ",GROUP:%s", sidstr); 3464 if (!p) { 3465 errno = ENOMEM; 3466 return -1; 3467 } 3468 n = strlen(p); 3469 } else { 3470 n = snprintf(buf, bufsize, 3471 ",GROUP:%s", sidstr); 3472 } 3473 } else if (StrnCaseCmp(name, "group", 5) == 0) { 3474 if (determine_size) { 3475 p = talloc_asprintf(ctx, "%s", sidstr); 3476 if (!p) { 3477 errno = ENOMEM; 3478 return -1; 3479 } 3480 n = strlen(p); 3481 } else { 3482 n = snprintf(buf, bufsize, "%s", sidstr); 3483 } 3484 } 3485 3486 if (!determine_size && n > bufsize) { 3487 errno = ERANGE; 3488 return -1; 3489 } 3490 buf += n; 3491 n_used += n; 3492 bufsize -= n; 3493 3494 /* Add aces to value buffer */ 3495 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { 3496 3497 SEC_ACE *ace = &sd->dacl->ace[i]; 3498 convert_sid_to_string(ipc_cli, pol, 3499 sidstr, numeric, &ace->trustee); 3500 3501 if (all || all_nt) { 3502 if (determine_size) { 3503 p = talloc_asprintf(ctx, 3504 ",ACL:" 3505 "%s:%d/%d/0x%08x", 3506 sidstr, 3507 ace->type, 3508 ace->flags, 3509 ace->info.mask); 3510 if (!p) { 3511 errno = ENOMEM; 3512 return -1; 3513 } 3514 n = strlen(p); 3515 } else { 3516 n = snprintf(buf, bufsize, 3517 ",ACL:%s:%d/%d/0x%08x", 3518 sidstr, 3519 ace->type, 3520 ace->flags, 3521 ace->info.mask); 3522 } 3523 } else if ((StrnCaseCmp(name, "acl", 3) == 0 && 3524 StrCaseCmp(name + 3, sidstr) == 0) || 3525 (StrnCaseCmp(name, "acl+", 4) == 0 && 3526 StrCaseCmp(name + 4, sidstr) == 0)) { 3527 if (determine_size) { 3528 p = talloc_asprintf(ctx, 3529 "%d/%d/0x%08x", 3530 ace->type, 3531 ace->flags, 3532 ace->info.mask); 3533 if (!p) { 3534 errno = ENOMEM; 3535 return -1; 3536 } 3537 n = strlen(p); 3538 } else { 3539 n = snprintf(buf, bufsize, 3540 "%d/%d/0x%08x", 3541 ace->type, 3542 ace->flags, 3543 ace->info.mask); 3544 } 3545 } 3546 if (n > bufsize) { 3547 errno = ERANGE; 3548 return -1; 3549 } 3550 buf += n; 3551 n_used += n; 3552 bufsize -= n; 3553 } 3554 3555 /* Restore name pointer to its original value */ 3556 name -= 19; 3557 } 3558 3559 if (all || some_dos) { 3560 /* Point to the portion after "system.dos_attr." */ 3561 name += 16; /* if (all) this will be invalid but unused */ 3562 3563 /* Obtain the DOS attributes */ 3564 if (!smbc_getatr(context, srv, filename, &mode, &size, 3565 &c_time, &a_time, &m_time, &ino)) { 3566 3567 errno = smbc_errno(context, &srv->cli); 3568 return -1; 3569 3570 } 3571 3572 if (all || all_dos) { 3573 if (determine_size) { 3574 p = talloc_asprintf(ctx, 3575 "%sMODE:0x%x", 3576 (ipc_cli && 3577 (all || some_nt) 3578 ? "," 3579 : ""), 3580 mode); 3581 if (!p) { 3582 errno = ENOMEM; 3583 return -1; 3584 } 3585 n = strlen(p); 3586 } else { 3587 n = snprintf(buf, bufsize, 3588 "%sMODE:0x%x", 3589 (ipc_cli && 3590 (all || some_nt) 3591 ? "," 3592 : ""), 3593 mode); 3594 } 3595 } else if (StrCaseCmp(name, "mode") == 0) { 3596 if (determine_size) { 3597 p = talloc_asprintf(ctx, "0x%x", mode); 3598 if (!p) { 3599 errno = ENOMEM; 3600 return -1; 3601 } 3602 n = strlen(p); 3603 } else { 3604 n = snprintf(buf, bufsize, "0x%x", mode); 3605 } 3606 } 3607 3608 if (!determine_size && n > bufsize) { 3609 errno = ERANGE; 3610 return -1; 3611 } 3612 buf += n; 3613 n_used += n; 3614 bufsize -= n; 3615 3616 if (all || all_dos) { 3617 if (determine_size) { 3618 p = talloc_asprintf(ctx, 3619 ",SIZE:%llu", 3620 (unsigned long long) size); 3621 if (!p) { 3622 errno = ENOMEM; 3623 return -1; 3624 } 3625 n = strlen(p); 3626 } else { 3627 n = snprintf(buf, bufsize, 3628 ",SIZE:%llu", 3629 (unsigned long long) size); 3630 } 3631 } else if (StrCaseCmp(name, "size") == 0) { 3632 if (determine_size) { 3633 p = talloc_asprintf(ctx, 3634 "%llu", 3635 (unsigned long long) size); 3636 if (!p) { 3637 errno = ENOMEM; 3638 return -1; 3639 } 3640 n = strlen(p); 3641 } else { 3642 n = snprintf(buf, bufsize, 3643 "%llu", 3644 (unsigned long long) size); 3645 } 3646 } 3647 3648 if (!determine_size && n > bufsize) { 3649 errno = ERANGE; 3650 return -1; 3651 } 3652 buf += n; 3653 n_used += n; 3654 bufsize -= n; 3655 3656 if (all || all_dos) { 3657 if (determine_size) { 3658 p = talloc_asprintf(ctx, 3659 ",C_TIME:%lu", c_time); 3660 if (!p) { 3661 errno = ENOMEM; 3662 return -1; 3663 } 3664 n = strlen(p); 3665 } else { 3666 n = snprintf(buf, bufsize, 3667 ",C_TIME:%lu", c_time); 3668 } 3669 } else if (StrCaseCmp(name, "c_time") == 0) { 3670 if (determine_size) { 3671 p = talloc_asprintf(ctx, "%lu", c_time); 3672 if (!p) { 3673 errno = ENOMEM; 3674 return -1; 3675 } 3676 n = strlen(p); 3677 } else { 3678 n = snprintf(buf, bufsize, "%lu", c_time); 3679 } 3680 } 3681 3682 if (!determine_size && n > bufsize) { 3683 errno = ERANGE; 3684 return -1; 3685 } 3686 buf += n; 3687 n_used += n; 3688 bufsize -= n; 3689 3690 if (all || all_dos) { 3691 if (determine_size) { 3692 p = talloc_asprintf(ctx, 3693 ",A_TIME:%lu", a_time); 3694 if (!p) { 3695 errno = ENOMEM; 3696 return -1; 3697 } 3698 n = strlen(p); 3699 } else { 3700 n = snprintf(buf, bufsize, 3701 ",A_TIME:%lu", a_time); 3702 } 3703 } else if (StrCaseCmp(name, "a_time") == 0) { 3704 if (determine_size) { 3705 p = talloc_asprintf(ctx, "%lu", a_time); 3706 if (!p) { 3707 errno = ENOMEM; 3708 return -1; 3709 } 3710 n = strlen(p); 3711 } else { 3712 n = snprintf(buf, bufsize, "%lu", a_time); 3713 } 3714 } 3715 3716 if (!determine_size && n > bufsize) { 3717 errno = ERANGE; 3718 return -1; 3719 } 3720 buf += n; 3721 n_used += n; 3722 bufsize -= n; 3723 3724 if (all || all_dos) { 3725 if (determine_size) { 3726 p = talloc_asprintf(ctx, 3727 ",M_TIME:%lu", m_time); 3728 if (!p) { 3729 errno = ENOMEM; 3730 return -1; 3731 } 3732 n = strlen(p); 3733 } else { 3734 n = snprintf(buf, bufsize, 3735 ",M_TIME:%lu", m_time); 3736 } 3737 } else if (StrCaseCmp(name, "m_time") == 0) { 3738 if (determine_size) { 3739 p = talloc_asprintf(ctx, "%lu", m_time); 3740 if (!p) { 3741 errno = ENOMEM; 3742 return -1; 3743 } 3744 n = strlen(p); 3745 } else { 3746 n = snprintf(buf, bufsize, "%lu", m_time); 3747 } 3748 } 3749 3750 if (!determine_size && n > bufsize) { 3751 errno = ERANGE; 3752 return -1; 3753 } 3754 buf += n; 3755 n_used += n; 3756 bufsize -= n; 3757 3758 if (all || all_dos) { 3759 if (determine_size) { 3760 p = talloc_asprintf(ctx, 3761 ",INODE:%llu", 3762 (unsigned long long) ino); 3763 if (!p) { 3764 errno = ENOMEM; 3765 return -1; 3766 } 3767 n = strlen(p); 3768 } else { 3769 n = snprintf(buf, bufsize, 3770 ",INODE:%llu", 3771 (unsigned long long) ino); 3772 } 3773 } else if (StrCaseCmp(name, "inode") == 0) { 3774 if (determine_size) { 3775 p = talloc_asprintf(ctx, 3776 "%llu", 3777 (unsigned long long) ino); 3778 if (!p) { 3779 errno = ENOMEM; 3780 return -1; 3781 } 3782 n = strlen(p); 3783 } else { 3784 n = snprintf(buf, bufsize, 3785 "%llu", 3786 (unsigned long long) ino); 3787 } 3788 } 3789 3790 if (!determine_size && n > bufsize) { 3791 errno = ERANGE; 3792 return -1; 3793 } 3794 buf += n; 3795 n_used += n; 3796 bufsize -= n; 3797 3798 /* Restore name pointer to its original value */ 3799 name -= 16; 3800 } 3801 3802 if (n_used == 0) { 3803 errno = ENOATTR; 3804 return -1; 3805 } 3806 3807 return n_used; 3808} 3809 3810 3811/***************************************************** 3812set the ACLs on a file given an ascii description 3813*******************************************************/ 3814static int cacl_set(TALLOC_CTX *ctx, struct cli_state *cli, 3815 struct cli_state *ipc_cli, POLICY_HND *pol, 3816 const char *filename, const char *the_acl, 3817 int mode, int flags) 3818{ 3819 int fnum; 3820 int err = 0; 3821 SEC_DESC *sd = NULL, *old; 3822 SEC_ACL *dacl = NULL; 3823 DOM_SID *owner_sid = NULL; 3824 DOM_SID *grp_sid = NULL; 3825 uint32 i, j; 3826 size_t sd_size; 3827 int ret = 0; 3828 char *p; 3829 BOOL numeric = True; 3830 3831 /* the_acl will be null for REMOVE_ALL operations */ 3832 if (the_acl) { 3833 numeric = ((p = strchr(the_acl, ':')) != NULL && 3834 p > the_acl && 3835 p[-1] != '+'); 3836 3837 /* if this is to set the entire ACL... */ 3838 if (*the_acl == '*') { 3839 /* ... then increment past the first colon */ 3840 the_acl = p + 1; 3841 } 3842 3843 sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, the_acl); 3844 3845 if (!sd) { 3846 errno = EINVAL; 3847 return -1; 3848 } 3849 } 3850 3851 /* The desired access below is the only one I could find that works 3852 with NT4, W2KP and Samba */ 3853 3854 fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); 3855 3856 if (fnum == -1) { 3857 DEBUG(5, ("cacl_set failed to open %s: %s\n", 3858 filename, cli_errstr(cli))); 3859 errno = 0; 3860 return -1; 3861 } 3862 3863 old = cli_query_secdesc(cli, fnum, ctx); 3864 3865 if (!old) { 3866 DEBUG(5, ("cacl_set Failed to query old descriptor\n")); 3867 errno = 0; 3868 return -1; 3869 } 3870 3871 cli_close(cli, fnum); 3872 3873 switch (mode) { 3874 case SMBC_XATTR_MODE_REMOVE_ALL: 3875 old->dacl->num_aces = 0; 3876 SAFE_FREE(old->dacl->ace); 3877 SAFE_FREE(old->dacl); 3878 old->off_dacl = 0; 3879 dacl = old->dacl; 3880 break; 3881 3882 case SMBC_XATTR_MODE_REMOVE: 3883 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { 3884 BOOL found = False; 3885 3886 for (j=0;old->dacl && j<old->dacl->num_aces;j++) { 3887 if (sec_ace_equal(&sd->dacl->ace[i], 3888 &old->dacl->ace[j])) { 3889 uint32 k; 3890 for (k=j; k<old->dacl->num_aces-1;k++) { 3891 old->dacl->ace[k] = old->dacl->ace[k+1]; 3892 } 3893 old->dacl->num_aces--; 3894 if (old->dacl->num_aces == 0) { 3895 SAFE_FREE(old->dacl->ace); 3896 SAFE_FREE(old->dacl); 3897 old->off_dacl = 0; 3898 } 3899 found = True; 3900 dacl = old->dacl; 3901 break; 3902 } 3903 } 3904 3905 if (!found) { 3906 err = ENOATTR; 3907 ret = -1; 3908 goto failed; 3909 } 3910 } 3911 break; 3912 3913 case SMBC_XATTR_MODE_ADD: 3914 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { 3915 BOOL found = False; 3916 3917 for (j=0;old->dacl && j<old->dacl->num_aces;j++) { 3918 if (sid_equal(&sd->dacl->ace[i].trustee, 3919 &old->dacl->ace[j].trustee)) { 3920 if (!(flags & SMBC_XATTR_FLAG_CREATE)) { 3921 err = EEXIST; 3922 ret = -1; 3923 goto failed; 3924 } 3925 old->dacl->ace[j] = sd->dacl->ace[i]; 3926 ret = -1; 3927 found = True; 3928 } 3929 } 3930 3931 if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) { 3932 err = ENOATTR; 3933 ret = -1; 3934 goto failed; 3935 } 3936 3937 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { 3938 add_ace(&old->dacl, &sd->dacl->ace[i], ctx); 3939 } 3940 } 3941 dacl = old->dacl; 3942 break; 3943 3944 case SMBC_XATTR_MODE_SET: 3945 old = sd; 3946 owner_sid = old->owner_sid; 3947 grp_sid = old->grp_sid; 3948 dacl = old->dacl; 3949 break; 3950 3951 case SMBC_XATTR_MODE_CHOWN: 3952 owner_sid = sd->owner_sid; 3953 break; 3954 3955 case SMBC_XATTR_MODE_CHGRP: 3956 grp_sid = sd->grp_sid; 3957 break; 3958 } 3959 3960 /* Denied ACE entries must come before allowed ones */ 3961 sort_acl(old->dacl); 3962 3963 /* Create new security descriptor and set it */ 3964 sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, 3965 owner_sid, grp_sid, NULL, dacl, &sd_size); 3966 3967 fnum = cli_nt_create(cli, filename, 3968 WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS); 3969 3970 if (fnum == -1) { 3971 DEBUG(5, ("cacl_set failed to open %s: %s\n", 3972 filename, cli_errstr(cli))); 3973 errno = 0; 3974 return -1; 3975 } 3976 3977 if (!cli_set_secdesc(cli, fnum, sd)) { 3978 DEBUG(5, ("ERROR: secdesc set failed: %s\n", cli_errstr(cli))); 3979 ret = -1; 3980 } 3981 3982 /* Clean up */ 3983 3984 failed: 3985 cli_close(cli, fnum); 3986 3987 if (err != 0) { 3988 errno = err; 3989 } 3990 3991 return ret; 3992} 3993 3994 3995int smbc_setxattr_ctx(SMBCCTX *context, 3996 const char *fname, 3997 const char *name, 3998 const void *value, 3999 size_t size, 4000 int flags) 4001{ 4002 int ret; 4003 int ret2; 4004 SMBCSRV *srv; 4005 SMBCSRV *ipc_srv; 4006 fstring server, share, user, password, workgroup; 4007 pstring path; 4008 TALLOC_CTX *ctx; 4009 POLICY_HND pol; 4010 DOS_ATTR_DESC *dad; 4011 4012 if (!context || !context->internal || 4013 !context->internal->_initialized) { 4014 4015 errno = EINVAL; /* Best I can think of ... */ 4016 return -1; 4017 4018 } 4019 4020 if (!fname) { 4021 4022 errno = EINVAL; 4023 return -1; 4024 4025 } 4026 4027 DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n", fname, name, (int) size, (const char*)value)); 4028 4029 if (smbc_parse_path(context, fname, 4030 server, sizeof(server), 4031 share, sizeof(share), 4032 path, sizeof(path), 4033 user, sizeof(user), 4034 password, sizeof(password), 4035 NULL, 0)) { 4036 errno = EINVAL; 4037 return -1; 4038 } 4039 4040 if (user[0] == (char)0) fstrcpy(user, context->user); 4041 4042 fstrcpy(workgroup, context->workgroup); 4043 4044 srv = smbc_server(context, server, share, workgroup, user, password); 4045 if (!srv) { 4046 return -1; /* errno set by smbc_server */ 4047 } 4048 4049 if (! srv->no_nt_session) { 4050 ipc_srv = smbc_attr_server(context, server, share, 4051 workgroup, user, password, 4052 &pol); 4053 srv->no_nt_session = True; 4054 } else { 4055 ipc_srv = NULL; 4056 } 4057 4058 ctx = talloc_init("smbc_setxattr"); 4059 if (!ctx) { 4060 errno = ENOMEM; 4061 return -1; 4062 } 4063 4064 /* 4065 * Are they asking to set the entire set of known attributes? 4066 */ 4067 if (StrCaseCmp(name, "system.*") == 0 || 4068 StrCaseCmp(name, "system.*+") == 0) { 4069 /* Yup. */ 4070 char *namevalue = 4071 talloc_asprintf(ctx, "%s:%s", name+7, (const char *) value); 4072 if (! namevalue) { 4073 errno = ENOMEM; 4074 ret = -1; 4075 return -1; 4076 } 4077 4078 if (ipc_srv) { 4079 ret = cacl_set(ctx, &srv->cli, 4080 &ipc_srv->cli, &pol, path, 4081 namevalue, 4082 (*namevalue == '*' 4083 ? SMBC_XATTR_MODE_SET 4084 : SMBC_XATTR_MODE_ADD), 4085 flags); 4086 } else { 4087 ret = 0; 4088 } 4089 4090 /* get a DOS Attribute Descriptor with current attributes */ 4091 dad = dos_attr_query(context, ctx, path, srv); 4092 if (dad) { 4093 /* Overwrite old with new, using what was provided */ 4094 dos_attr_parse(context, dad, srv, namevalue); 4095 4096 /* Set the new DOS attributes */ 4097#if 0 /* not yet implemented */ 4098 if (! cli_setpathinfo(&srv->cli, path, 4099 dad->c_time, 4100 dad->a_time, 4101 dad->m_time, 4102 dad->mode)) { 4103 if (!cli_setatr(&srv->cli, path, 4104 dad->mode, dad->m_time)) { 4105 errno = smbc_errno(context, &srv->cli); 4106 } 4107 } 4108#else 4109 if (!cli_setatr(&srv->cli, path, 4110 dad->mode, dad->m_time)) { 4111 errno = smbc_errno(context, &srv->cli); 4112 } 4113#endif 4114 } 4115 4116 /* we only fail if both NT and DOS sets failed */ 4117 if (ret < 0 && ! dad) { 4118 ret = -1; /* in case dad was null */ 4119 } 4120 else { 4121 ret = 0; 4122 } 4123 4124 talloc_destroy(ctx); 4125 return ret; 4126 } 4127 4128 /* 4129 * Are they asking to set an access control element or to set 4130 * the entire access control list? 4131 */ 4132 if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || 4133 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || 4134 StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || 4135 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || 4136 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { 4137 4138 /* Yup. */ 4139 char *namevalue = 4140 talloc_asprintf(ctx, "%s:%s", name+19, (const char *) value); 4141 4142 if (! ipc_srv) { 4143 ret = -1; /* errno set by smbc_server() */ 4144 } 4145 else if (! namevalue) { 4146 errno = ENOMEM; 4147 ret = -1; 4148 } else { 4149 ret = cacl_set(ctx, &srv->cli, 4150 &ipc_srv->cli, &pol, path, 4151 namevalue, 4152 (*namevalue == '*' 4153 ? SMBC_XATTR_MODE_SET 4154 : SMBC_XATTR_MODE_ADD), 4155 flags); 4156 } 4157 talloc_destroy(ctx); 4158 return ret; 4159 } 4160 4161 /* 4162 * Are they asking to set the owner? 4163 */ 4164 if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || 4165 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) { 4166 4167 /* Yup. */ 4168 char *namevalue = 4169 talloc_asprintf(ctx, "%s:%s", name+19, (const char *) value); 4170 4171 if (! ipc_srv) { 4172 4173 ret = -1; /* errno set by smbc_server() */ 4174 } 4175 else if (! namevalue) { 4176 errno = ENOMEM; 4177 ret = -1; 4178 } else { 4179 ret = cacl_set(ctx, &srv->cli, 4180 &ipc_srv->cli, &pol, path, 4181 namevalue, SMBC_XATTR_MODE_CHOWN, 0); 4182 } 4183 talloc_destroy(ctx); 4184 return ret; 4185 } 4186 4187 /* 4188 * Are they asking to set the group? 4189 */ 4190 if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || 4191 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) { 4192 4193 /* Yup. */ 4194 char *namevalue = 4195 talloc_asprintf(ctx, "%s:%s", name+19, (const char *) value); 4196 4197 if (! ipc_srv) { 4198 /* errno set by smbc_server() */ 4199 ret = -1; 4200 } 4201 else if (! namevalue) { 4202 errno = ENOMEM; 4203 ret = -1; 4204 } else { 4205 ret = cacl_set(ctx, &srv->cli, 4206 &ipc_srv->cli, &pol, path, 4207 namevalue, SMBC_XATTR_MODE_CHOWN, 0); 4208 } 4209 talloc_destroy(ctx); 4210 return ret; 4211 } 4212 4213 /* 4214 * Are they asking to set a DOS attribute? 4215 */ 4216 if (StrCaseCmp(name, "system.dos_attr.*") == 0 || 4217 StrCaseCmp(name, "system.dos_attr.mode") == 0 || 4218 StrCaseCmp(name, "system.dos_attr.c_time") == 0 || 4219 StrCaseCmp(name, "system.dos_attr.a_time") == 0 || 4220 StrCaseCmp(name, "system.dos_attr.m_time") == 0) { 4221 4222 /* get a DOS Attribute Descriptor with current attributes */ 4223 dad = dos_attr_query(context, ctx, path, srv); 4224 if (dad) { 4225 char *namevalue = 4226 talloc_asprintf(ctx, "%s:%s", name+16, (const char *) value); 4227 if (! namevalue) { 4228 errno = ENOMEM; 4229 ret = -1; 4230 } else { 4231 /* Overwrite old with provided new params */ 4232 dos_attr_parse(context, dad, srv, namevalue); 4233 4234 /* Set the new DOS attributes */ 4235#if 0 /* not yet implemented */ 4236 ret2 = cli_setpathinfo(&srv->cli, path, 4237 dad->c_time, 4238 dad->a_time, 4239 dad->m_time, 4240 dad->mode); 4241 if (! ret2) { 4242 ret2 = cli_setatr(&srv->cli, path, 4243 dad->mode, 4244 dad->m_time); 4245 if (! ret2) { 4246 errno = smbc_errno(context, 4247 &srv->cli); 4248 } 4249 } 4250#else 4251 ret2 = cli_setatr(&srv->cli, path, 4252 dad->mode, dad->m_time); 4253 if (! ret2) { 4254 errno = smbc_errno(context, &srv->cli); 4255 } 4256#endif 4257 4258 /* ret2 has True (success) / False (failure) */ 4259 if (ret2) { 4260 ret = 0; 4261 } else { 4262 ret = -1; 4263 } 4264 } 4265 } else { 4266 ret = -1; 4267 } 4268 4269 talloc_destroy(ctx); 4270 return ret; 4271 } 4272 4273 /* Unsupported attribute name */ 4274 talloc_destroy(ctx); 4275 errno = EINVAL; 4276 return -1; 4277} 4278 4279int smbc_getxattr_ctx(SMBCCTX *context, 4280 const char *fname, 4281 const char *name, 4282 const void *value, 4283 size_t size) 4284{ 4285 int ret; 4286 SMBCSRV *srv; 4287 SMBCSRV *ipc_srv; 4288 fstring server, share, user, password, workgroup; 4289 pstring path; 4290 TALLOC_CTX *ctx; 4291 POLICY_HND pol; 4292 4293 4294 if (!context || !context->internal || 4295 !context->internal->_initialized) { 4296 4297 errno = EINVAL; /* Best I can think of ... */ 4298 return -1; 4299 4300 } 4301 4302 if (!fname) { 4303 4304 errno = EINVAL; 4305 return -1; 4306 4307 } 4308 4309 DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name)); 4310 4311 if (smbc_parse_path(context, fname, 4312 server, sizeof(server), 4313 share, sizeof(share), 4314 path, sizeof(path), 4315 user, sizeof(user), 4316 password, sizeof(password), 4317 NULL, 0)) { 4318 errno = EINVAL; 4319 return -1; 4320 } 4321 4322 if (user[0] == (char)0) fstrcpy(user, context->user); 4323 4324 fstrcpy(workgroup, context->workgroup); 4325 4326 srv = smbc_server(context, server, share, workgroup, user, password); 4327 if (!srv) { 4328 return -1; /* errno set by smbc_server */ 4329 } 4330 4331 if (! srv->no_nt_session) { 4332 ipc_srv = smbc_attr_server(context, server, share, 4333 workgroup, user, password, 4334 &pol); 4335 if (! ipc_srv) { 4336 srv->no_nt_session = True; 4337 } 4338 } else { 4339 ipc_srv = NULL; 4340 } 4341 4342 ctx = talloc_init("smbc:getxattr"); 4343 if (!ctx) { 4344 errno = ENOMEM; 4345 return -1; 4346 } 4347 4348 /* Are they requesting a supported attribute? */ 4349 if (StrCaseCmp(name, "system.*") == 0 || 4350 StrCaseCmp(name, "system.*+") == 0 || 4351 StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || 4352 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || 4353 StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || 4354 StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || 4355 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || 4356 StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || 4357 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || 4358 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || 4359 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 || 4360 StrCaseCmp(name, "system.dos_attr.*") == 0 || 4361 StrCaseCmp(name, "system.dos_attr.mode") == 0 || 4362 StrCaseCmp(name, "system.dos_attr.size") == 0 || 4363 StrCaseCmp(name, "system.dos_attr.c_time") == 0 || 4364 StrCaseCmp(name, "system.dos_attr.a_time") == 0 || 4365 StrCaseCmp(name, "system.dos_attr.m_time") == 0 || 4366 StrCaseCmp(name, "system.dos_attr.inode") == 0) { 4367 4368 /* Yup. */ 4369 ret = cacl_get(context, ctx, srv, 4370 ipc_srv == NULL ? NULL : &ipc_srv->cli, 4371 &pol, path, name, (const char *) value, size); 4372 if (ret < 0 && errno == 0) { 4373 errno = smbc_errno(context, &srv->cli); 4374 } 4375 talloc_destroy(ctx); 4376 return ret; 4377 } 4378 4379 /* Unsupported attribute name */ 4380 talloc_destroy(ctx); 4381 errno = EINVAL; 4382 return -1; 4383} 4384 4385 4386int smbc_removexattr_ctx(SMBCCTX *context, 4387 const char *fname, 4388 const char *name) 4389{ 4390 int ret; 4391 SMBCSRV *srv; 4392 SMBCSRV *ipc_srv; 4393 fstring server, share, user, password, workgroup; 4394 pstring path; 4395 TALLOC_CTX *ctx; 4396 POLICY_HND pol; 4397 4398 if (!context || !context->internal || 4399 !context->internal->_initialized) { 4400 4401 errno = EINVAL; /* Best I can think of ... */ 4402 return -1; 4403 4404 } 4405 4406 if (!fname) { 4407 4408 errno = EINVAL; 4409 return -1; 4410 4411 } 4412 4413 DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name)); 4414 4415 if (smbc_parse_path(context, fname, 4416 server, sizeof(server), 4417 share, sizeof(share), 4418 path, sizeof(path), 4419 user, sizeof(user), 4420 password, sizeof(password), 4421 NULL, 0)) { 4422 errno = EINVAL; 4423 return -1; 4424 } 4425 4426 if (user[0] == (char)0) fstrcpy(user, context->user); 4427 4428 fstrcpy(workgroup, context->workgroup); 4429 4430 srv = smbc_server(context, server, share, workgroup, user, password); 4431 if (!srv) { 4432 return -1; /* errno set by smbc_server */ 4433 } 4434 4435 if (! srv->no_nt_session) { 4436 ipc_srv = smbc_attr_server(context, server, share, 4437 workgroup, user, password, 4438 &pol); 4439 srv->no_nt_session = True; 4440 } else { 4441 ipc_srv = NULL; 4442 } 4443 4444 if (! ipc_srv) { 4445 return -1; /* errno set by smbc_attr_server */ 4446 } 4447 4448 ctx = talloc_init("smbc_removexattr"); 4449 if (!ctx) { 4450 errno = ENOMEM; 4451 return -1; 4452 } 4453 4454 /* Are they asking to set the entire ACL? */ 4455 if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || 4456 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) { 4457 4458 /* Yup. */ 4459 ret = cacl_set(ctx, &srv->cli, 4460 &ipc_srv->cli, &pol, path, 4461 NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0); 4462 talloc_destroy(ctx); 4463 return ret; 4464 } 4465 4466 /* 4467 * Are they asking to remove one or more spceific security descriptor 4468 * attributes? 4469 */ 4470 if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || 4471 StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || 4472 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || 4473 StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || 4474 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || 4475 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || 4476 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { 4477 4478 /* Yup. */ 4479 ret = cacl_set(ctx, &srv->cli, 4480 &ipc_srv->cli, &pol, path, 4481 name + 19, SMBC_XATTR_MODE_REMOVE, 0); 4482 talloc_destroy(ctx); 4483 return ret; 4484 } 4485 4486 /* Unsupported attribute name */ 4487 talloc_destroy(ctx); 4488 errno = EINVAL; 4489 return -1; 4490} 4491 4492int smbc_listxattr_ctx(SMBCCTX *context, 4493 const char *fname, 4494 char *list, 4495 size_t size) 4496{ 4497 /* 4498 * This isn't quite what listxattr() is supposed to do. This returns 4499 * the complete set of attribute names, always, rather than only those 4500 * attribute names which actually exist for a file. Hmmm... 4501 */ 4502 const char supported[] = 4503 "system.*\0" 4504 "system.*+\0" 4505 "system.nt_sec_desc.revision\0" 4506 "system.nt_sec_desc.owner\0" 4507 "system.nt_sec_desc.owner+\0" 4508 "system.nt_sec_desc.group\0" 4509 "system.nt_sec_desc.group+\0" 4510 "system.nt_sec_desc.acl\0" 4511 "system.nt_sec_desc.acl+\0" 4512 "system.nt_sec_desc.*\0" 4513 "system.nt_sec_desc.*+\0" 4514 "system.dos_attr.*\0" 4515 "system.dos_attr.mode\0" 4516 "system.dos_attr.c_time\0" 4517 "system.dos_attr.a_time\0" 4518 "system.dos_attr.m_time\0" 4519 ; 4520 4521 if (size == 0) { 4522 return sizeof(supported); 4523 } 4524 4525 if (sizeof(supported) > size) { 4526 errno = ERANGE; 4527 return -1; 4528 } 4529 4530 /* this can't be strcpy() because there are embedded null characters */ 4531 memcpy(list, supported, sizeof(supported)); 4532 return sizeof(supported); 4533} 4534 4535 4536/* 4537 * Open a print file to be written to by other calls 4538 */ 4539 4540static SMBCFILE *smbc_open_print_job_ctx(SMBCCTX *context, const char *fname) 4541{ 4542 fstring server, share, user, password; 4543 pstring path; 4544 4545 if (!context || !context->internal || 4546 !context->internal->_initialized) { 4547 4548 errno = EINVAL; 4549 return NULL; 4550 4551 } 4552 4553 if (!fname) { 4554 4555 errno = EINVAL; 4556 return NULL; 4557 4558 } 4559 4560 DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname)); 4561 4562 if (smbc_parse_path(context, fname, 4563 server, sizeof(server), 4564 share, sizeof(share), 4565 path, sizeof(path), 4566 user, sizeof(user), 4567 password, sizeof(password), 4568 NULL, 0)) { 4569 errno = EINVAL; 4570 return NULL; 4571 } 4572 4573 /* What if the path is empty, or the file exists? */ 4574 4575 return context->open(context, fname, O_WRONLY, 666); 4576 4577} 4578 4579/* 4580 * Routine to print a file on a remote server ... 4581 * 4582 * We open the file, which we assume to be on a remote server, and then 4583 * copy it to a print file on the share specified by printq. 4584 */ 4585 4586static int smbc_print_file_ctx(SMBCCTX *c_file, const char *fname, SMBCCTX *c_print, const char *printq) 4587{ 4588 SMBCFILE *fid1, *fid2; 4589 int bytes, saverr, tot_bytes = 0; 4590 char buf[4096]; 4591 4592 if (!c_file || !c_file->internal->_initialized || !c_print || 4593 !c_print->internal->_initialized) { 4594 4595 errno = EINVAL; 4596 return -1; 4597 4598 } 4599 4600 if (!fname && !printq) { 4601 4602 errno = EINVAL; 4603 return -1; 4604 4605 } 4606 4607 /* Try to open the file for reading ... */ 4608 4609 if ((int)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) { 4610 4611 DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno)); 4612 return -1; /* smbc_open sets errno */ 4613 4614 } 4615 4616 /* Now, try to open the printer file for writing */ 4617 4618 if ((int)(fid2 = c_print->open_print_job(c_print, printq)) < 0) { 4619 4620 saverr = errno; /* Save errno */ 4621 c_file->close(c_file, fid1); 4622 errno = saverr; 4623 return -1; 4624 4625 } 4626 4627 while ((bytes = c_file->read(c_file, fid1, buf, sizeof(buf))) > 0) { 4628 4629 tot_bytes += bytes; 4630 4631 if ((c_print->write(c_print, fid2, buf, bytes)) < 0) { 4632 4633 saverr = errno; 4634 c_file->close(c_file, fid1); 4635 c_print->close(c_print, fid2); 4636 errno = saverr; 4637 4638 } 4639 4640 } 4641 4642 saverr = errno; 4643 4644 c_file->close(c_file, fid1); /* We have to close these anyway */ 4645 c_print->close(c_print, fid2); 4646 4647 if (bytes < 0) { 4648 4649 errno = saverr; 4650 return -1; 4651 4652 } 4653 4654 return tot_bytes; 4655 4656} 4657 4658/* 4659 * Routine to list print jobs on a printer share ... 4660 */ 4661 4662static int smbc_list_print_jobs_ctx(SMBCCTX *context, const char *fname, smbc_list_print_job_fn fn) 4663{ 4664 SMBCSRV *srv; 4665 fstring server, share, user, password, workgroup; 4666 pstring path; 4667 4668 if (!context || !context->internal || 4669 !context->internal->_initialized) { 4670 4671 errno = EINVAL; 4672 return -1; 4673 4674 } 4675 4676 if (!fname) { 4677 4678 errno = EINVAL; 4679 return -1; 4680 4681 } 4682 4683 DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname)); 4684 4685 if (smbc_parse_path(context, fname, 4686 server, sizeof(server), 4687 share, sizeof(share), 4688 path, sizeof(path), 4689 user, sizeof(user), 4690 password, sizeof(password), 4691 NULL, 0)) { 4692 errno = EINVAL; 4693 return -1; 4694 } 4695 4696 if (user[0] == (char)0) fstrcpy(user, context->user); 4697 4698 fstrcpy(workgroup, context->workgroup); 4699 4700 srv = smbc_server(context, server, share, workgroup, user, password); 4701 4702 if (!srv) { 4703 4704 return -1; /* errno set by smbc_server */ 4705 4706 } 4707 4708 if (cli_print_queue(&srv->cli, (void (*)(struct print_job_info *))fn) < 0) { 4709 4710 errno = smbc_errno(context, &srv->cli); 4711 return -1; 4712 4713 } 4714 4715 return 0; 4716 4717} 4718 4719/* 4720 * Delete a print job from a remote printer share 4721 */ 4722 4723static int smbc_unlink_print_job_ctx(SMBCCTX *context, const char *fname, int id) 4724{ 4725 SMBCSRV *srv; 4726 fstring server, share, user, password, workgroup; 4727 pstring path; 4728 int err; 4729 4730 if (!context || !context->internal || 4731 !context->internal->_initialized) { 4732 4733 errno = EINVAL; 4734 return -1; 4735 4736 } 4737 4738 if (!fname) { 4739 4740 errno = EINVAL; 4741 return -1; 4742 4743 } 4744 4745 DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname)); 4746 4747 if (smbc_parse_path(context, fname, 4748 server, sizeof(server), 4749 share, sizeof(share), 4750 path, sizeof(path), 4751 user, sizeof(user), 4752 password, sizeof(password), 4753 NULL, 0)) { 4754 errno = EINVAL; 4755 return -1; 4756 } 4757 4758 if (user[0] == (char)0) fstrcpy(user, context->user); 4759 4760 fstrcpy(workgroup, context->workgroup); 4761 4762 srv = smbc_server(context, server, share, workgroup, user, password); 4763 4764 if (!srv) { 4765 4766 return -1; /* errno set by smbc_server */ 4767 4768 } 4769 4770 if ((err = cli_printjob_del(&srv->cli, id)) != 0) { 4771 4772 if (err < 0) 4773 errno = smbc_errno(context, &srv->cli); 4774 else if (err == ERRnosuchprintjob) 4775 errno = EINVAL; 4776 return -1; 4777 4778 } 4779 4780 return 0; 4781 4782} 4783 4784/* 4785 * Get a new empty handle to fill in with your own info 4786 */ 4787SMBCCTX * smbc_new_context(void) 4788{ 4789 SMBCCTX * context; 4790 4791 context = SMB_MALLOC_P(SMBCCTX); 4792 if (!context) { 4793 errno = ENOMEM; 4794 return NULL; 4795 } 4796 4797 ZERO_STRUCTP(context); 4798 4799 context->internal = SMB_MALLOC_P(struct smbc_internal_data); 4800 if (!context->internal) { 4801 errno = ENOMEM; 4802 return NULL; 4803 } 4804 4805 ZERO_STRUCTP(context->internal); 4806 4807 4808 /* ADD REASONABLE DEFAULTS */ 4809 context->debug = 0; 4810 context->timeout = 20000; /* 20 seconds */ 4811 4812 context->options.browse_max_lmb_count = 3; /* # LMBs to query */ 4813 context->options.urlencode_readdir_entries = False;/* backward compat */ 4814 context->options.one_share_per_server = False;/* backward compat */ 4815 4816 context->open = smbc_open_ctx; 4817 context->creat = smbc_creat_ctx; 4818 context->read = smbc_read_ctx; 4819 context->write = smbc_write_ctx; 4820 context->close = smbc_close_ctx; 4821 context->unlink = smbc_unlink_ctx; 4822 context->rename = smbc_rename_ctx; 4823 context->lseek = smbc_lseek_ctx; 4824 context->stat = smbc_stat_ctx; 4825 context->fstat = smbc_fstat_ctx; 4826 context->opendir = smbc_opendir_ctx; 4827 context->closedir = smbc_closedir_ctx; 4828 context->readdir = smbc_readdir_ctx; 4829 context->getdents = smbc_getdents_ctx; 4830 context->mkdir = smbc_mkdir_ctx; 4831 context->rmdir = smbc_rmdir_ctx; 4832 context->telldir = smbc_telldir_ctx; 4833 context->lseekdir = smbc_lseekdir_ctx; 4834 context->fstatdir = smbc_fstatdir_ctx; 4835 context->chmod = smbc_chmod_ctx; 4836 context->utimes = smbc_utimes_ctx; 4837 context->setxattr = smbc_setxattr_ctx; 4838 context->getxattr = smbc_getxattr_ctx; 4839 context->removexattr = smbc_removexattr_ctx; 4840 context->listxattr = smbc_listxattr_ctx; 4841 context->open_print_job = smbc_open_print_job_ctx; 4842 context->print_file = smbc_print_file_ctx; 4843 context->list_print_jobs = smbc_list_print_jobs_ctx; 4844 context->unlink_print_job = smbc_unlink_print_job_ctx; 4845 4846 context->callbacks.check_server_fn = smbc_check_server; 4847 context->callbacks.remove_unused_server_fn = smbc_remove_unused_server; 4848 4849 smbc_default_cache_functions(context); 4850 4851 return context; 4852} 4853 4854/* 4855 * Free a context 4856 * 4857 * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed 4858 * and thus you'll be leaking memory if not handled properly. 4859 * 4860 */ 4861int smbc_free_context(SMBCCTX * context, int shutdown_ctx) 4862{ 4863 if (!context) { 4864 errno = EBADF; 4865 return 1; 4866 } 4867 4868 if (shutdown_ctx) { 4869 SMBCFILE * f; 4870 DEBUG(1,("Performing aggressive shutdown.\n")); 4871 4872 f = context->internal->_files; 4873 while (f) { 4874 context->close(context, f); 4875 f = f->next; 4876 } 4877 context->internal->_files = NULL; 4878 4879 /* First try to remove the servers the nice way. */ 4880 if (context->callbacks.purge_cached_fn(context)) { 4881 SMBCSRV * s; 4882 SMBCSRV * next; 4883 DEBUG(1, ("Could not purge all servers, Nice way shutdown failed.\n")); 4884 s = context->internal->_servers; 4885 while (s) { 4886 DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", s, s->cli.fd)); 4887 cli_shutdown(&s->cli); 4888 context->callbacks.remove_cached_srv_fn(context, s); 4889 next = s->next; 4890 DLIST_REMOVE(context->internal->_servers, s); 4891 SAFE_FREE(s); 4892 s = next; 4893 } 4894 context->internal->_servers = NULL; 4895 } 4896 } 4897 else { 4898 /* This is the polite way */ 4899 if (context->callbacks.purge_cached_fn(context)) { 4900 DEBUG(1, ("Could not purge all servers, free_context failed.\n")); 4901 errno = EBUSY; 4902 return 1; 4903 } 4904 if (context->internal->_servers) { 4905 DEBUG(1, ("Active servers in context, free_context failed.\n")); 4906 errno = EBUSY; 4907 return 1; 4908 } 4909 if (context->internal->_files) { 4910 DEBUG(1, ("Active files in context, free_context failed.\n")); 4911 errno = EBUSY; 4912 return 1; 4913 } 4914 } 4915 4916 /* Things we have to clean up */ 4917 SAFE_FREE(context->workgroup); 4918 SAFE_FREE(context->netbios_name); 4919 SAFE_FREE(context->user); 4920 4921 DEBUG(3, ("Context %p succesfully freed\n", context)); 4922 SAFE_FREE(context->internal); 4923 SAFE_FREE(context); 4924 return 0; 4925} 4926 4927 4928/* 4929 * Initialise the library etc 4930 * 4931 * We accept a struct containing handle information. 4932 * valid values for info->debug from 0 to 100, 4933 * and insist that info->fn must be non-null. 4934 */ 4935SMBCCTX * smbc_init_context(SMBCCTX * context) 4936{ 4937 pstring conf; 4938 int pid; 4939 char *user = NULL, *home = NULL; 4940 4941 if (!context || !context->internal) { 4942 errno = EBADF; 4943 return NULL; 4944 } 4945 4946 /* Do not initialise the same client twice */ 4947 if (context->internal->_initialized) { 4948 return 0; 4949 } 4950 4951 if (!context->callbacks.auth_fn || context->debug < 0 || context->debug > 100) { 4952 4953 errno = EINVAL; 4954 return NULL; 4955 4956 } 4957 4958 if (!smbc_initialized) { 4959 /* Do some library wide intialisations the first time we get called */ 4960 4961 /* Set this to what the user wants */ 4962 DEBUGLEVEL = context->debug; 4963 4964 setup_logging( "libsmbclient", True); 4965 4966 /* Here we would open the smb.conf file if needed ... */ 4967 4968 home = getenv("HOME"); 4969 4970 slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home); 4971 4972 load_interfaces(); /* Load the list of interfaces ... */ 4973 4974 in_client = True; /* FIXME, make a param */ 4975 4976 if (!lp_load(conf, True, False, False)) { 4977 4978 /* 4979 * Well, if that failed, try the dyn_CONFIGFILE 4980 * Which points to the standard locn, and if that 4981 * fails, silently ignore it and use the internal 4982 * defaults ... 4983 */ 4984 4985 if (!lp_load(dyn_CONFIGFILE, True, False, False)) { 4986 DEBUG(5, ("Could not load either config file: %s or %s\n", 4987 conf, dyn_CONFIGFILE)); 4988 } 4989 } 4990 4991 reopen_logs(); /* Get logging working ... */ 4992 4993 /* 4994 * Block SIGPIPE (from lib/util_sock.c: write()) 4995 * It is not needed and should not stop execution 4996 */ 4997 BlockSignals(True, SIGPIPE); 4998 4999 /* Done with one-time initialisation */ 5000 smbc_initialized = 1; 5001 5002 } 5003 5004 if (!context->user) { 5005 /* 5006 * FIXME: Is this the best way to get the user info? 5007 */ 5008 user = getenv("USER"); 5009 /* walk around as "guest" if no username can be found */ 5010 if (!user) context->user = SMB_STRDUP("guest"); 5011 else context->user = SMB_STRDUP(user); 5012 } 5013 5014 if (!context->netbios_name) { 5015 /* 5016 * We try to get our netbios name from the config. If that fails we fall 5017 * back on constructing our netbios name from our hostname etc 5018 */ 5019 if (global_myname()) { 5020 context->netbios_name = SMB_STRDUP(global_myname()); 5021 } 5022 else { 5023 /* 5024 * Hmmm, I want to get hostname as well, but I am too lazy for the moment 5025 */ 5026 pid = sys_getpid(); 5027 context->netbios_name = SMB_MALLOC(17); 5028 if (!context->netbios_name) { 5029 errno = ENOMEM; 5030 return NULL; 5031 } 5032 slprintf(context->netbios_name, 16, "smbc%s%d", context->user, pid); 5033 } 5034 } 5035 5036 DEBUG(1, ("Using netbios name %s.\n", context->netbios_name)); 5037 5038 if (!context->workgroup) { 5039 if (lp_workgroup()) { 5040 context->workgroup = SMB_STRDUP(lp_workgroup()); 5041 } 5042 else { 5043 /* TODO: Think about a decent default workgroup */ 5044 context->workgroup = SMB_STRDUP("samba"); 5045 } 5046 } 5047 5048 DEBUG(1, ("Using workgroup %s.\n", context->workgroup)); 5049 5050 /* shortest timeout is 1 second */ 5051 if (context->timeout > 0 && context->timeout < 1000) 5052 context->timeout = 1000; 5053 5054 /* 5055 * FIXME: Should we check the function pointers here? 5056 */ 5057 5058 context->internal->_initialized = 1; 5059 5060 return context; 5061} 5062 5063 5064/* Return the verion of samba, and thus libsmbclient */ 5065const char * 5066smbc_version(void) 5067{ 5068 return samba_version_string(); 5069} 5070