1/* 2 Unix SMB/Netbios implementation. 3 Version 2.0 4 SMB wrapper functions 5 Copyright (C) Andrew Tridgell 1998 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22#include "includes.h" 23#include "realcalls.h" 24 25pstring smbw_cwd; 26 27static struct smbw_file *smbw_files; 28static struct smbw_server *smbw_srvs; 29 30struct bitmap *smbw_file_bmap; 31extern pstring global_myname; 32extern int DEBUGLEVEL; 33 34fstring smbw_prefix = SMBW_PREFIX; 35 36int smbw_busy=0; 37 38/* needs to be here because of dumb include files on some systems */ 39int creat_bits = O_WRONLY|O_CREAT|O_TRUNC; 40 41 42/***************************************************** 43initialise structures 44*******************************************************/ 45void smbw_init(void) 46{ 47 extern BOOL in_client; 48 static int initialised; 49 static pstring servicesf = CONFIGFILE; 50 extern FILE *dbf; 51 char *p; 52 int eno; 53 pstring line; 54 55 if (initialised) return; 56 initialised = 1; 57 58 eno = errno; 59 60 smbw_busy++; 61 62 DEBUGLEVEL = 0; 63 setup_logging("smbsh",True); 64 65 dbf = stderr; 66 67 if ((p=smbw_getshared("LOGFILE"))) { 68 dbf = sys_fopen(p, "a"); 69 } 70 71 smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN); 72 if (!smbw_file_bmap) { 73 exit(1); 74 } 75 76 charset_initialise(); 77 78 in_client = True; 79 80 load_interfaces(); 81 82 lp_load(servicesf,True,False,False); 83 84 get_myname(global_myname); 85 86 if ((p=smbw_getshared("DEBUG"))) { 87 DEBUGLEVEL = atoi(p); 88 } 89 90 if ((p=smbw_getshared("RESOLVE_ORDER"))) { 91 lp_set_name_resolve_order(p); 92 } 93 94 if ((p=smbw_getshared("PREFIX"))) { 95 slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p); 96 all_string_sub(smbw_prefix,"//", "/", 0); 97 DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix)); 98 } 99 100 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid()); 101 102 p = smbw_getshared(line); 103 if (!p) { 104 sys_getwd(smbw_cwd); 105 } 106 pstrcpy(smbw_cwd, p); 107 DEBUG(4,("Initial cwd is %s\n", smbw_cwd)); 108 109 smbw_busy--; 110 111 set_maxfiles(SMBW_MAX_OPEN); 112 113 BlockSignals(True,SIGPIPE); 114 115 errno = eno; 116} 117 118/***************************************************** 119determine if a file descriptor is a smb one 120*******************************************************/ 121int smbw_fd(int fd) 122{ 123 if (smbw_busy) return 0; 124 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd); 125} 126 127/***************************************************** 128determine if a file descriptor is an internal smbw fd 129*******************************************************/ 130int smbw_local_fd(int fd) 131{ 132 struct smbw_server *srv; 133 134 smbw_init(); 135 136 if (smbw_busy) return 0; 137 if (smbw_shared_fd(fd)) return 1; 138 139 for (srv=smbw_srvs;srv;srv=srv->next) { 140 if (srv->cli.fd == fd) return 1; 141 } 142 143 return 0; 144} 145 146/***************************************************** 147a crude inode number generator 148*******************************************************/ 149ino_t smbw_inode(const char *name) 150{ 151 if (!*name) return 2; 152 return (ino_t)str_checksum(name); 153} 154 155/***************************************************** 156remove redundent stuff from a filename 157*******************************************************/ 158void clean_fname(char *name) 159{ 160 char *p, *p2; 161 int l; 162 int modified = 1; 163 164 if (!name) return; 165 166 while (modified) { 167 modified = 0; 168 169 DEBUG(5,("cleaning %s\n", name)); 170 171 if ((p=strstr(name,"/./"))) { 172 modified = 1; 173 while (*p) { 174 p[0] = p[2]; 175 p++; 176 } 177 } 178 179 if ((p=strstr(name,"//"))) { 180 modified = 1; 181 while (*p) { 182 p[0] = p[1]; 183 p++; 184 } 185 } 186 187 if (strcmp(name,"/../")==0) { 188 modified = 1; 189 name[1] = 0; 190 } 191 192 if ((p=strstr(name,"/../"))) { 193 modified = 1; 194 for (p2=(p>name?p-1:p);p2>name;p2--) { 195 if (p2[0] == '/') break; 196 } 197 while (*p2) { 198 p2[0] = p2[3]; 199 p2++; 200 } 201 } 202 203 if (strcmp(name,"/..")==0) { 204 modified = 1; 205 name[1] = 0; 206 } 207 208 l = strlen(name); 209 p = l>=3?(name+l-3):name; 210 if (strcmp(p,"/..")==0) { 211 modified = 1; 212 for (p2=p-1;p2>name;p2--) { 213 if (p2[0] == '/') break; 214 } 215 if (p2==name) { 216 p[0] = '/'; 217 p[1] = 0; 218 } else { 219 p2[0] = 0; 220 } 221 } 222 223 l = strlen(name); 224 p = l>=2?(name+l-2):name; 225 if (strcmp(p,"/.")==0) { 226 if (p == name) { 227 p[1] = 0; 228 } else { 229 p[0] = 0; 230 } 231 } 232 233 if (strncmp(p=name,"./",2) == 0) { 234 modified = 1; 235 do { 236 p[0] = p[2]; 237 } while (*p++); 238 } 239 240 l = strlen(p=name); 241 if (l > 1 && p[l-1] == '/') { 242 modified = 1; 243 p[l-1] = 0; 244 } 245 } 246} 247 248 249/***************************************************** 250parse a smb path into its components. 251*******************************************************/ 252char *smbw_parse_path(const char *fname, char *server, char *share, char *path) 253{ 254 static pstring s; 255 char *p, *p2; 256 int len = strlen(smbw_prefix)-1; 257 258 *server = *share = *path = 0; 259 260 if (fname[0] == '/') { 261 pstrcpy(s, fname); 262 } else { 263 slprintf(s,sizeof(s)-1, "%s/%s", smbw_cwd, fname); 264 } 265 clean_fname(s); 266 267 DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n", 268 s, fname, smbw_cwd)); 269 270 if (strncmp(s,smbw_prefix,len) || 271 (s[len] != '/' && s[len] != 0)) return s; 272 273 p = s + len; 274 if (*p == '/') p++; 275 276 p2 = strchr(p,'/'); 277 278 if (p2) { 279 len = (int)(p2-p); 280 } else { 281 len = strlen(p); 282 } 283 284 len = MIN(len,sizeof(fstring)-1); 285 286 strncpy(server, p, len); 287 server[len] = 0; 288 289 p = p2; 290 if (!p) { 291 if (len == 0) { 292 char *workgroup = smbw_getshared("WORKGROUP"); 293 if (!workgroup) workgroup = lp_workgroup(); 294 slprintf(server,sizeof(fstring)-1, "%s#1D", workgroup); 295 } 296 fstrcpy(share,"IPC$"); 297 pstrcpy(path,""); 298 goto ok; 299 } 300 301 p++; 302 p2 = strchr(p,'/'); 303 304 if (p2) { 305 len = (int)(p2-p); 306 } else { 307 len = strlen(p); 308 } 309 310 len = MIN(len,sizeof(fstring)-1); 311 312 strncpy(share, p, len); 313 share[len] = 0; 314 315 p = p2; 316 if (!p) { 317 pstrcpy(path,"\\"); 318 goto ok; 319 } 320 321 pstrcpy(path,p); 322 323 all_string_sub(path, "/", "\\", 0); 324 325 ok: 326 DEBUG(4,("parsed path name=%s cwd=%s [%s] [%s] [%s]\n", 327 fname, smbw_cwd, 328 server, share, path)); 329 330 return s; 331} 332 333/***************************************************** 334determine if a path name (possibly relative) is in the 335smb name space 336*******************************************************/ 337int smbw_path(const char *path) 338{ 339 fstring server, share; 340 pstring s; 341 char *cwd; 342 int len; 343 344 if(!path) 345 return 0; 346 347 /* this is needed to prevent recursion with the BSD malloc which 348 opens /etc/malloc.conf on the first call */ 349 if (strncmp(path,"/etc/", 5) == 0) { 350 return 0; 351 } 352 353 smbw_init(); 354 355 len = strlen(smbw_prefix)-1; 356 357 if (path[0] == '/' && strncmp(path,smbw_prefix,len)) { 358 return 0; 359 } 360 361 if (smbw_busy) return 0; 362 363 DEBUG(3,("smbw_path(%s)\n", path)); 364 365 cwd = smbw_parse_path(path, server, share, s); 366 367 if (strncmp(cwd,smbw_prefix,len) == 0 && 368 (cwd[len] == '/' || cwd[len] == 0)) { 369 return 1; 370 } 371 372 return 0; 373} 374 375/***************************************************** 376return a unix errno from a SMB error pair 377*******************************************************/ 378int smbw_errno(struct cli_state *c) 379{ 380 uint8 eclass; 381 uint32 ecode; 382 int ret; 383 384 ret = cli_error(c, &eclass, &ecode, NULL); 385 386 if (ret) { 387 DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n", 388 (int)eclass, (int)ecode, (int)ecode, ret)); 389 } 390 return ret; 391} 392 393/***************************************************** 394return a connection to a server (existing or new) 395*******************************************************/ 396struct smbw_server *smbw_server(char *server, char *share) 397{ 398 struct smbw_server *srv=NULL; 399 struct cli_state c; 400 char *username; 401 char *password; 402 char *workgroup; 403 struct nmb_name called, calling; 404 char *p, *server_n = server; 405 fstring group; 406 pstring ipenv; 407 struct in_addr ip; 408 extern struct in_addr ipzero; 409 410 ip = ipzero; 411 ZERO_STRUCT(c); 412 413 username = smbw_getshared("USER"); 414 if (!username) username = getenv("USER"); 415 if (!username) username = "guest"; 416 417 workgroup = smbw_getshared("WORKGROUP"); 418 if (!workgroup) workgroup = lp_workgroup(); 419 420 password = smbw_getshared("PASSWORD"); 421 if (!password) password = ""; 422 423 /* try to use an existing connection */ 424 for (srv=smbw_srvs;srv;srv=srv->next) { 425 if (strcmp(server,srv->server_name)==0 && 426 strcmp(share,srv->share_name)==0) return srv; 427 } 428 429 if (server[0] == 0) { 430 errno = EPERM; 431 return NULL; 432 } 433 434 make_nmb_name(&calling, global_myname, 0x0); 435 make_nmb_name(&called , server, 0x20); 436 437 DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server)); 438 439 if ((p=strchr(server_n,'#')) && strcmp(p+1,"1D")==0) { 440 struct in_addr sip; 441 pstring s; 442 443 fstrcpy(group, server_n); 444 p = strchr(group,'#'); 445 *p = 0; 446 447 /* cache the workgroup master lookup */ 448 slprintf(s,sizeof(s)-1,"MASTER_%s", group); 449 if (!(server_n = smbw_getshared(s))) { 450 if (!find_master_ip(group, &sip)) { 451 errno = ENOENT; 452 return NULL; 453 } 454 fstrcpy(group, inet_ntoa(sip)); 455 server_n = group; 456 smbw_setshared(s,server_n); 457 } 458 } 459 460 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); 461 462 again: 463 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); 464 465 ip = ipzero; 466 if ((p=smbw_getshared(ipenv))) { 467 ip = *(interpret_addr2(p)); 468 } 469 470 /* have to open a new connection */ 471 if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) { 472 errno = ENOENT; 473 return NULL; 474 } 475 476 if (!cli_session_request(&c, &calling, &called)) { 477 cli_shutdown(&c); 478 if (strcmp(called.name, "*SMBSERVER")) { 479 make_nmb_name(&called , "*SMBSERVER", 0x20); 480 goto again; 481 } 482 errno = ENOENT; 483 return NULL; 484 } 485 486 DEBUG(4,(" session request ok\n")); 487 488 if (!cli_negprot(&c)) { 489 cli_shutdown(&c); 490 errno = ENOENT; 491 return NULL; 492 } 493 494 if (!cli_session_setup(&c, username, 495 password, strlen(password), 496 password, strlen(password), 497 workgroup) && 498 /* try an anonymous login if it failed */ 499 !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) { 500 cli_shutdown(&c); 501 errno = EPERM; 502 return NULL; 503 } 504 505 DEBUG(4,(" session setup ok\n")); 506 507 if (!cli_send_tconX(&c, share, "?????", 508 password, strlen(password)+1)) { 509 errno = smbw_errno(&c); 510 cli_shutdown(&c); 511 return NULL; 512 } 513 514 smbw_setshared(ipenv,inet_ntoa(ip)); 515 516 DEBUG(4,(" tconx ok\n")); 517 518 srv = (struct smbw_server *)malloc(sizeof(*srv)); 519 if (!srv) { 520 errno = ENOMEM; 521 goto failed; 522 } 523 524 ZERO_STRUCTP(srv); 525 526 srv->cli = c; 527 528 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); 529 530 srv->server_name = strdup(server); 531 if (!srv->server_name) { 532 errno = ENOMEM; 533 goto failed; 534 } 535 536 srv->share_name = strdup(share); 537 if (!srv->share_name) { 538 errno = ENOMEM; 539 goto failed; 540 } 541 542 /* some programs play with file descriptors fairly intimately. We 543 try to get out of the way by duping to a high fd number */ 544 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) { 545 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == 546 srv->cli.fd+SMBW_CLI_FD) { 547 close(srv->cli.fd); 548 srv->cli.fd += SMBW_CLI_FD; 549 } 550 } 551 552 DLIST_ADD(smbw_srvs, srv); 553 554 return srv; 555 556 failed: 557 cli_shutdown(&c); 558 if (!srv) return NULL; 559 560 if (srv->server_name) free(srv->server_name); 561 if (srv->share_name) free(srv->share_name); 562 free(srv); 563 return NULL; 564} 565 566 567/***************************************************** 568map a fd to a smbw_file structure 569*******************************************************/ 570struct smbw_file *smbw_file(int fd) 571{ 572 struct smbw_file *file; 573 574 for (file=smbw_files;file;file=file->next) { 575 if (file->fd == fd) return file; 576 } 577 return NULL; 578} 579 580/***************************************************** 581a wrapper for open() 582*******************************************************/ 583int smbw_open(const char *fname, int flags, mode_t mode) 584{ 585 fstring server, share; 586 pstring path; 587 struct smbw_server *srv=NULL; 588 int eno=0, fd = -1; 589 struct smbw_file *file=NULL; 590 591 smbw_init(); 592 593 if (!fname) { 594 errno = EINVAL; 595 return -1; 596 } 597 598 smbw_busy++; 599 600 /* work out what server they are after */ 601 smbw_parse_path(fname, server, share, path); 602 603 /* get a connection to the server */ 604 srv = smbw_server(server, share); 605 if (!srv) { 606 /* smbw_server sets errno */ 607 goto failed; 608 } 609 610 if (path[strlen(path)-1] == '\\') { 611 fd = -1; 612 } else { 613 fd = cli_open(&srv->cli, path, flags, DENY_NONE); 614 } 615 if (fd == -1) { 616 /* it might be a directory. Maybe we should use chkpath? */ 617 eno = smbw_errno(&srv->cli); 618 fd = smbw_dir_open(fname); 619 if (fd == -1) errno = eno; 620 smbw_busy--; 621 return fd; 622 } 623 624 file = (struct smbw_file *)malloc(sizeof(*file)); 625 if (!file) { 626 errno = ENOMEM; 627 goto failed; 628 } 629 630 ZERO_STRUCTP(file); 631 632 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f))); 633 if (!file->f) { 634 errno = ENOMEM; 635 goto failed; 636 } 637 638 ZERO_STRUCTP(file->f); 639 640 file->f->cli_fd = fd; 641 file->f->fname = strdup(path); 642 if (!file->f->fname) { 643 errno = ENOMEM; 644 goto failed; 645 } 646 file->srv = srv; 647 file->fd = open(SMBW_DUMMY, O_WRONLY); 648 if (file->fd == -1) { 649 errno = EMFILE; 650 goto failed; 651 } 652 653 if (bitmap_query(smbw_file_bmap, file->fd)) { 654 DEBUG(0,("ERROR: fd used in smbw_open\n")); 655 errno = EIO; 656 goto failed; 657 } 658 659 file->f->ref_count=1; 660 661 bitmap_set(smbw_file_bmap, file->fd); 662 663 DLIST_ADD(smbw_files, file); 664 665 DEBUG(4,("opened %s\n", fname)); 666 667 smbw_busy--; 668 return file->fd; 669 670 failed: 671 if (fd != -1) { 672 cli_close(&srv->cli, fd); 673 } 674 if (file) { 675 if (file->f) { 676 if (file->f->fname) { 677 free(file->f->fname); 678 } 679 free(file->f); 680 } 681 free(file); 682 } 683 smbw_busy--; 684 return -1; 685} 686 687 688/***************************************************** 689a wrapper for pread() 690*******************************************************/ 691ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs) 692{ 693 struct smbw_file *file; 694 int ret; 695 696 smbw_busy++; 697 698 file = smbw_file(fd); 699 if (!file) { 700 errno = EBADF; 701 smbw_busy--; 702 return -1; 703 } 704 705 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count); 706 707 if (ret == -1) { 708 errno = smbw_errno(&file->srv->cli); 709 smbw_busy--; 710 return -1; 711 } 712 713 smbw_busy--; 714 return ret; 715} 716 717/***************************************************** 718a wrapper for read() 719*******************************************************/ 720ssize_t smbw_read(int fd, void *buf, size_t count) 721{ 722 struct smbw_file *file; 723 int ret; 724 725 DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count)); 726 727 smbw_busy++; 728 729 file = smbw_file(fd); 730 if (!file) { 731 errno = EBADF; 732 smbw_busy--; 733 return -1; 734 } 735 736 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, 737 file->f->offset, count); 738 739 if (ret == -1) { 740 errno = smbw_errno(&file->srv->cli); 741 smbw_busy--; 742 return -1; 743 } 744 745 file->f->offset += ret; 746 747 DEBUG(4,(" -> %d\n", ret)); 748 749 smbw_busy--; 750 return ret; 751} 752 753 754 755/***************************************************** 756a wrapper for write() 757*******************************************************/ 758ssize_t smbw_write(int fd, void *buf, size_t count) 759{ 760 struct smbw_file *file; 761 int ret; 762 763 smbw_busy++; 764 765 file = smbw_file(fd); 766 if (!file) { 767 errno = EBADF; 768 smbw_busy--; 769 return -1; 770 } 771 772 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count); 773 774 if (ret == -1) { 775 errno = smbw_errno(&file->srv->cli); 776 smbw_busy--; 777 return -1; 778 } 779 780 file->f->offset += ret; 781 782 smbw_busy--; 783 return ret; 784} 785 786/***************************************************** 787a wrapper for pwrite() 788*******************************************************/ 789ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs) 790{ 791 struct smbw_file *file; 792 int ret; 793 794 smbw_busy++; 795 796 file = smbw_file(fd); 797 if (!file) { 798 errno = EBADF; 799 smbw_busy--; 800 return -1; 801 } 802 803 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count); 804 805 if (ret == -1) { 806 errno = smbw_errno(&file->srv->cli); 807 smbw_busy--; 808 return -1; 809 } 810 811 smbw_busy--; 812 return ret; 813} 814 815/***************************************************** 816a wrapper for close() 817*******************************************************/ 818int smbw_close(int fd) 819{ 820 struct smbw_file *file; 821 822 smbw_busy++; 823 824 file = smbw_file(fd); 825 if (!file) { 826 int ret = smbw_dir_close(fd); 827 smbw_busy--; 828 return ret; 829 } 830 831 if (file->f->ref_count == 1 && 832 !cli_close(&file->srv->cli, file->f->cli_fd)) { 833 errno = smbw_errno(&file->srv->cli); 834 smbw_busy--; 835 return -1; 836 } 837 838 839 bitmap_clear(smbw_file_bmap, file->fd); 840 close(file->fd); 841 842 DLIST_REMOVE(smbw_files, file); 843 844 file->f->ref_count--; 845 if (file->f->ref_count == 0) { 846 free(file->f->fname); 847 free(file->f); 848 } 849 ZERO_STRUCTP(file); 850 free(file); 851 852 smbw_busy--; 853 854 return 0; 855} 856 857 858/***************************************************** 859a wrapper for fcntl() 860*******************************************************/ 861int smbw_fcntl(int fd, int cmd, long arg) 862{ 863 return 0; 864} 865 866 867/***************************************************** 868a wrapper for access() 869*******************************************************/ 870int smbw_access(const char *name, int mode) 871{ 872 struct stat st; 873 874 DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode)); 875 876 if (smbw_stat(name, &st)) return -1; 877 878 if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) || 879 ((mode & W_OK) && !(st.st_mode & S_IWUSR)) || 880 ((mode & X_OK) && !(st.st_mode & S_IXUSR))) { 881 errno = EACCES; 882 return -1; 883 } 884 885 return 0; 886} 887 888/***************************************************** 889a wrapper for realink() - needed for correct errno setting 890*******************************************************/ 891int smbw_readlink(const char *path, char *buf, size_t bufsize) 892{ 893 struct stat st; 894 int ret; 895 896 ret = smbw_stat(path, &st); 897 if (ret != 0) { 898 DEBUG(4,("readlink(%s) failed\n", path)); 899 return -1; 900 } 901 902 /* it exists - say it isn't a link */ 903 DEBUG(4,("readlink(%s) not a link\n", path)); 904 905 errno = EINVAL; 906 return -1; 907} 908 909 910/***************************************************** 911a wrapper for unlink() 912*******************************************************/ 913int smbw_unlink(const char *fname) 914{ 915 struct smbw_server *srv; 916 fstring server, share; 917 pstring path; 918 919 if (!fname) { 920 errno = EINVAL; 921 return -1; 922 } 923 924 smbw_init(); 925 926 smbw_busy++; 927 928 /* work out what server they are after */ 929 smbw_parse_path(fname, server, share, path); 930 931 /* get a connection to the server */ 932 srv = smbw_server(server, share); 933 if (!srv) { 934 /* smbw_server sets errno */ 935 goto failed; 936 } 937 938 if (strncmp(srv->cli.dev, "LPT", 3) == 0) { 939 int job = smbw_stat_printjob(srv, path, NULL, NULL); 940 if (job == -1) { 941 goto failed; 942 } 943 if (cli_printjob_del(&srv->cli, job) != 0) { 944 goto failed; 945 } 946 } else if (!cli_unlink(&srv->cli, path)) { 947 errno = smbw_errno(&srv->cli); 948 goto failed; 949 } 950 951 smbw_busy--; 952 return 0; 953 954 failed: 955 smbw_busy--; 956 return -1; 957} 958 959 960/***************************************************** 961a wrapper for rename() 962*******************************************************/ 963int smbw_rename(const char *oldname, const char *newname) 964{ 965 struct smbw_server *srv; 966 fstring server1, share1; 967 pstring path1; 968 fstring server2, share2; 969 pstring path2; 970 971 if (!oldname || !newname) { 972 errno = EINVAL; 973 return -1; 974 } 975 976 smbw_init(); 977 978 DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname)); 979 980 smbw_busy++; 981 982 /* work out what server they are after */ 983 smbw_parse_path(oldname, server1, share1, path1); 984 smbw_parse_path(newname, server2, share2, path2); 985 986 if (strcmp(server1, server2) || strcmp(share1, share2)) { 987 /* can't cross filesystems */ 988 errno = EXDEV; 989 return -1; 990 } 991 992 /* get a connection to the server */ 993 srv = smbw_server(server1, share1); 994 if (!srv) { 995 /* smbw_server sets errno */ 996 goto failed; 997 } 998 999 if (!cli_rename(&srv->cli, path1, path2)) { 1000 int eno = smbw_errno(&srv->cli); 1001 if (eno != EEXIST || 1002 !cli_unlink(&srv->cli, path2) || 1003 !cli_rename(&srv->cli, path1, path2)) { 1004 errno = eno; 1005 goto failed; 1006 } 1007 } 1008 1009 smbw_busy--; 1010 return 0; 1011 1012 failed: 1013 smbw_busy--; 1014 return -1; 1015} 1016 1017 1018/***************************************************** 1019a wrapper for utime and utimes 1020*******************************************************/ 1021static int smbw_settime(const char *fname, time_t t) 1022{ 1023 struct smbw_server *srv; 1024 fstring server, share; 1025 pstring path; 1026 uint16 mode; 1027 1028 if (!fname) { 1029 errno = EINVAL; 1030 return -1; 1031 } 1032 1033 smbw_init(); 1034 1035 smbw_busy++; 1036 1037 /* work out what server they are after */ 1038 smbw_parse_path(fname, server, share, path); 1039 1040 /* get a connection to the server */ 1041 srv = smbw_server(server, share); 1042 if (!srv) { 1043 /* smbw_server sets errno */ 1044 goto failed; 1045 } 1046 1047 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) { 1048 errno = smbw_errno(&srv->cli); 1049 goto failed; 1050 } 1051 1052 if (!cli_setatr(&srv->cli, path, mode, t)) { 1053 /* some servers always refuse directory changes */ 1054 if (!(mode & aDIR)) { 1055 errno = smbw_errno(&srv->cli); 1056 goto failed; 1057 } 1058 } 1059 1060 smbw_busy--; 1061 return 0; 1062 1063 failed: 1064 smbw_busy--; 1065 return -1; 1066} 1067 1068/***************************************************** 1069a wrapper for utime 1070*******************************************************/ 1071int smbw_utime(const char *fname, void *buf) 1072{ 1073 struct utimbuf *tbuf = (struct utimbuf *)buf; 1074 return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL)); 1075} 1076 1077/***************************************************** 1078a wrapper for utime 1079*******************************************************/ 1080int smbw_utimes(const char *fname, void *buf) 1081{ 1082 struct timeval *tbuf = (struct timeval *)buf; 1083 return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL)); 1084} 1085 1086 1087/***************************************************** 1088a wrapper for chown() 1089*******************************************************/ 1090int smbw_chown(const char *fname, uid_t owner, gid_t group) 1091{ 1092 struct smbw_server *srv; 1093 fstring server, share; 1094 pstring path; 1095 uint16 mode; 1096 1097 if (!fname) { 1098 errno = EINVAL; 1099 return -1; 1100 } 1101 1102 smbw_init(); 1103 1104 smbw_busy++; 1105 1106 /* work out what server they are after */ 1107 smbw_parse_path(fname, server, share, path); 1108 1109 /* get a connection to the server */ 1110 srv = smbw_server(server, share); 1111 if (!srv) { 1112 /* smbw_server sets errno */ 1113 goto failed; 1114 } 1115 1116 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) { 1117 errno = smbw_errno(&srv->cli); 1118 goto failed; 1119 } 1120 1121 /* assume success */ 1122 1123 smbw_busy--; 1124 return 0; 1125 1126 failed: 1127 smbw_busy--; 1128 return -1; 1129} 1130 1131/***************************************************** 1132a wrapper for chmod() 1133*******************************************************/ 1134int smbw_chmod(const char *fname, mode_t newmode) 1135{ 1136 struct smbw_server *srv; 1137 fstring server, share; 1138 pstring path; 1139 uint32 mode; 1140 1141 if (!fname) { 1142 errno = EINVAL; 1143 return -1; 1144 } 1145 1146 smbw_init(); 1147 1148 smbw_busy++; 1149 1150 /* work out what server they are after */ 1151 smbw_parse_path(fname, server, share, path); 1152 1153 /* get a connection to the server */ 1154 srv = smbw_server(server, share); 1155 if (!srv) { 1156 /* smbw_server sets errno */ 1157 goto failed; 1158 } 1159 1160 mode = 0; 1161 1162 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; 1163 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; 1164 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; 1165 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; 1166 1167 if (!cli_setatr(&srv->cli, path, mode, 0)) { 1168 errno = smbw_errno(&srv->cli); 1169 goto failed; 1170 } 1171 1172 smbw_busy--; 1173 return 0; 1174 1175 failed: 1176 smbw_busy--; 1177 return -1; 1178} 1179 1180/***************************************************** 1181a wrapper for lseek() 1182*******************************************************/ 1183off_t smbw_lseek(int fd, off_t offset, int whence) 1184{ 1185 struct smbw_file *file; 1186 size_t size; 1187 1188 smbw_busy++; 1189 1190 file = smbw_file(fd); 1191 if (!file) { 1192 off_t ret = smbw_dir_lseek(fd, offset, whence); 1193 smbw_busy--; 1194 return ret; 1195 } 1196 1197 switch (whence) { 1198 case SEEK_SET: 1199 file->f->offset = offset; 1200 break; 1201 case SEEK_CUR: 1202 file->f->offset += offset; 1203 break; 1204 case SEEK_END: 1205 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd, 1206 NULL, &size, NULL, NULL, NULL, 1207 NULL, NULL) && 1208 !cli_getattrE(&file->srv->cli, file->f->cli_fd, 1209 NULL, &size, NULL, NULL, NULL)) { 1210 errno = EINVAL; 1211 smbw_busy--; 1212 return -1; 1213 } 1214 file->f->offset = size + offset; 1215 break; 1216 } 1217 1218 smbw_busy--; 1219 return file->f->offset; 1220} 1221 1222 1223/***************************************************** 1224a wrapper for dup() 1225*******************************************************/ 1226int smbw_dup(int fd) 1227{ 1228 int fd2; 1229 struct smbw_file *file, *file2; 1230 1231 smbw_busy++; 1232 1233 file = smbw_file(fd); 1234 if (!file) { 1235 errno = EBADF; 1236 goto failed; 1237 } 1238 1239 fd2 = dup(file->fd); 1240 if (fd2 == -1) { 1241 goto failed; 1242 } 1243 1244 if (bitmap_query(smbw_file_bmap, fd2)) { 1245 DEBUG(0,("ERROR: fd already open in dup!\n")); 1246 errno = EIO; 1247 goto failed; 1248 } 1249 1250 file2 = (struct smbw_file *)malloc(sizeof(*file2)); 1251 if (!file2) { 1252 close(fd2); 1253 errno = ENOMEM; 1254 goto failed; 1255 } 1256 1257 ZERO_STRUCTP(file2); 1258 1259 *file2 = *file; 1260 file2->fd = fd2; 1261 1262 file->f->ref_count++; 1263 1264 bitmap_set(smbw_file_bmap, fd2); 1265 1266 DLIST_ADD(smbw_files, file2); 1267 1268 smbw_busy--; 1269 return fd2; 1270 1271 failed: 1272 smbw_busy--; 1273 return -1; 1274} 1275 1276 1277/***************************************************** 1278a wrapper for dup2() 1279*******************************************************/ 1280int smbw_dup2(int fd, int fd2) 1281{ 1282 struct smbw_file *file, *file2; 1283 1284 smbw_busy++; 1285 1286 file = smbw_file(fd); 1287 if (!file) { 1288 errno = EBADF; 1289 goto failed; 1290 } 1291 1292 if (bitmap_query(smbw_file_bmap, fd2)) { 1293 DEBUG(0,("ERROR: fd already open in dup2!\n")); 1294 errno = EIO; 1295 goto failed; 1296 } 1297 1298 if (dup2(file->fd, fd2) != fd2) { 1299 goto failed; 1300 } 1301 1302 file2 = (struct smbw_file *)malloc(sizeof(*file2)); 1303 if (!file2) { 1304 close(fd2); 1305 errno = ENOMEM; 1306 goto failed; 1307 } 1308 1309 ZERO_STRUCTP(file2); 1310 1311 *file2 = *file; 1312 file2->fd = fd2; 1313 1314 file->f->ref_count++; 1315 1316 bitmap_set(smbw_file_bmap, fd2); 1317 1318 DLIST_ADD(smbw_files, file2); 1319 1320 smbw_busy--; 1321 return fd2; 1322 1323 failed: 1324 smbw_busy--; 1325 return -1; 1326} 1327 1328 1329/***************************************************** 1330close a connection to a server 1331*******************************************************/ 1332static void smbw_srv_close(struct smbw_server *srv) 1333{ 1334 smbw_busy++; 1335 1336 cli_shutdown(&srv->cli); 1337 1338 free(srv->server_name); 1339 free(srv->share_name); 1340 1341 DLIST_REMOVE(smbw_srvs, srv); 1342 1343 ZERO_STRUCTP(srv); 1344 1345 free(srv); 1346 1347 smbw_busy--; 1348} 1349 1350/***************************************************** 1351when we fork we have to close all connections and files 1352in the child 1353*******************************************************/ 1354int smbw_fork(void) 1355{ 1356 pid_t child; 1357 int p[2]; 1358 char c=0; 1359 pstring line; 1360 1361 struct smbw_file *file, *next_file; 1362 struct smbw_server *srv, *next_srv; 1363 1364 if (pipe(p)) return real_fork(); 1365 1366 child = real_fork(); 1367 1368 if (child) { 1369 /* block the parent for a moment until the sockets are 1370 closed */ 1371 close(p[1]); 1372 read(p[0], &c, 1); 1373 close(p[0]); 1374 return child; 1375 } 1376 1377 close(p[0]); 1378 1379 /* close all files */ 1380 for (file=smbw_files;file;file=next_file) { 1381 next_file = file->next; 1382 close(file->fd); 1383 } 1384 1385 /* close all server connections */ 1386 for (srv=smbw_srvs;srv;srv=next_srv) { 1387 next_srv = srv->next; 1388 smbw_srv_close(srv); 1389 } 1390 1391 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid()); 1392 smbw_setshared(line,smbw_cwd); 1393 1394 /* unblock the parent */ 1395 write(p[1], &c, 1); 1396 close(p[1]); 1397 1398 /* and continue in the child */ 1399 return 0; 1400} 1401 1402#ifndef NO_ACL_WRAPPER 1403/***************************************************** 1404say no to acls 1405*******************************************************/ 1406 int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp) 1407{ 1408 if (cmd == GETACL || cmd == GETACLCNT) return 0; 1409 errno = ENOSYS; 1410 return -1; 1411} 1412#endif 1413 1414#ifndef NO_FACL_WRAPPER 1415/***************************************************** 1416say no to acls 1417*******************************************************/ 1418 int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp) 1419{ 1420 if (cmd == GETACL || cmd == GETACLCNT) return 0; 1421 errno = ENOSYS; 1422 return -1; 1423} 1424#endif 1425 1426 1427#ifdef HAVE_STAT64 1428/* this can't be in wrapped.c because of include conflicts */ 1429 void stat64_convert(struct stat *st, struct stat64 *st64) 1430{ 1431 st64->st_size = st->st_size; 1432 st64->st_mode = st->st_mode; 1433 st64->st_ino = st->st_ino; 1434 st64->st_dev = st->st_dev; 1435 st64->st_rdev = st->st_rdev; 1436 st64->st_nlink = st->st_nlink; 1437 st64->st_uid = st->st_uid; 1438 st64->st_gid = st->st_gid; 1439 st64->st_atime = st->st_atime; 1440 st64->st_mtime = st->st_mtime; 1441 st64->st_ctime = st->st_ctime; 1442 st64->st_blksize = st->st_blksize; 1443 st64->st_blocks = st->st_blocks; 1444} 1445#endif 1446 1447#ifdef HAVE_READDIR64 1448 void dirent64_convert(struct dirent *d, struct dirent64 *d64) 1449{ 1450 d64->d_ino = d->d_ino; 1451 d64->d_off = d->d_off; 1452 d64->d_reclen = d->d_reclen; 1453 pstrcpy(d64->d_name, d->d_name); 1454} 1455#endif 1456 1457 1458#ifdef HAVE___XSTAT 1459/* Definition of `struct stat' used in the linux kernel.. */ 1460struct kernel_stat { 1461 unsigned short int st_dev; 1462 unsigned short int __pad1; 1463 unsigned long int st_ino; 1464 unsigned short int st_mode; 1465 unsigned short int st_nlink; 1466 unsigned short int st_uid; 1467 unsigned short int st_gid; 1468 unsigned short int st_rdev; 1469 unsigned short int __pad2; 1470 unsigned long int st_size; 1471 unsigned long int st_blksize; 1472 unsigned long int st_blocks; 1473 unsigned long int st_atime; 1474 unsigned long int __unused1; 1475 unsigned long int st_mtime; 1476 unsigned long int __unused2; 1477 unsigned long int st_ctime; 1478 unsigned long int __unused3; 1479 unsigned long int __unused4; 1480 unsigned long int __unused5; 1481}; 1482 1483/* 1484 * Prototype for gcc in 'fussy' mode. 1485 */ 1486 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf); 1487 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf) 1488{ 1489#ifdef _STAT_VER_LINUX_OLD 1490 if (vers == _STAT_VER_LINUX_OLD) { 1491 memcpy(st, kbuf, sizeof(*st)); 1492 return; 1493 } 1494#endif 1495 1496 ZERO_STRUCTP(st); 1497 1498 st->st_dev = kbuf->st_dev; 1499 st->st_ino = kbuf->st_ino; 1500 st->st_mode = kbuf->st_mode; 1501 st->st_nlink = kbuf->st_nlink; 1502 st->st_uid = kbuf->st_uid; 1503 st->st_gid = kbuf->st_gid; 1504 st->st_rdev = kbuf->st_rdev; 1505 st->st_size = kbuf->st_size; 1506 st->st_blksize = kbuf->st_blksize; 1507 st->st_blocks = kbuf->st_blocks; 1508 st->st_atime = kbuf->st_atime; 1509 st->st_mtime = kbuf->st_mtime; 1510 st->st_ctime = kbuf->st_ctime; 1511} 1512#endif 1513