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