1/* 2 Unix SMB/Netbios implementation. 3 Version 1.9. 4 Samba utility functions 5 Copyright (C) Andrew Tridgell 1992-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 24#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) 25#ifdef WITH_NISPLUS_HOME 26#ifdef BROKEN_NISPLUS_INCLUDE_FILES 27/* 28 * The following lines are needed due to buggy include files 29 * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and 30 * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA. 31 * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as 32 * an enum in /usr/include/rpcsvc/nis.h. 33 */ 34 35#if defined(GROUP) 36#undef GROUP 37#endif 38 39#if defined(GROUP_OBJ) 40#undef GROUP_OBJ 41#endif 42 43#endif /* BROKEN_NISPLUS_INCLUDE_FILES */ 44 45#include <rpcsvc/nis.h> 46 47#else /* !WITH_NISPLUS_HOME */ 48 49#include "rpcsvc/ypclnt.h" 50 51#endif /* WITH_NISPLUS_HOME */ 52#endif /* HAVE_NETGROUP && WITH_AUTOMOUNT */ 53 54#ifdef WITH_SSL 55#include <ssl.h> 56#undef Realloc /* SSLeay defines this and samba has a function of this name */ 57extern SSL *ssl; 58extern int sslFd; 59#endif /* WITH_SSL */ 60 61extern int DEBUGLEVEL; 62 63int Protocol = PROTOCOL_COREPLUS; 64 65/* a default finfo structure to ensure all fields are sensible */ 66file_info def_finfo = {-1,0,0,0,0,0,0,""}; 67 68/* the client file descriptor */ 69extern int Client; 70 71/* this is used by the chaining code */ 72int chain_size = 0; 73 74int trans_num = 0; 75 76/* 77 case handling on filenames 78*/ 79int case_default = CASE_LOWER; 80 81/* the following control case operations - they are put here so the 82 client can link easily */ 83BOOL case_sensitive; 84BOOL case_preserve; 85BOOL use_mangled_map = False; 86BOOL short_case_preserve; 87BOOL case_mangle; 88 89fstring remote_machine=""; 90fstring local_machine=""; 91fstring remote_arch="UNKNOWN"; 92static enum remote_arch_types ra_type = RA_UNKNOWN; 93fstring remote_proto="UNKNOWN"; 94pstring user_socket_options=DEFAULT_SOCKET_OPTIONS; 95 96pstring sesssetup_user=""; 97pstring samlogon_user=""; 98 99BOOL sam_logon_in_ssb = False; 100 101pstring global_myname = ""; 102fstring global_myworkgroup = ""; 103char **my_netbios_names; 104 105static char *filename_dos(char *path,char *buf); 106 107 108 109/**************************************************************************** 110 find a suitable temporary directory. The result should be copied immediately 111 as it may be overwritten by a subsequent call 112 ****************************************************************************/ 113char *tmpdir(void) 114{ 115 char *p; 116 if ((p = getenv("TMPDIR"))) { 117 return p; 118 } 119 return "/tmp"; 120} 121 122/**************************************************************************** 123determine whether we are in the specified group 124****************************************************************************/ 125 126BOOL in_group(gid_t group, gid_t current_gid, int ngroups, gid_t *groups) 127{ 128 int i; 129 130 if (group == current_gid) return(True); 131 132 for (i=0;i<ngroups;i++) 133 if (group == groups[i]) 134 return(True); 135 136 return(False); 137} 138 139 140/**************************************************************************** 141like atoi but gets the value up to the separater character 142****************************************************************************/ 143char *Atoic(char *p, int *n, char *c) 144{ 145 if (!isdigit((int)*p)) 146 { 147 DEBUG(5, ("Atoic: malformed number\n")); 148 return NULL; 149 } 150 151 (*n) = atoi(p); 152 153 while ((*p) && isdigit((int)*p)) 154 { 155 p++; 156 } 157 158 if (strchr(c, *p) == NULL) 159 { 160 DEBUG(5, ("Atoic: no separator characters (%s) not found\n", c)); 161 return NULL; 162 } 163 164 return p; 165} 166 167/************************************************************************* 168 reads a list of numbers 169 *************************************************************************/ 170char *get_numlist(char *p, uint32 **num, int *count) 171{ 172 int val; 173 174 if (num == NULL || count == NULL) 175 { 176 return NULL; 177 } 178 179 (*count) = 0; 180 (*num ) = NULL; 181 182 while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':') 183 { 184 (*num) = Realloc((*num), ((*count)+1) * sizeof(uint32)); 185 if ((*num) == NULL) 186 { 187 return NULL; 188 } 189 (*num)[(*count)] = val; 190 (*count)++; 191 p++; 192 } 193 194 return p; 195} 196 197#define TRUNCATE_NETBIOS_NAME 1 198 199/******************************************************************* 200 convert, possibly using a stupid microsoft-ism which has destroyed 201 the transport independence of netbios (for CIFS vendors that usually 202 use the Win95-type methods, not for NT to NT communication, which uses 203 DCE/RPC and therefore full-length unicode strings...) a dns name into 204 a netbios name. 205 206 the netbios name (NOT necessarily null-terminated) is truncated to 15 207 characters. 208 209 ******************************************************************/ 210char *dns_to_netbios_name(char *dns_name) 211{ 212 static char netbios_name[16]; 213 int i; 214 StrnCpy(netbios_name, dns_name, 15); 215 netbios_name[15] = 0; 216 217#ifdef TRUNCATE_NETBIOS_NAME 218 /* ok. this is because of a stupid microsoft-ism. if the called host 219 name contains a '.', microsoft clients expect you to truncate the 220 netbios name up to and including the '.' this even applies, by 221 mistake, to workgroup (domain) names, which is _really_ daft. 222 */ 223 for (i = 15; i >= 0; i--) 224 { 225 if (netbios_name[i] == '.') 226 { 227 netbios_name[i] = 0; 228 break; 229 } 230 } 231#endif /* TRUNCATE_NETBIOS_NAME */ 232 233 return netbios_name; 234} 235 236 237/**************************************************************************** 238interpret the weird netbios "name". Return the name type 239****************************************************************************/ 240static int name_interpret(char *in,char *out) 241{ 242 int ret; 243 int len = (*in++) / 2; 244 245 *out=0; 246 247 if (len > 30 || len<1) return(0); 248 249 while (len--) 250 { 251 if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { 252 *out = 0; 253 return(0); 254 } 255 *out = ((in[0]-'A')<<4) + (in[1]-'A'); 256 in += 2; 257 out++; 258 } 259 *out = 0; 260 ret = out[-1]; 261 262#ifdef NETBIOS_SCOPE 263 /* Handle any scope names */ 264 while(*in) 265 { 266 *out++ = '.'; /* Scope names are separated by periods */ 267 len = *(unsigned char *)in++; 268 StrnCpy(out, in, len); 269 out += len; 270 *out=0; 271 in += len; 272 } 273#endif 274 return(ret); 275} 276 277/**************************************************************************** 278mangle a name into netbios format 279 280 Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum. 281****************************************************************************/ 282int name_mangle( char *In, char *Out, char name_type ) 283 { 284 int i; 285 int c; 286 int len; 287 char buf[20]; 288 char *p = Out; 289 extern pstring global_scope; 290 291 /* Safely copy the input string, In, into buf[]. */ 292 (void)memset( buf, 0, 20 ); 293 if (strcmp(In,"*") == 0) 294 buf[0] = '*'; 295 else 296 (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type ); 297 298 /* Place the length of the first field into the output buffer. */ 299 p[0] = 32; 300 p++; 301 302 /* Now convert the name to the rfc1001/1002 format. */ 303 for( i = 0; i < 16; i++ ) 304 { 305 c = toupper( buf[i] ); 306 p[i*2] = ( (c >> 4) & 0x000F ) + 'A'; 307 p[(i*2)+1] = (c & 0x000F) + 'A'; 308 } 309 p += 32; 310 p[0] = '\0'; 311 312 /* Add the scope string. */ 313 for( i = 0, len = 0; NULL != global_scope; i++, len++ ) 314 { 315 switch( global_scope[i] ) 316 { 317 case '\0': 318 p[0] = len; 319 if( len > 0 ) 320 p[len+1] = 0; 321 return( name_len(Out) ); 322 case '.': 323 p[0] = len; 324 p += (len + 1); 325 len = -1; 326 break; 327 default: 328 p[len+1] = global_scope[i]; 329 break; 330 } 331 } 332 333 return( name_len(Out) ); 334 } /* name_mangle */ 335 336/******************************************************************* 337 check if a file exists 338********************************************************************/ 339BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf) 340{ 341 SMB_STRUCT_STAT st; 342 if (!sbuf) sbuf = &st; 343 344 if (sys_stat(fname,sbuf) != 0) 345 return(False); 346 347 return(S_ISREG(sbuf->st_mode)); 348} 349 350/******************************************************************* 351check a files mod time 352********************************************************************/ 353time_t file_modtime(char *fname) 354{ 355 SMB_STRUCT_STAT st; 356 357 if (sys_stat(fname,&st) != 0) 358 return(0); 359 360 return(st.st_mtime); 361} 362 363/******************************************************************* 364 check if a directory exists 365********************************************************************/ 366BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st) 367{ 368 SMB_STRUCT_STAT st2; 369 BOOL ret; 370 371 if (!st) st = &st2; 372 373 if (sys_stat(dname,st) != 0) 374 return(False); 375 376 ret = S_ISDIR(st->st_mode); 377 if(!ret) 378 errno = ENOTDIR; 379 return ret; 380} 381 382/******************************************************************* 383returns the size in bytes of the named file 384********************************************************************/ 385SMB_OFF_T get_file_size(char *file_name) 386{ 387 SMB_STRUCT_STAT buf; 388 buf.st_size = 0; 389 if(sys_stat(file_name,&buf) != 0) 390 return (SMB_OFF_T)-1; 391 return(buf.st_size); 392} 393 394/******************************************************************* 395return a string representing an attribute for a file 396********************************************************************/ 397char *attrib_string(uint16 mode) 398{ 399 static fstring attrstr; 400 401 attrstr[0] = 0; 402 403 if (mode & aVOLID) fstrcat(attrstr,"V"); 404 if (mode & aDIR) fstrcat(attrstr,"D"); 405 if (mode & aARCH) fstrcat(attrstr,"A"); 406 if (mode & aHIDDEN) fstrcat(attrstr,"H"); 407 if (mode & aSYSTEM) fstrcat(attrstr,"S"); 408 if (mode & aRONLY) fstrcat(attrstr,"R"); 409 410 return(attrstr); 411} 412 413/******************************************************************* 414 show a smb message structure 415********************************************************************/ 416void show_msg(char *buf) 417{ 418 int i; 419 int bcc=0; 420 421 if (DEBUGLEVEL < 5) return; 422 423 DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n", 424 smb_len(buf), 425 (int)CVAL(buf,smb_com), 426 (int)CVAL(buf,smb_rcls), 427 (int)CVAL(buf,smb_reh), 428 (int)SVAL(buf,smb_err), 429 (int)CVAL(buf,smb_flg), 430 (int)SVAL(buf,smb_flg2))); 431 DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", 432 (int)SVAL(buf,smb_tid), 433 (int)SVAL(buf,smb_pid), 434 (int)SVAL(buf,smb_uid), 435 (int)SVAL(buf,smb_mid), 436 (int)CVAL(buf,smb_wct))); 437 438 for (i=0;i<(int)CVAL(buf,smb_wct);i++) 439 { 440 DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i, 441 SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i))); 442 } 443 444 bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); 445 446 DEBUG(5,("smb_bcc=%d\n",bcc)); 447 448 if (DEBUGLEVEL < 10) return; 449 450 if (DEBUGLEVEL < 50) 451 { 452 bcc = MIN(bcc, 512); 453 } 454 455 dump_data(10, smb_buf(buf), bcc); 456} 457 458/******************************************************************* 459 set the length and marker of an smb packet 460********************************************************************/ 461void smb_setlen(char *buf,int len) 462{ 463 _smb_setlen(buf,len); 464 465 CVAL(buf,4) = 0xFF; 466 CVAL(buf,5) = 'S'; 467 CVAL(buf,6) = 'M'; 468 CVAL(buf,7) = 'B'; 469} 470 471/******************************************************************* 472 setup the word count and byte count for a smb message 473********************************************************************/ 474int set_message(char *buf,int num_words,int num_bytes,BOOL zero) 475{ 476 if (zero) 477 memset(buf + smb_size,'\0',num_words*2 + num_bytes); 478 CVAL(buf,smb_wct) = num_words; 479 SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); 480 smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); 481 return (smb_size + num_words*2 + num_bytes); 482} 483 484/******************************************************************* 485reduce a file name, removing .. elements. 486********************************************************************/ 487void dos_clean_name(char *s) 488{ 489 char *p=NULL; 490 491 DEBUG(3,("dos_clean_name [%s]\n",s)); 492 493 /* remove any double slashes */ 494 all_string_sub(s, "\\\\", "\\", 0); 495 496 while ((p = strstr(s,"\\..\\")) != NULL) 497 { 498 pstring s1; 499 500 *p = 0; 501 pstrcpy(s1,p+3); 502 503 if ((p=strrchr(s,'\\')) != NULL) 504 *p = 0; 505 else 506 *s = 0; 507 pstrcat(s,s1); 508 } 509 510 trim_string(s,NULL,"\\.."); 511 512 all_string_sub(s, "\\.\\", "\\", 0); 513} 514 515/******************************************************************* 516reduce a file name, removing .. elements. 517********************************************************************/ 518void unix_clean_name(char *s) 519{ 520 char *p=NULL; 521 522 DEBUG(3,("unix_clean_name [%s]\n",s)); 523 524 /* remove any double slashes */ 525 all_string_sub(s, "//","/", 0); 526 527 /* Remove leading ./ characters */ 528 if(strncmp(s, "./", 2) == 0) { 529 trim_string(s, "./", NULL); 530 if(*s == 0) 531 pstrcpy(s,"./"); 532 } 533 534 while ((p = strstr(s,"/../")) != NULL) 535 { 536 pstring s1; 537 538 *p = 0; 539 pstrcpy(s1,p+3); 540 541 if ((p=strrchr(s,'/')) != NULL) 542 *p = 0; 543 else 544 *s = 0; 545 pstrcat(s,s1); 546 } 547 548 trim_string(s,NULL,"/.."); 549} 550 551/******************************************************************* 552reduce a file name, removing .. elements and checking that 553it is below dir in the heirachy. This uses dos_GetWd() and so must be run 554on the system that has the referenced file system. 555 556widelinks are allowed if widelinks is true 557********************************************************************/ 558 559BOOL reduce_name(char *s,char *dir,BOOL widelinks) 560{ 561#ifndef REDUCE_PATHS 562 return True; 563#else 564 pstring dir2; 565 pstring wd; 566 pstring base_name; 567 pstring newname; 568 char *p=NULL; 569 BOOL relative = (*s != '/'); 570 571 *dir2 = *wd = *base_name = *newname = 0; 572 573 if (widelinks) 574 { 575 unix_clean_name(s); 576 /* can't have a leading .. */ 577 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) 578 { 579 DEBUG(3,("Illegal file name? (%s)\n",s)); 580 return(False); 581 } 582 583 if (strlen(s) == 0) 584 pstrcpy(s,"./"); 585 586 return(True); 587 } 588 589 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir)); 590 591 /* remove any double slashes */ 592 all_string_sub(s,"//","/",0); 593 594 pstrcpy(base_name,s); 595 p = strrchr(base_name,'/'); 596 597 if (!p) 598 return(True); 599 600 if (!dos_GetWd(wd)) 601 { 602 DEBUG(0,("couldn't getwd for %s %s\n",s,dir)); 603 return(False); 604 } 605 606 if (dos_ChDir(dir) != 0) 607 { 608 DEBUG(0,("couldn't chdir to %s\n",dir)); 609 return(False); 610 } 611 612 if (!dos_GetWd(dir2)) 613 { 614 DEBUG(0,("couldn't getwd for %s\n",dir)); 615 dos_ChDir(wd); 616 return(False); 617 } 618 619 if (p && (p != base_name)) 620 { 621 *p = 0; 622 if (strcmp(p+1,".")==0) 623 p[1]=0; 624 if (strcmp(p+1,"..")==0) 625 *p = '/'; 626 } 627 628 if (dos_ChDir(base_name) != 0) 629 { 630 dos_ChDir(wd); 631 DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name)); 632 return(False); 633 } 634 635 if (!dos_GetWd(newname)) 636 { 637 dos_ChDir(wd); 638 DEBUG(2,("couldn't get wd for %s %s\n",s,dir2)); 639 return(False); 640 } 641 642 if (p && (p != base_name)) 643 { 644 pstrcat(newname,"/"); 645 pstrcat(newname,p+1); 646 } 647 648 { 649 size_t l = strlen(dir2); 650 if (dir2[l-1] == '/') 651 l--; 652 653 if (strncmp(newname,dir2,l) != 0) 654 { 655 dos_ChDir(wd); 656 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l)); 657 return(False); 658 } 659 660 if (relative) 661 { 662 if (newname[l] == '/') 663 pstrcpy(s,newname + l + 1); 664 else 665 pstrcpy(s,newname+l); 666 } 667 else 668 pstrcpy(s,newname); 669 } 670 671 dos_ChDir(wd); 672 673 if (strlen(s) == 0) 674 pstrcpy(s,"./"); 675 676 DEBUG(3,("reduced to %s\n",s)); 677 return(True); 678#endif 679} 680 681/**************************************************************************** 682expand some *s 683****************************************************************************/ 684static void expand_one(char *Mask,int len) 685{ 686 char *p1; 687 while ((p1 = strchr(Mask,'*')) != NULL) 688 { 689 int lfill = (len+1) - strlen(Mask); 690 int l1= (p1 - Mask); 691 pstring tmp; 692 pstrcpy(tmp,Mask); 693 memset(tmp+l1,'?',lfill); 694 pstrcpy(tmp + l1 + lfill,Mask + l1 + 1); 695 pstrcpy(Mask,tmp); 696 } 697} 698 699/**************************************************************************** 700expand a wildcard expression, replacing *s with ?s 701****************************************************************************/ 702void expand_mask(char *Mask,BOOL doext) 703{ 704 pstring mbeg,mext; 705 pstring dirpart; 706 pstring filepart; 707 BOOL hasdot = False; 708 char *p1; 709 BOOL absolute = (*Mask == '\\'); 710 711 *mbeg = *mext = *dirpart = *filepart = 0; 712 713 /* parse the directory and filename */ 714 if (strchr(Mask,'\\')) 715 split_at_last_component(Mask,dirpart,'\\',NULL); 716 717 filename_dos(Mask,filepart); 718 719 pstrcpy(mbeg,filepart); 720 if ((p1 = strchr(mbeg,'.')) != NULL) 721 { 722 hasdot = True; 723 *p1 = 0; 724 p1++; 725 pstrcpy(mext,p1); 726 } 727 else 728 { 729 pstrcpy(mext,""); 730 if (strlen(mbeg) > 8) 731 { 732 pstrcpy(mext,mbeg + 8); 733 mbeg[8] = 0; 734 } 735 } 736 737 if (*mbeg == 0) 738 pstrcpy(mbeg,"????????"); 739 if ((*mext == 0) && doext && !hasdot) 740 pstrcpy(mext,"???"); 741 742 if (strequal(mbeg,"*") && *mext==0) 743 pstrcpy(mext,"*"); 744 745 /* expand *'s */ 746 expand_one(mbeg,8); 747 if (*mext) 748 expand_one(mext,3); 749 750 pstrcpy(Mask,dirpart); 751 if (*dirpart || absolute) pstrcat(Mask,"\\"); 752 pstrcat(Mask,mbeg); 753 pstrcat(Mask,"."); 754 pstrcat(Mask,mext); 755 756 DEBUG(6,("Mask expanded to [%s]\n",Mask)); 757} 758 759 760 761/**************************************************************************** 762 make a dir struct 763****************************************************************************/ 764void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date) 765{ 766 char *p; 767 pstring mask2; 768 769 pstrcpy(mask2,mask); 770 771 if ((mode & aDIR) != 0) 772 size = 0; 773 774 memset(buf+1,' ',11); 775 if ((p = strchr(mask2,'.')) != NULL) 776 { 777 *p = 0; 778 memcpy(buf+1,mask2,MIN(strlen(mask2),8)); 779 memcpy(buf+9,p+1,MIN(strlen(p+1),3)); 780 *p = '.'; 781 } 782 else 783 memcpy(buf+1,mask2,MIN(strlen(mask2),11)); 784 785 memset(buf+21,'\0',DIR_STRUCT_SIZE-21); 786 CVAL(buf,21) = mode; 787 put_dos_date(buf,22,date); 788 SSVAL(buf,26,size & 0xFFFF); 789 SSVAL(buf,28,(size >> 16)&0xFFFF); 790 StrnCpy(buf+30,fname,12); 791 if (!case_sensitive) 792 strupper(buf+30); 793 DEBUG(8,("put name [%s] into dir struct\n",buf+30)); 794} 795 796 797/******************************************************************* 798close the low 3 fd's and open dev/null in their place 799********************************************************************/ 800void close_low_fds(void) 801{ 802 int fd; 803 int i; 804 close(0); close(1); close(2); 805 /* try and use up these file descriptors, so silly 806 library routines writing to stdout etc won't cause havoc */ 807 for (i=0;i<3;i++) { 808 fd = sys_open("/dev/null",O_RDWR,0); 809 if (fd < 0) fd = sys_open("/dev/null",O_WRONLY,0); 810 if (fd < 0) { 811 DEBUG(0,("Can't open /dev/null\n")); 812 return; 813 } 814 if (fd != i) { 815 DEBUG(0,("Didn't get file descriptor %d\n",i)); 816 return; 817 } 818 } 819} 820 821/**************************************************************************** 822Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, 823else 824if SYSV use O_NDELAY 825if BSD use FNDELAY 826****************************************************************************/ 827int set_blocking(int fd, BOOL set) 828{ 829 int val; 830#ifdef O_NONBLOCK 831#define FLAG_TO_SET O_NONBLOCK 832#else 833#ifdef SYSV 834#define FLAG_TO_SET O_NDELAY 835#else /* BSD */ 836#define FLAG_TO_SET FNDELAY 837#endif 838#endif 839 840 if((val = fcntl(fd, F_GETFL, 0)) == -1) 841 return -1; 842 if(set) /* Turn blocking on - ie. clear nonblock flag */ 843 val &= ~FLAG_TO_SET; 844 else 845 val |= FLAG_TO_SET; 846 return fcntl( fd, F_SETFL, val); 847#undef FLAG_TO_SET 848} 849 850/**************************************************************************** 851transfer some data between two fd's 852****************************************************************************/ 853SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n,char *header,int headlen,int align) 854{ 855 static char *buf=NULL; 856 static int size=0; 857 char *buf1,*abuf; 858 SMB_OFF_T total = 0; 859 860 DEBUG(4,("transfer_file n=%.0f (head=%d) called\n",(double)n,headlen)); 861 862 if (size == 0) { 863 size = lp_readsize(); 864 size = MAX(size,1024); 865 } 866 867 while (!buf && size>0) { 868 buf = (char *)Realloc(buf,size+8); 869 if (!buf) size /= 2; 870 } 871 872 if (!buf) { 873 DEBUG(0,("Can't allocate transfer buffer!\n")); 874 exit(1); 875 } 876 877 abuf = buf + (align%8); 878 879 if (header) 880 n += headlen; 881 882 while (n > 0) 883 { 884 int s = (int)MIN(n,(SMB_OFF_T)size); 885 int ret,ret2=0; 886 887 ret = 0; 888 889 if (header && (headlen >= MIN(s,1024))) { 890 buf1 = header; 891 s = headlen; 892 ret = headlen; 893 headlen = 0; 894 header = NULL; 895 } else { 896 buf1 = abuf; 897 } 898 899 if (header && headlen > 0) 900 { 901 ret = MIN(headlen,size); 902 memcpy(buf1,header,ret); 903 headlen -= ret; 904 header += ret; 905 if (headlen <= 0) header = NULL; 906 } 907 908 if (s > ret) 909 ret += read(infd,buf1+ret,s-ret); 910 911 if (ret > 0) 912 { 913 ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret); 914 if (ret2 > 0) total += ret2; 915 /* if we can't write then dump excess data */ 916 if (ret2 != ret) 917 transfer_file(infd,-1,n-(ret+headlen),NULL,0,0); 918 } 919 if (ret <= 0 || ret2 != ret) 920 return(total); 921 n -= ret; 922 } 923 return(total); 924} 925 926 927 928/**************************************************************************** 929find a pointer to a netbios name 930****************************************************************************/ 931static char *name_ptr(char *buf,int ofs) 932{ 933 unsigned char c = *(unsigned char *)(buf+ofs); 934 935 if ((c & 0xC0) == 0xC0) 936 { 937 uint16 l = RSVAL(buf, ofs) & 0x3FFF; 938 DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l)); 939 return(buf + l); 940 } 941 else 942 return(buf+ofs); 943} 944 945/**************************************************************************** 946extract a netbios name from a buf 947****************************************************************************/ 948int name_extract(char *buf,int ofs,char *name) 949{ 950 char *p = name_ptr(buf,ofs); 951 int d = PTR_DIFF(p,buf+ofs); 952 pstrcpy(name,""); 953 if (d < -50 || d > 50) return(0); 954 return(name_interpret(p,name)); 955} 956 957/**************************************************************************** 958return the total storage length of a mangled name 959****************************************************************************/ 960int name_len(char *s1) 961{ 962 /* NOTE: this argument _must_ be unsigned */ 963 unsigned char *s = (unsigned char *)s1; 964 int len; 965 966 /* If the two high bits of the byte are set, return 2. */ 967 if (0xC0 == (*s & 0xC0)) 968 return(2); 969 970 /* Add up the length bytes. */ 971 for (len = 1; (*s); s += (*s) + 1) { 972 len += *s + 1; 973 SMB_ASSERT(len < 80); 974 } 975 976 return(len); 977} /* name_len */ 978 979 980/******************************************************************* 981sleep for a specified number of milliseconds 982********************************************************************/ 983void msleep(int t) 984{ 985 int tdiff=0; 986 struct timeval tval,t1,t2; 987 fd_set fds; 988 989 GetTimeOfDay(&t1); 990 GetTimeOfDay(&t2); 991 992 while (tdiff < t) { 993 tval.tv_sec = (t-tdiff)/1000; 994 tval.tv_usec = 1000*((t-tdiff)%1000); 995 996 FD_ZERO(&fds); 997 errno = 0; 998 sys_select(0,&fds,&tval); 999 1000 GetTimeOfDay(&t2); 1001 tdiff = TvalDiff(&t1,&t2); 1002 } 1003} 1004 1005 1006/********************************************************* 1007* Recursive routine that is called by unix_mask_match. 1008* Does the actual matching. This is the 'original code' 1009* used by the unix matcher. 1010*********************************************************/ 1011 1012BOOL unix_do_match(char *str, char *regexp, BOOL case_sig) 1013{ 1014 char *p; 1015 1016 for( p = regexp; *p && *str; ) { 1017 switch(*p) { 1018 case '?': 1019 str++; p++; 1020 break; 1021 1022 case '*': 1023 /* 1024 * Look for a character matching 1025 * the one after the '*'. 1026 */ 1027 p++; 1028 if(!*p) 1029 return True; /* Automatic match */ 1030 while(*str) { 1031 1032 while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) 1033 str++; 1034 1035 /* 1036 * Patch from weidel@multichart.de. In the case of the regexp 1037 * '*XX*' we want to ensure there are at least 2 'X' characters 1038 * in the filename after the '*' for a match to be made. 1039 */ 1040 1041 { 1042 int matchcount=0; 1043 1044 /* 1045 * Eat all the characters that match, but count how many there were. 1046 */ 1047 1048 while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str)))) { 1049 str++; 1050 matchcount++; 1051 } 1052 1053 /* 1054 * Now check that if the regexp had n identical characters that 1055 * matchcount had at least that many matches. 1056 */ 1057 1058 while (( *(p+1) && (case_sig ? (*(p+1) == *p) : (toupper(*(p+1))==toupper(*p))))) { 1059 p++; 1060 matchcount--; 1061 } 1062 if ( matchcount <= 0 ) { 1063 return False; 1064 } 1065 } 1066 str--; /* We've eaten the match char after the '*' */ 1067 if(unix_do_match(str,p,case_sig)) 1068 return True; 1069 if(!*str) 1070 return False; 1071 else 1072 str++; 1073 } 1074 return False; 1075 1076 default: 1077 if(case_sig) { 1078 if(*str != *p) 1079 return False; 1080 } else { 1081 if(toupper(*str) != toupper(*p)) 1082 return False; 1083 } 1084 str++, p++; 1085 break; 1086 } 1087 } 1088 1089 if(!*p && !*str) 1090 return True; 1091 1092 if (!*p && str[0] == '.' && str[1] == 0) 1093 return(True); 1094 1095 if (!*str && *p == '?') 1096 { 1097 while (*p == '?') p++; 1098 return(!*p); 1099 } 1100 1101 if(!*str && (*p == '*' && p[1] == '\0')) 1102 return True; 1103 return False; 1104} 1105 1106 1107/********************************************************* 1108* Routine to match a given string with a regexp - uses 1109* simplified regexp that takes * and ? only. Case can be 1110* significant or not. 1111* This is the 'original code' used by the unix matcher. 1112*********************************************************/ 1113 1114static BOOL unix_mask_match(char *str, char *regexp, BOOL case_sig) 1115{ 1116 char *p; 1117 pstring p1, p2; 1118 fstring ebase,sbase; 1119 BOOL matched; 1120 1121 /* Make local copies of str and regexp */ 1122 StrnCpy(p1,regexp,sizeof(pstring)-1); 1123 StrnCpy(p2,str,sizeof(pstring)-1); 1124 1125 /* Remove any *? and ** as they are meaningless */ 1126 for(p = p1; *p; p++) 1127 while( *p == '*' && (p[1] == '?' ||p[1] == '*')) 1128 (void)pstrcpy( &p[1], &p[2]); 1129 1130 if (strequal(p1,"*")) return(True); 1131 1132 DEBUG(8,("unix_mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); 1133 1134 fstrcpy(ebase,p1); 1135 fstrcpy(sbase,p2); 1136 1137 matched = unix_do_match(sbase,ebase,case_sig); 1138 1139 DEBUG(8,("unix_mask_match returning %d\n", matched)); 1140 1141 return matched; 1142} 1143 1144/********************************************************* 1145* Recursive routine that is called by mask_match. 1146* Does the actual matching. Returns True if matched, 1147* False if failed. This is the 'new' NT style matcher. 1148* The win9x_semantics parameter is needed as Win9x matching 1149* is *actually different*. In Win9x, trailing '?' characters 1150* will only match the *exact* number of characters. Under 1151* DOS and NT they match any number. This makes no 1152* sense..... 1153*********************************************************/ 1154 1155static BOOL do_match(char *str, char *regexp, int case_sig, BOOL win9x_semantics) 1156{ 1157 char *p; 1158 1159 for( p = regexp; *p && *str; ) { 1160 switch(*p) { 1161 case '?': 1162 str++; p++; 1163 break; 1164 1165 case '*': 1166 /* Look for a character matching 1167 the one after the '*' */ 1168 p++; 1169 if(!*p) 1170 return True; /* Automatic match */ 1171 while(*str) { 1172 while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) 1173 str++; 1174 1175 /* 1176 * Patch from weidel@multichart.de. In the case of the regexp 1177 * '*XX*' we want to ensure there are at least 2 'X' characters 1178 * in the filename after the '*' for a match to be made. 1179 */ 1180 1181 { 1182 int matchcount=0; 1183 1184 /* 1185 * Eat all the characters that match, but count how many there were. 1186 */ 1187 1188 while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str)))) { 1189 str++; 1190 matchcount++; 1191 } 1192 1193 /* 1194 * Now check that if the regexp had n identical characters that 1195 * matchcount had at least that many matches. 1196 */ 1197 1198 while (( *(p+1) && (case_sig ? (*(p+1) == *p) : (toupper(*(p+1))==toupper(*p))))) { 1199 p++; 1200 matchcount--; 1201 } 1202 if ( matchcount <= 0 ) { 1203 return False; 1204 } 1205 } 1206 str--; /* We've eaten the match char after the '*' */ 1207 if(do_match(str,p,case_sig,win9x_semantics)) { 1208 return True; 1209 } 1210 if(!*str) { 1211 return False; 1212 } else { 1213 str++; 1214 } 1215 } 1216 return False; 1217 1218 default: 1219 if(case_sig) { 1220 if(*str != *p) { 1221 return False; 1222 } 1223 } else { 1224 if(toupper(*str) != toupper(*p)) { 1225 return False; 1226 } 1227 } 1228 str++, p++; 1229 break; 1230 } 1231 } 1232 1233 if(!*p && !*str) 1234 return True; 1235 1236 if (!*p && str[0] == '.' && str[1] == 0) { 1237 return(True); 1238 } 1239 1240 if (!win9x_semantics) { 1241 if (!*str && *p == '?') { 1242 while (*p == '?') 1243 p++; 1244 return(!*p); 1245 } 1246 } 1247 1248 if(!*str && (*p == '*' && p[1] == '\0')) { 1249 return True; 1250 } 1251 1252 return False; 1253} 1254 1255/********************************************************* 1256* Routine to match a given string with a regexp - uses 1257* simplified regexp that takes * and ? only. Case can be 1258* significant or not. 1259* The 8.3 handling was rewritten by Ums Harald <Harald.Ums@pro-sieben.de> 1260* This is the new 'NT style' matcher. 1261*********************************************************/ 1262 1263BOOL mask_match(char *str, char *regexp, BOOL case_sig, BOOL trans2) 1264{ 1265 char *p; 1266 pstring t_pattern, t_filename, te_pattern, te_filename; 1267 fstring ebase,eext,sbase,sext; 1268 BOOL matched = False; 1269 BOOL win9x_semantics = (get_remote_arch() == RA_WIN95) && trans2; 1270 1271 /* special case - if it is exactly the same then it always matches! */ 1272 if(exact_match(str, regexp, case_sig)) 1273 return True; 1274 1275 /* Make local copies of str and regexp */ 1276 pstrcpy(t_pattern,regexp); 1277 pstrcpy(t_filename,str); 1278 1279 if(trans2) { 1280 1281 /* a special case for 16 bit apps */ 1282 if (strequal(t_pattern,"????????.???")) 1283 pstrcpy(t_pattern,"*"); 1284 1285#if 0 1286 /* 1287 * Handle broken clients that send us old 8.3 format. 1288 */ 1289 pstring_sub(t_pattern,"????????","*"); 1290 pstring_sub(t_pattern,".???",".*"); 1291#endif 1292 } 1293 1294#if 0 1295 /* 1296 * Not sure if this is a good idea. JRA. 1297 */ 1298 if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False)) 1299 trans2 = False; 1300#endif 1301 1302#if 0 1303 if (!strchr(t_filename,'.')) { 1304 pstrcat(t_filename,"."); 1305 } 1306#endif 1307 1308 /* Remove any *? and ** as they are meaningless */ 1309 while(all_string_sub(t_pattern, "*?", "*", sizeof(pstring))) 1310 ; 1311 1312 while(all_string_sub(t_pattern, "**", "*", sizeof(pstring))) 1313 ; 1314 1315 if (strequal(t_pattern,"*")) 1316 return(True); 1317 1318 DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig)); 1319 1320 if(trans2) { 1321 /* 1322 * Match each component of the regexp, split up by '.' 1323 * characters. 1324 */ 1325 char *fp, *rp, *cp2, *cp1; 1326 BOOL last_wcard_was_star = False; 1327 int num_path_components, num_regexp_components; 1328 1329 if(strequal(t_pattern, ".")) 1330 return False; /* A dot pattern never matches... ???? */ 1331 1332 /* 1333 * NT *always* treats '.' and '..' as identical for a match.... why ? 1334 */ 1335 1336 if(strequal(t_filename, "..")) 1337 pstrcpy(t_filename, "."); 1338 1339 pstrcpy(te_pattern,t_pattern); 1340 pstrcpy(te_filename,t_filename); 1341 /* 1342 * Remove multiple "*." patterns. 1343 */ 1344 while(all_string_sub(te_pattern, "*.*.", "*.", sizeof(pstring))) 1345 ; 1346 num_regexp_components = count_chars(te_pattern, '.'); 1347 num_path_components = count_chars(te_filename, '.'); 1348 1349 /* 1350 * Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z 1351 */ 1352 if(num_regexp_components == 0) 1353 matched = do_match( te_filename, te_pattern, case_sig, win9x_semantics); 1354 else { 1355 for( cp1 = te_pattern, cp2 = te_filename; cp1;) { 1356 fp = strchr(cp2, '.'); 1357 if(fp) 1358 *fp = '\0'; 1359 rp = strchr(cp1, '.'); 1360 if(rp) 1361 *rp = '\0'; 1362 1363 if(cp1[0] && cp1[strlen(cp1)-1] == '*') 1364 last_wcard_was_star = True; 1365 else 1366 last_wcard_was_star = False; 1367 1368 if(!do_match(cp2, cp1, case_sig, win9x_semantics)) 1369 break; 1370 1371 /* 1372 * Ugly ! Special case for Win9x *only*. If filename is XXXX and pattern extension 1373 * is '*' or all '?' then disallow match. 1374 */ 1375 1376 if (win9x_semantics) { 1377 if (*cp2 == '\0' && str_is_all(cp1, '?')) 1378 break; 1379 } 1380 1381 cp1 = rp ? rp + 1 : NULL; 1382 cp2 = fp ? fp + 1 : ""; 1383 1384 if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) { 1385 /* Eat the extra path components. */ 1386 int i; 1387 1388 for(i = 0; i < num_path_components - num_regexp_components; i++) { 1389 fp = strchr(cp2, '.'); 1390 if(fp) 1391 *fp = '\0'; 1392 1393 if((cp1 != NULL) && do_match( cp2, cp1, case_sig, win9x_semantics)) { 1394 cp2 = fp ? fp + 1 : ""; 1395 break; 1396 } 1397 cp2 = fp ? fp + 1 : ""; 1398 } 1399 num_path_components -= i; 1400 } 1401 } 1402 if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star)) 1403 matched = True; 1404 } 1405 } else { 1406 1407 /* ------------------------------------------------- 1408 * Behaviour of Win95 1409 * for 8.3 filenames and 8.3 Wildcards 1410 * ------------------------------------------------- 1411 */ 1412 if (strequal (t_filename, ".")) { 1413 /* 1414 * Patterns: *.* *. ?. ? ????????.??? are valid. 1415 * 1416 */ 1417 if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || 1418 strequal(t_pattern, "????????.???") || 1419 strequal(t_pattern, "?.") || strequal(t_pattern, "?")) 1420 matched = True; 1421 } else if (strequal (t_filename, "..")) { 1422 /* 1423 * Patterns: *.* *. ?. ? *.? ????????.??? are valid. 1424 * 1425 */ 1426 if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || 1427 strequal(t_pattern, "?.") || strequal(t_pattern, "?") || 1428 strequal(t_pattern, "????????.???") || 1429 strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*")) 1430 matched = True; 1431 } else { 1432 1433 if ((p = strrchr (t_pattern, '.'))) { 1434 /* 1435 * Wildcard has a suffix. 1436 */ 1437 *p = 0; 1438 fstrcpy (ebase, t_pattern); 1439 if (p[1]) { 1440 fstrcpy (eext, p + 1); 1441 } else { 1442 /* pattern ends in DOT: treat as if there is no DOT */ 1443 *eext = 0; 1444 if (strequal (ebase, "*")) 1445 return (True); 1446 } 1447 } else { 1448 /* 1449 * No suffix for wildcard. 1450 */ 1451 fstrcpy (ebase, t_pattern); 1452 eext[0] = 0; 1453 } 1454 1455 p = strrchr (t_filename, '.'); 1456 if (p && (p[1] == 0) ) { 1457 /* 1458 * Filename has an extension of '.' only. 1459 */ 1460 *p = 0; /* nuke dot at end of string */ 1461 p = 0; /* and treat it as if there is no extension */ 1462 } 1463 1464 if (p) { 1465 /* 1466 * Filename has an extension. 1467 */ 1468 *p = 0; 1469 fstrcpy (sbase, t_filename); 1470 fstrcpy (sext, p + 1); 1471 if (*eext) { 1472 matched = do_match(sbase, ebase, case_sig, False) 1473 && do_match(sext, eext, case_sig, False); 1474 } else { 1475 /* pattern has no extension */ 1476 /* Really: match complete filename with pattern ??? means exactly 3 chars */ 1477 matched = do_match(str, ebase, case_sig, False); 1478 } 1479 } else { 1480 /* 1481 * Filename has no extension. 1482 */ 1483 fstrcpy (sbase, t_filename); 1484 fstrcpy (sext, ""); 1485 if (*eext) { 1486 /* pattern has extension */ 1487 matched = do_match(sbase, ebase, case_sig, False) 1488 && do_match(sext, eext, case_sig, False); 1489 1490 } else { 1491 matched = do_match(sbase, ebase, case_sig, False); 1492#ifdef EMULATE_WEIRD_W95_MATCHING 1493 /* 1494 * Even Microsoft has some problems 1495 * Behaviour Win95 -> local disk 1496 * is different from Win95 -> smb drive from Nt 4.0 1497 * This branch would reflect the Win95 local disk behaviour 1498 */ 1499 if (!matched) { 1500 /* a? matches aa and a in w95 */ 1501 fstrcat (sbase, "."); 1502 matched = do_match(sbase, ebase, case_sig, False); 1503 } 1504#endif 1505 } 1506 } 1507 } 1508 } 1509 1510 DEBUG(8,("mask_match returning %d\n", matched)); 1511 1512 return matched; 1513} 1514 1515/**************************************************************************** 1516become a daemon, discarding the controlling terminal 1517****************************************************************************/ 1518void become_daemon(void) 1519{ 1520 if (fork()) { 1521 _exit(0); 1522 } 1523 1524 /* detach from the terminal */ 1525#ifdef HAVE_SETSID 1526 setsid(); 1527#elif defined(TIOCNOTTY) 1528 { 1529 int i = sys_open("/dev/tty", O_RDWR, 0); 1530 if (i != -1) { 1531 ioctl(i, (int) TIOCNOTTY, (char *)0); 1532 close(i); 1533 } 1534 } 1535#endif /* HAVE_SETSID */ 1536 1537 /* Close fd's 0,1,2. Needed if started by rsh */ 1538 close_low_fds(); 1539} 1540 1541 1542/**************************************************************************** 1543put up a yes/no prompt 1544****************************************************************************/ 1545BOOL yesno(char *p) 1546{ 1547 pstring ans; 1548 printf("%s",p); 1549 1550 if (!fgets(ans,sizeof(ans)-1,stdin)) 1551 return(False); 1552 1553 if (*ans == 'y' || *ans == 'Y') 1554 return(True); 1555 1556 return(False); 1557} 1558 1559/**************************************************************************** 1560set the length of a file from a filedescriptor. 1561Returns 0 on success, -1 on failure. 1562****************************************************************************/ 1563 1564int set_filelen(int fd, SMB_OFF_T len) 1565{ 1566/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot 1567 extend a file with ftruncate. Provide alternate implementation 1568 for this */ 1569 1570#ifdef HAVE_FTRUNCATE_EXTEND 1571 return sys_ftruncate(fd, len); 1572#else 1573 SMB_STRUCT_STAT st; 1574 char c = 0; 1575 SMB_OFF_T currpos = sys_lseek(fd, (SMB_OFF_T)0, SEEK_CUR); 1576 1577 if(currpos == -1) 1578 return -1; 1579 /* Do an fstat to see if the file is longer than 1580 the requested size (call ftruncate), 1581 or shorter, in which case seek to len - 1 and write 1 1582 byte of zero */ 1583 if(sys_fstat(fd, &st)<0) 1584 return -1; 1585 1586#ifdef S_ISFIFO 1587 if (S_ISFIFO(st.st_mode)) 1588 return 0; 1589#endif 1590 1591 if(st.st_size == len) 1592 return 0; 1593 if(st.st_size > len) 1594 return sys_ftruncate(fd, len); 1595 1596 if(sys_lseek(fd, len-1, SEEK_SET) != len -1) 1597 return -1; 1598 if(write(fd, &c, 1)!=1) 1599 return -1; 1600 /* Seek to where we were */ 1601 if(sys_lseek(fd, currpos, SEEK_SET) != currpos) 1602 return -1; 1603 return 0; 1604#endif 1605} 1606 1607 1608#ifdef HPUX 1609/**************************************************************************** 1610this is a version of setbuffer() for those machines that only have setvbuf 1611****************************************************************************/ 1612 void setbuffer(FILE *f,char *buf,int bufsize) 1613{ 1614 setvbuf(f,buf,_IOFBF,bufsize); 1615} 1616#endif 1617 1618 1619/**************************************************************************** 1620parse out a filename from a path name. Assumes dos style filenames. 1621****************************************************************************/ 1622static char *filename_dos(char *path,char *buf) 1623{ 1624 char *p = strrchr(path,'\\'); 1625 1626 if (!p) 1627 pstrcpy(buf,path); 1628 else 1629 pstrcpy(buf,p+1); 1630 1631 return(buf); 1632} 1633 1634 1635 1636/**************************************************************************** 1637expand a pointer to be a particular size 1638****************************************************************************/ 1639void *Realloc(void *p,size_t size) 1640{ 1641 void *ret=NULL; 1642 1643 if (size == 0) { 1644 if (p) free(p); 1645 DEBUG(5,("Realloc asked for 0 bytes\n")); 1646 return NULL; 1647 } 1648 1649 if (!p) 1650 ret = (void *)malloc(size); 1651 else 1652 ret = (void *)realloc(p,size); 1653 1654#ifdef MEM_MAN 1655 { 1656 extern FILE *dbf; 1657 smb_mem_write_info(ret, dbf); 1658 } 1659#endif 1660 1661 if (!ret) 1662 DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",(int)size)); 1663 1664 return(ret); 1665} 1666 1667 1668/**************************************************************************** 1669get my own name and IP 1670****************************************************************************/ 1671BOOL get_myname(char *my_name) 1672{ 1673 pstring hostname; 1674 1675 *hostname = 0; 1676 1677 /* get my host name */ 1678 if (gethostname(hostname, sizeof(hostname)) == -1) { 1679 DEBUG(0,("gethostname failed\n")); 1680 return False; 1681 } 1682 1683 /* Ensure null termination. */ 1684 hostname[sizeof(hostname)-1] = '\0'; 1685 1686 if (my_name) { 1687 /* split off any parts after an initial . */ 1688 char *p = strchr(hostname,'.'); 1689 if (p) *p = 0; 1690 1691 fstrcpy(my_name,hostname); 1692 } 1693 1694 return(True); 1695} 1696 1697/**************************************************************************** 1698interpret a protocol description string, with a default 1699****************************************************************************/ 1700int interpret_protocol(char *str,int def) 1701{ 1702 if (strequal(str,"NT1")) 1703 return(PROTOCOL_NT1); 1704 if (strequal(str,"LANMAN2")) 1705 return(PROTOCOL_LANMAN2); 1706 if (strequal(str,"LANMAN1")) 1707 return(PROTOCOL_LANMAN1); 1708 if (strequal(str,"CORE")) 1709 return(PROTOCOL_CORE); 1710 if (strequal(str,"COREPLUS")) 1711 return(PROTOCOL_COREPLUS); 1712 if (strequal(str,"CORE+")) 1713 return(PROTOCOL_COREPLUS); 1714 1715 DEBUG(0,("Unrecognised protocol level %s\n",str)); 1716 1717 return(def); 1718} 1719 1720/**************************************************************************** 1721 Return true if a string could be a pure IP address. 1722****************************************************************************/ 1723 1724BOOL is_ipaddress(const char *str) 1725{ 1726 BOOL pure_address = True; 1727 int i; 1728 1729 for (i=0; pure_address && str[i]; i++) 1730 if (!(isdigit((int)str[i]) || str[i] == '.')) 1731 pure_address = False; 1732 1733 /* Check that a pure number is not misinterpreted as an IP */ 1734 pure_address = pure_address && (strchr(str, '.') != NULL); 1735 1736 return pure_address; 1737} 1738 1739/**************************************************************************** 1740interpret an internet address or name into an IP address in 4 byte form 1741****************************************************************************/ 1742 1743uint32 interpret_addr(char *str) 1744{ 1745 struct hostent *hp; 1746 uint32 res; 1747 1748 if (strcmp(str,"0.0.0.0") == 0) return(0); 1749 if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF); 1750 1751 /* if it's in the form of an IP address then get the lib to interpret it */ 1752 if (is_ipaddress(str)) { 1753 res = inet_addr(str); 1754 } else { 1755 /* otherwise assume it's a network name of some sort and use 1756 Get_Hostbyname */ 1757 if ((hp = Get_Hostbyname(str)) == 0) { 1758 DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str)); 1759 return 0; 1760 } 1761 if(hp->h_addr == NULL) { 1762 DEBUG(3,("Get_Hostbyname: host address is invalid for host %s\n",str)); 1763 return 0; 1764 } 1765 putip((char *)&res,(char *)hp->h_addr); 1766 } 1767 1768 if (res == (uint32)-1) return(0); 1769 1770 return(res); 1771} 1772 1773/******************************************************************* 1774 a convenient addition to interpret_addr() 1775 ******************************************************************/ 1776struct in_addr *interpret_addr2(char *str) 1777{ 1778 static struct in_addr ret; 1779 uint32 a = interpret_addr(str); 1780 ret.s_addr = a; 1781 return(&ret); 1782} 1783 1784/******************************************************************* 1785 check if an IP is the 0.0.0.0 1786 ******************************************************************/ 1787BOOL zero_ip(struct in_addr ip) 1788{ 1789 uint32 a; 1790 putip((char *)&a,(char *)&ip); 1791 return(a == 0); 1792} 1793 1794 1795/******************************************************************* 1796 matchname - determine if host name matches IP address 1797 ******************************************************************/ 1798BOOL matchname(char *remotehost,struct in_addr addr) 1799{ 1800 struct hostent *hp; 1801 int i; 1802 1803 if ((hp = Get_Hostbyname(remotehost)) == 0) { 1804 DEBUG(0,("Get_Hostbyname(%s): lookup failure.\n", remotehost)); 1805 return False; 1806 } 1807 1808 /* 1809 * Make sure that gethostbyname() returns the "correct" host name. 1810 * Unfortunately, gethostbyname("localhost") sometimes yields 1811 * "localhost.domain". Since the latter host name comes from the 1812 * local DNS, we just have to trust it (all bets are off if the local 1813 * DNS is perverted). We always check the address list, though. 1814 */ 1815 1816 if (strcasecmp(remotehost, hp->h_name) 1817 && strcasecmp(remotehost, "localhost")) { 1818 DEBUG(0,("host name/name mismatch: %s != %s\n", 1819 remotehost, hp->h_name)); 1820 return False; 1821 } 1822 1823 /* Look up the host address in the address list we just got. */ 1824 for (i = 0; hp->h_addr_list[i]; i++) { 1825 if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0) 1826 return True; 1827 } 1828 1829 /* 1830 * The host name does not map to the original host address. Perhaps 1831 * someone has compromised a name server. More likely someone botched 1832 * it, but that could be dangerous, too. 1833 */ 1834 1835 DEBUG(0,("host name/address mismatch: %s != %s\n", 1836 inet_ntoa(addr), hp->h_name)); 1837 return False; 1838} 1839 1840 1841#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT)) 1842/****************************************************************** 1843 Remove any mount options such as -rsize=2048,wsize=2048 etc. 1844 Based on a fix from <Thomas.Hepper@icem.de>. 1845*******************************************************************/ 1846 1847static void strip_mount_options( pstring *str) 1848{ 1849 if (**str == '-') 1850 { 1851 char *p = *str; 1852 while(*p && !isspace(*p)) 1853 p++; 1854 while(*p && isspace(*p)) 1855 p++; 1856 if(*p) { 1857 pstring tmp_str; 1858 1859 pstrcpy(tmp_str, p); 1860 pstrcpy(*str, tmp_str); 1861 } 1862 } 1863} 1864 1865/******************************************************************* 1866 Patch from jkf@soton.ac.uk 1867 Split Luke's automount_server into YP lookup and string splitter 1868 so can easily implement automount_path(). 1869 As we may end up doing both, cache the last YP result. 1870*******************************************************************/ 1871 1872#ifdef WITH_NISPLUS_HOME 1873static char *automount_lookup(char *user_name) 1874{ 1875 static fstring last_key = ""; 1876 static pstring last_value = ""; 1877 1878 char *nis_map = (char *)lp_nis_home_map_name(); 1879 1880 char nis_domain[NIS_MAXNAMELEN + 1]; 1881 char buffer[NIS_MAXATTRVAL + 1]; 1882 nis_result *result; 1883 nis_object *object; 1884 entry_obj *entry; 1885 1886 strncpy(nis_domain, (char *)nis_local_directory(), NIS_MAXNAMELEN); 1887 nis_domain[NIS_MAXNAMELEN] = '\0'; 1888 1889 DEBUG(5, ("NIS+ Domain: %s\n", nis_domain)); 1890 1891 if (strcmp(user_name, last_key)) 1892 { 1893 slprintf(buffer, sizeof(buffer)-1, "[%s=%s]%s.%s", "key", user_name, nis_map, nis_domain); 1894 DEBUG(5, ("NIS+ querystring: %s\n", buffer)); 1895 1896 if (result = nis_list(buffer, RETURN_RESULT, NULL, NULL)) 1897 { 1898 if (result->status != NIS_SUCCESS) 1899 { 1900 DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status))); 1901 fstrcpy(last_key, ""); pstrcpy(last_value, ""); 1902 } 1903 else 1904 { 1905 object = result->objects.objects_val; 1906 if (object->zo_data.zo_type == ENTRY_OBJ) 1907 { 1908 entry = &object->zo_data.objdata_u.en_data; 1909 DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type)); 1910 DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val)); 1911 1912 pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val); 1913 pstring_sub(last_value, "&", user_name); 1914 fstrcpy(last_key, user_name); 1915 } 1916 } 1917 } 1918 nis_freeresult(result); 1919 } 1920 1921 strip_mount_options(&last_value); 1922 1923 DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value)); 1924 return last_value; 1925} 1926#else /* WITH_NISPLUS_HOME */ 1927static char *automount_lookup(char *user_name) 1928{ 1929 static fstring last_key = ""; 1930 static pstring last_value = ""; 1931 1932 int nis_error; /* returned by yp all functions */ 1933 char *nis_result; /* yp_match inits this */ 1934 int nis_result_len; /* and set this */ 1935 char *nis_domain; /* yp_get_default_domain inits this */ 1936 char *nis_map = (char *)lp_nis_home_map_name(); 1937 1938 if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) 1939 { 1940 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); 1941 return last_value; 1942 } 1943 1944 DEBUG(5, ("NIS Domain: %s\n", nis_domain)); 1945 1946 if (!strcmp(user_name, last_key)) 1947 { 1948 nis_result = last_value; 1949 nis_result_len = strlen(last_value); 1950 nis_error = 0; 1951 } 1952 else 1953 { 1954 if ((nis_error = yp_match(nis_domain, nis_map, 1955 user_name, strlen(user_name), 1956 &nis_result, &nis_result_len)) != 0) 1957 { 1958 DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n", 1959 yperr_string(nis_error), user_name, nis_map)); 1960 } 1961 if (!nis_error && nis_result_len >= sizeof(pstring)) 1962 { 1963 nis_result_len = sizeof(pstring)-1; 1964 } 1965 fstrcpy(last_key, user_name); 1966 strncpy(last_value, nis_result, nis_result_len); 1967 last_value[nis_result_len] = '\0'; 1968 } 1969 1970 strip_mount_options(&last_value); 1971 1972 DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value)); 1973 return last_value; 1974} 1975#endif /* WITH_NISPLUS_HOME */ 1976#endif 1977 1978/******************************************************************* 1979 Patch from jkf@soton.ac.uk 1980 This is Luke's original function with the NIS lookup code 1981 moved out to a separate function. 1982*******************************************************************/ 1983static char *automount_server(char *user_name) 1984{ 1985 static pstring server_name; 1986 1987 /* use the local machine name as the default */ 1988 /* this will be the default if WITH_AUTOMOUNT is not used or fails */ 1989 pstrcpy(server_name, local_machine); 1990 1991#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) 1992 1993 if (lp_nis_home_map()) 1994 { 1995 int home_server_len; 1996 char *automount_value = automount_lookup(user_name); 1997 home_server_len = strcspn(automount_value,":"); 1998 DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len)); 1999 if (home_server_len > sizeof(pstring)) 2000 { 2001 home_server_len = sizeof(pstring); 2002 } 2003 strncpy(server_name, automount_value, home_server_len); 2004 server_name[home_server_len] = '\0'; 2005 } 2006#endif 2007 2008 DEBUG(4,("Home server: %s\n", server_name)); 2009 2010 return server_name; 2011} 2012 2013/******************************************************************* 2014 Patch from jkf@soton.ac.uk 2015 Added this to implement %p (NIS auto-map version of %H) 2016*******************************************************************/ 2017static char *automount_path(char *user_name) 2018{ 2019 static pstring server_path; 2020 2021 /* use the passwd entry as the default */ 2022 /* this will be the default if WITH_AUTOMOUNT is not used or fails */ 2023 /* pstrcpy() copes with get_user_home_dir() returning NULL */ 2024 pstrcpy(server_path, get_user_home_dir(user_name)); 2025 2026#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) 2027 2028 if (lp_nis_home_map()) 2029 { 2030 char *home_path_start; 2031 char *automount_value = automount_lookup(user_name); 2032 home_path_start = strchr(automount_value,':'); 2033 if (home_path_start != NULL) 2034 { 2035 DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n", 2036 home_path_start?(home_path_start+1):"")); 2037 pstrcpy(server_path, home_path_start+1); 2038 } 2039 } 2040#endif 2041 2042 DEBUG(4,("Home server path: %s\n", server_path)); 2043 2044 return server_path; 2045} 2046 2047/******************************************************************* 2048 Given a pointer to a %$(NAME) expand it as an environment variable. 2049 Return the number of characters by which the pointer should be advanced. 2050 Based on code by Branko Cibej <branko.cibej@hermes.si> 2051 When this is called p points at the '%' character. 2052********************************************************************/ 2053 2054static size_t expand_env_var(char *p, int len) 2055{ 2056 fstring envname; 2057 char *envval; 2058 char *q, *r; 2059 int copylen; 2060 2061 if (p[1] != '$') 2062 return 1; 2063 2064 if (p[2] != '(') 2065 return 2; 2066 2067 /* 2068 * Look for the terminating ')'. 2069 */ 2070 2071 if ((q = strchr(p,')')) == NULL) { 2072 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p)); 2073 return 2; 2074 } 2075 2076 /* 2077 * Extract the name from within the %$(NAME) string. 2078 */ 2079 2080 r = p+3; 2081 copylen = MIN((q-r),(sizeof(envname)-1)); 2082 strncpy(envname,r,copylen); 2083 envname[copylen] = '\0'; 2084 2085 if ((envval = getenv(envname)) == NULL) { 2086 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname)); 2087 return 2; 2088 } 2089 2090 /* 2091 * Copy the full %$(NAME) into envname so it 2092 * can be replaced. 2093 */ 2094 2095 copylen = MIN((q+1-p),(sizeof(envname)-1)); 2096 strncpy(envname,p,copylen); 2097 envname[copylen] = '\0'; 2098 string_sub(p,envname,envval,len); 2099 return 0; /* Allow the environment contents to be parsed. */ 2100} 2101 2102/******************************************************************* 2103 Substitute strings with useful parameters. 2104 Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and 2105 Paul Rippin <pr3245@nopc.eurostat.cec.be>. 2106********************************************************************/ 2107 2108void standard_sub_basic(char *str) 2109{ 2110 char *s, *p; 2111 char pidstr[10]; 2112 struct passwd *pass; 2113 char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user; 2114 2115 for (s = str ; s && *s && (p = strchr(s,'%')); s = p ) 2116 { 2117 int l = sizeof(pstring) - (int)(p-str); 2118 2119 if (l < 0) { 2120 DEBUG(0,("ERROR: string overflow by %d in standard_sub_basic(%.50s)\n", 2121 -l, str)); 2122 2123 return; 2124 } 2125 2126 switch (*(p+1)) 2127 { 2128 case 'G' : 2129 { 2130 if ((pass = Get_Pwnam(username,False))!=NULL) { 2131 string_sub(p,"%G",gidtoname(pass->pw_gid),l); 2132 } else { 2133 p += 2; 2134 } 2135 break; 2136 } 2137 case 'N' : string_sub(p,"%N", automount_server(username),l); break; 2138 case 'I' : string_sub(p,"%I", client_addr(Client),l); break; 2139 case 'L' : string_sub(p,"%L", local_machine,l); break; 2140 case 'M' : string_sub(p,"%M", client_name(Client),l); break; 2141 case 'R' : string_sub(p,"%R", remote_proto,l); break; 2142 case 'T' : string_sub(p,"%T", timestring(False),l); break; 2143 case 'U' : string_sub(p,"%U", username,l); break; 2144 case 'a' : string_sub(p,"%a", remote_arch,l); break; 2145 case 'd' : 2146 { 2147 slprintf(pidstr,sizeof(pidstr) - 1, "%d",(int)getpid()); 2148 string_sub(p,"%d", pidstr,l); 2149 break; 2150 } 2151 case 'h' : string_sub(p,"%h", myhostname(),l); break; 2152 case 'm' : string_sub(p,"%m", remote_machine,l); break; 2153 case 'v' : string_sub(p,"%v", VERSION,l); break; 2154 case '$' : p += expand_env_var(p,l); break; /* Expand environment variables */ 2155 case '\0': p++; break; /* don't run off end if last character is % */ 2156 default : p+=2; break; 2157 } 2158 } 2159 return; 2160} 2161 2162 2163/**************************************************************************** 2164 Do some standard substitutions in a string. 2165****************************************************************************/ 2166 2167void standard_sub(connection_struct *conn,char *str) 2168{ 2169 char *p, *s, *home; 2170 2171 for (s=str; (p=strchr(s, '%'));s=p) { 2172 int l = sizeof(pstring) - (int)(p-str); 2173 2174 switch (*(p+1)) { 2175 case 'H': 2176 if ((home = get_user_home_dir(conn->user))) { 2177 string_sub(p,"%H",home,l); 2178 } else { 2179 p += 2; 2180 } 2181 break; 2182 2183 case 'P': 2184 string_sub(p,"%P",conn->connectpath,l); 2185 break; 2186 2187 case 'S': 2188 string_sub(p,"%S", 2189 lp_servicename(SNUM(conn)),l); 2190 break; 2191 2192 case 'g': 2193 string_sub(p,"%g", 2194 gidtoname(conn->gid),l); 2195 break; 2196 case 'u': 2197 string_sub(p,"%u",conn->user,l); 2198 break; 2199 2200 /* Patch from jkf@soton.ac.uk Left the %N (NIS 2201 * server name) in standard_sub_basic as it is 2202 * a feature for logon servers, hence uses the 2203 * username. The %p (NIS server path) code is 2204 * here as it is used instead of the default 2205 * "path =" string in [homes] and so needs the 2206 * service name, not the username. */ 2207 case 'p': 2208 string_sub(p,"%p", 2209 automount_path(lp_servicename(SNUM(conn))),l); 2210 break; 2211 case '\0': 2212 p++; 2213 break; /* don't run off the end of the string 2214 */ 2215 2216 default: p+=2; 2217 break; 2218 } 2219 } 2220 2221 standard_sub_basic(str); 2222} 2223 2224 2225 2226/******************************************************************* 2227are two IPs on the same subnet? 2228********************************************************************/ 2229BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) 2230{ 2231 uint32 net1,net2,nmask; 2232 2233 nmask = ntohl(mask.s_addr); 2234 net1 = ntohl(ip1.s_addr); 2235 net2 = ntohl(ip2.s_addr); 2236 2237 return((net1 & nmask) == (net2 & nmask)); 2238} 2239 2240 2241/**************************************************************************** 2242a wrapper for gethostbyname() that tries with all lower and all upper case 2243if the initial name fails 2244****************************************************************************/ 2245struct hostent *Get_Hostbyname(const char *name) 2246{ 2247 char *name2 = strdup(name); 2248 struct hostent *ret; 2249 2250 if (!name2) 2251 { 2252 DEBUG(0,("Memory allocation error in Get_Hostbyname! panic\n")); 2253 exit(0); 2254 } 2255 2256 2257 /* 2258 * This next test is redundent and causes some systems (with 2259 * broken isalnum() calls) problems. 2260 * JRA. 2261 */ 2262 2263#if 0 2264 if (!isalnum(*name2)) 2265 { 2266 free(name2); 2267 return(NULL); 2268 } 2269#endif /* 0 */ 2270 2271 ret = sys_gethostbyname(name2); 2272 if (ret != NULL) 2273 { 2274 free(name2); 2275 return(ret); 2276 } 2277 2278 /* try with all lowercase */ 2279 strlower(name2); 2280 ret = sys_gethostbyname(name2); 2281 if (ret != NULL) 2282 { 2283 free(name2); 2284 return(ret); 2285 } 2286 2287 /* try with all uppercase */ 2288 strupper(name2); 2289 ret = sys_gethostbyname(name2); 2290 if (ret != NULL) 2291 { 2292 free(name2); 2293 return(ret); 2294 } 2295 2296 /* nothing works :-( */ 2297 free(name2); 2298 return(NULL); 2299} 2300 2301 2302/**************************************************************************** 2303check if a process exists. Does this work on all unixes? 2304****************************************************************************/ 2305 2306BOOL process_exists(pid_t pid) 2307{ 2308 return(kill(pid,0) == 0 || errno != ESRCH); 2309} 2310 2311 2312/******************************************************************* 2313turn a uid into a user name 2314********************************************************************/ 2315char *uidtoname(uid_t uid) 2316{ 2317 static char name[40]; 2318 struct passwd *pass = sys_getpwuid(uid); 2319 if (pass) return(pass->pw_name); 2320 slprintf(name, sizeof(name) - 1, "%d",(int)uid); 2321 return(name); 2322} 2323 2324 2325/******************************************************************* 2326turn a gid into a group name 2327********************************************************************/ 2328 2329char *gidtoname(gid_t gid) 2330{ 2331 static char name[40]; 2332 struct group *grp = getgrgid(gid); 2333 if (grp) return(grp->gr_name); 2334 slprintf(name,sizeof(name) - 1, "%d",(int)gid); 2335 return(name); 2336} 2337 2338/******************************************************************* 2339turn a user name into a uid 2340********************************************************************/ 2341uid_t nametouid(const char *name) 2342{ 2343 struct passwd *pass; 2344 char *p; 2345 uid_t u; 2346 2347 u = strtol(name, &p, 0); 2348 if (p != name) return u; 2349 2350 pass = sys_getpwnam(name); 2351 if (pass) return(pass->pw_uid); 2352 return (uid_t)-1; 2353} 2354 2355/******************************************************************* 2356turn a group name into a gid 2357********************************************************************/ 2358gid_t nametogid(const char *name) 2359{ 2360 struct group *grp; 2361 char *p; 2362 gid_t g; 2363 2364 g = strtol(name, &p, 0); 2365 if (p != name) return g; 2366 2367 grp = getgrnam(name); 2368 if (grp) return(grp->gr_gid); 2369 return (gid_t)-1; 2370} 2371 2372/******************************************************************* 2373something really nasty happened - panic! 2374********************************************************************/ 2375void smb_panic(char *why) 2376{ 2377 char *cmd = lp_panic_action(); 2378 if (cmd && *cmd) { 2379 system(cmd); 2380 } 2381 DEBUG(0,("PANIC: %s\n", why)); 2382 dbgflush(); 2383 abort(); 2384} 2385 2386 2387/******************************************************************* 2388a readdir wrapper which just returns the file name 2389********************************************************************/ 2390char *readdirname(DIR *p) 2391{ 2392 SMB_STRUCT_DIRENT *ptr; 2393 char *dname; 2394 2395 if (!p) return(NULL); 2396 2397 ptr = (SMB_STRUCT_DIRENT *)sys_readdir(p); 2398 if (!ptr) return(NULL); 2399 2400 dname = ptr->d_name; 2401 2402#ifdef NEXT2 2403 if (telldir(p) < 0) return(NULL); 2404#endif 2405 2406#ifdef HAVE_BROKEN_READDIR 2407 /* using /usr/ucb/cc is BAD */ 2408 dname = dname - 2; 2409#endif 2410 2411 { 2412 static pstring buf; 2413 memcpy(buf, dname, NAMLEN(ptr)+1); 2414 dname = buf; 2415 } 2416 2417 return(dname); 2418} 2419 2420/******************************************************************* 2421 Utility function used to decide if the last component 2422 of a path matches a (possibly wildcarded) entry in a namelist. 2423********************************************************************/ 2424 2425BOOL is_in_path(char *name, name_compare_entry *namelist) 2426{ 2427 pstring last_component; 2428 char *p; 2429 2430 DEBUG(8, ("is_in_path: %s\n", name)); 2431 2432 /* if we have no list it's obviously not in the path */ 2433 if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) 2434 { 2435 DEBUG(8,("is_in_path: no name list.\n")); 2436 return False; 2437 } 2438 2439 /* Get the last component of the unix name. */ 2440 p = strrchr(name, '/'); 2441 strncpy(last_component, p ? ++p : name, sizeof(last_component)-1); 2442 last_component[sizeof(last_component)-1] = '\0'; 2443 2444 for(; namelist->name != NULL; namelist++) 2445 { 2446 if(namelist->is_wild) 2447 { 2448 /* 2449 * Look for a wildcard match. Use the old 2450 * 'unix style' mask match, rather than the 2451 * new NT one. 2452 */ 2453 if (unix_mask_match(last_component, namelist->name, case_sensitive)) 2454 { 2455 DEBUG(8,("is_in_path: mask match succeeded\n")); 2456 return True; 2457 } 2458 } 2459 else 2460 { 2461 if((case_sensitive && (strcmp(last_component, namelist->name) == 0))|| 2462 (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0))) 2463 { 2464 DEBUG(8,("is_in_path: match succeeded\n")); 2465 return True; 2466 } 2467 } 2468 } 2469 DEBUG(8,("is_in_path: match not found\n")); 2470 2471 return False; 2472} 2473 2474/******************************************************************* 2475 Strip a '/' separated list into an array of 2476 name_compare_enties structures suitable for 2477 passing to is_in_path(). We do this for 2478 speed so we can pre-parse all the names in the list 2479 and don't do it for each call to is_in_path(). 2480 namelist is modified here and is assumed to be 2481 a copy owned by the caller. 2482 We also check if the entry contains a wildcard to 2483 remove a potentially expensive call to mask_match 2484 if possible. 2485********************************************************************/ 2486 2487void set_namearray(name_compare_entry **ppname_array, char *namelist) 2488{ 2489 char *name_end; 2490 char *nameptr = namelist; 2491 int num_entries = 0; 2492 int i; 2493 2494 (*ppname_array) = NULL; 2495 2496 if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) 2497 return; 2498 2499 /* We need to make two passes over the string. The 2500 first to count the number of elements, the second 2501 to split it. 2502 */ 2503 while(*nameptr) 2504 { 2505 if ( *nameptr == '/' ) 2506 { 2507 /* cope with multiple (useless) /s) */ 2508 nameptr++; 2509 continue; 2510 } 2511 /* find the next / */ 2512 name_end = strchr(nameptr, '/'); 2513 2514 /* oops - the last check for a / didn't find one. */ 2515 if (name_end == NULL) 2516 break; 2517 2518 /* next segment please */ 2519 nameptr = name_end + 1; 2520 num_entries++; 2521 } 2522 2523 if(num_entries == 0) 2524 return; 2525 2526 if(( (*ppname_array) = (name_compare_entry *)malloc( 2527 (num_entries + 1) * sizeof(name_compare_entry))) == NULL) 2528 { 2529 DEBUG(0,("set_namearray: malloc fail\n")); 2530 return; 2531 } 2532 2533 /* Now copy out the names */ 2534 nameptr = namelist; 2535 i = 0; 2536 while(*nameptr) 2537 { 2538 if ( *nameptr == '/' ) 2539 { 2540 /* cope with multiple (useless) /s) */ 2541 nameptr++; 2542 continue; 2543 } 2544 /* find the next / */ 2545 if ((name_end = strchr(nameptr, '/')) != NULL) 2546 { 2547 *name_end = 0; 2548 } 2549 2550 /* oops - the last check for a / didn't find one. */ 2551 if(name_end == NULL) 2552 break; 2553 2554 (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) || 2555 (strchr( nameptr, '*')!=NULL)); 2556 if(((*ppname_array)[i].name = strdup(nameptr)) == NULL) 2557 { 2558 DEBUG(0,("set_namearray: malloc fail (1)\n")); 2559 return; 2560 } 2561 2562 /* next segment please */ 2563 nameptr = name_end + 1; 2564 i++; 2565 } 2566 2567 (*ppname_array)[i].name = NULL; 2568 2569 return; 2570} 2571 2572/**************************************************************************** 2573routine to free a namearray. 2574****************************************************************************/ 2575 2576void free_namearray(name_compare_entry *name_array) 2577{ 2578 if(name_array == 0) 2579 return; 2580 2581 if(name_array->name != NULL) 2582 free(name_array->name); 2583 2584 free((char *)name_array); 2585} 2586 2587/**************************************************************************** 2588 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-). 2589****************************************************************************/ 2590 2591uint32 map_lock_offset(uint32 high, uint32 low) 2592{ 2593 unsigned int i; 2594 uint32 mask = 0; 2595 uint32 highcopy = high; 2596 2597 /* 2598 * Try and find out how many significant bits there are in high. 2599 */ 2600 2601 for(i = 0; highcopy; i++) 2602 highcopy >>= 1; 2603 2604 /* 2605 * We use 31 bits not 32 here as POSIX 2606 * lock offsets may not be negative. 2607 */ 2608 2609 mask = (~0) << (31 - i); 2610 2611 if(low & mask) 2612 return 0; /* Fail. */ 2613 2614 high <<= (31 - i); 2615 2616 return (high|low); 2617} 2618 2619/**************************************************************************** 2620routine to do file locking 2621****************************************************************************/ 2622 2623BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) 2624{ 2625#if HAVE_FCNTL_LOCK 2626 SMB_STRUCT_FLOCK lock; 2627 int ret; 2628#if defined(LARGE_SMB_OFF_T) 2629 /* 2630 * In the 64 bit locking case we store the original 2631 * values in case we have to map to a 32 bit lock on 2632 * a filesystem that doesn't support 64 bit locks. 2633 */ 2634 SMB_OFF_T orig_offset = offset; 2635 SMB_OFF_T orig_count = count; 2636#endif /* LARGE_SMB_OFF_T */ 2637 2638 if(lp_ole_locking_compat()) { 2639 SMB_OFF_T mask2= ((SMB_OFF_T)0x3) << (SMB_OFF_T_BITS-4); 2640 SMB_OFF_T mask = (mask2<<2); 2641 2642 /* make sure the count is reasonable, we might kill the lockd otherwise */ 2643 count &= ~mask; 2644 2645 /* the offset is often strange - remove 2 of its bits if either of 2646 the top two bits are set. Shift the top ones by two bits. This 2647 still allows OLE2 apps to operate, but should stop lockd from 2648 dieing */ 2649 if ((offset & mask) != 0) 2650 offset = (offset & ~mask) | (((offset & mask) >> 2) & mask2); 2651 } else { 2652 SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4); 2653 SMB_OFF_T mask = (mask2<<1); 2654 SMB_OFF_T neg_mask = ~mask; 2655 2656 /* interpret negative counts as large numbers */ 2657 if (count < 0) 2658 count &= ~mask; 2659 2660 /* no negative offsets */ 2661 if(offset < 0) 2662 offset &= ~mask; 2663 2664 /* count + offset must be in range */ 2665 while ((offset < 0 || (offset + count < 0)) && mask) 2666 { 2667 offset &= ~mask; 2668 mask = ((mask >> 1) & neg_mask); 2669 } 2670 } 2671 2672 DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type)); 2673 2674 lock.l_type = type; 2675 lock.l_whence = SEEK_SET; 2676 lock.l_start = offset; 2677 lock.l_len = count; 2678 lock.l_pid = 0; 2679 2680 errno = 0; 2681 2682 ret = fcntl(fd,op,&lock); 2683 if (errno == EFBIG) 2684 { 2685 if( DEBUGLVL( 0 )) 2686 { 2687 dbgtext("fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n", (double)offset,(double)count); 2688 dbgtext("a 'file too large' error. This can happen when using 64 bit lock offsets\n"); 2689 dbgtext("on 32 bit NFS mounted file systems. Retrying with 32 bit truncated length.\n"); 2690 } 2691 /* 32 bit NFS file system, retry with smaller offset */ 2692 errno = 0; 2693 lock.l_len = count & 0x7fffffff; 2694 ret = fcntl(fd,op,&lock); 2695 } 2696 2697 if (errno != 0) 2698 DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); 2699 2700 /* a lock query */ 2701 if (op == SMB_F_GETLK) 2702 { 2703 if ((ret != -1) && 2704 (lock.l_type != F_UNLCK) && 2705 (lock.l_pid != 0) && 2706 (lock.l_pid != getpid())) 2707 { 2708 DEBUG(3,("fd %d is locked by pid %d\n",fd,(int)lock.l_pid)); 2709 return(True); 2710 } 2711 2712 /* it must be not locked or locked by me */ 2713 return(False); 2714 } 2715 2716 /* a lock set or unset */ 2717 if (ret == -1) 2718 { 2719 DEBUG(3,("lock failed at offset %.0f count %.0f op %d type %d (%s)\n", 2720 (double)offset,(double)count,op,type,strerror(errno))); 2721 2722 /* perhaps it doesn't support this sort of locking?? */ 2723 if (errno == EINVAL) 2724 { 2725 2726#if defined(LARGE_SMB_OFF_T) 2727 { 2728 /* 2729 * Ok - if we get here then we have a 64 bit lock request 2730 * that has returned EINVAL. Try and map to 31 bits for offset 2731 * and length and try again. This may happen if a filesystem 2732 * doesn't support 64 bit offsets (efs/ufs) although the underlying 2733 * OS does. 2734 */ 2735 uint32 off_low = (orig_offset & 0xFFFFFFFF); 2736 uint32 off_high = ((orig_offset >> 32) & 0xFFFFFFFF); 2737 2738 lock.l_len = (orig_count & 0x7FFFFFFF); 2739 lock.l_start = (SMB_OFF_T)map_lock_offset(off_high, off_low); 2740 ret = fcntl(fd,op,&lock); 2741 if (ret == -1) 2742 { 2743 if (errno == EINVAL) 2744 { 2745 DEBUG(3,("locking not supported? returning True\n")); 2746 return(True); 2747 } 2748 return False; 2749 } 2750 DEBUG(3,("64 -> 32 bit modified lock call successful\n")); 2751 return True; 2752 } 2753#else /* LARGE_SMB_OFF_T */ 2754 DEBUG(3,("locking not supported? returning True\n")); 2755 return(True); 2756#endif /* LARGE_SMB_OFF_T */ 2757 } 2758 2759 return(False); 2760 } 2761 2762 /* everything went OK */ 2763 DEBUG(8,("Lock call successful\n")); 2764 2765 return(True); 2766#else 2767 return(False); 2768#endif 2769} 2770 2771/******************************************************************* 2772is the name specified one of my netbios names 2773returns true is it is equal, false otherwise 2774********************************************************************/ 2775BOOL is_myname(char *s) 2776{ 2777 int n; 2778 BOOL ret = False; 2779 2780 for (n=0; my_netbios_names[n]; n++) { 2781 if (strequal(my_netbios_names[n], s)) 2782 ret=True; 2783 } 2784 DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret)); 2785 return(ret); 2786} 2787 2788/******************************************************************* 2789set the horrid remote_arch string based on an enum. 2790********************************************************************/ 2791void set_remote_arch(enum remote_arch_types type) 2792{ 2793 ra_type = type; 2794 switch( type ) 2795 { 2796 case RA_WFWG: 2797 fstrcpy(remote_arch, "WfWg"); 2798 return; 2799 case RA_OS2: 2800 fstrcpy(remote_arch, "OS2"); 2801 return; 2802 case RA_WIN95: 2803 fstrcpy(remote_arch, "Win95"); 2804 return; 2805 case RA_WINNT: 2806 fstrcpy(remote_arch, "WinNT"); 2807 return; 2808 case RA_WIN2K: 2809 fstrcpy(remote_arch, "Win2K"); 2810 return; 2811 case RA_SAMBA: 2812 fstrcpy(remote_arch,"Samba"); 2813 return; 2814 default: 2815 ra_type = RA_UNKNOWN; 2816 fstrcpy(remote_arch, "UNKNOWN"); 2817 break; 2818 } 2819} 2820 2821/******************************************************************* 2822 Get the remote_arch type. 2823********************************************************************/ 2824enum remote_arch_types get_remote_arch(void) 2825{ 2826 return ra_type; 2827} 2828 2829 2830/******************************************************************* 2831align a pointer to a multiple of 2 bytes 2832********************************************************************/ 2833char *align2(char *q, char *base) 2834{ 2835 if (PTR_DIFF(q, base) & 1) 2836 { 2837 q++; 2838 } 2839 return q; 2840} 2841 2842/******************************************************************* 2843 align a pointer to a multiple of 4 bytes. 2844 ********************************************************************/ 2845char *align4(char *q, char *base) 2846{ 2847 int mod = PTR_DIFF(q, base) & 3; 2848 if (mod != 0) 2849 { 2850 q += 4-mod; 2851 } 2852 return q; 2853} 2854 2855void out_ascii(FILE *f, unsigned char *buf,int len) 2856{ 2857 int i; 2858 for (i=0;i<len;i++) 2859 { 2860 fprintf(f, "%c", isprint(buf[i])?buf[i]:'.'); 2861 } 2862} 2863 2864void out_data(FILE *f,char *buf1,int len, int per_line) 2865{ 2866 unsigned char *buf = (unsigned char *)buf1; 2867 int i=0; 2868 if (len<=0) 2869 { 2870 return; 2871 } 2872 2873 fprintf(f, "[%03X] ",i); 2874 for (i=0;i<len;) 2875 { 2876 fprintf(f, "%02X ",(int)buf[i]); 2877 i++; 2878 if (i%(per_line/2) == 0) fprintf(f, " "); 2879 if (i%per_line == 0) 2880 { 2881 out_ascii(f,&buf[i-per_line ],per_line/2); fprintf(f, " "); 2882 out_ascii(f,&buf[i-per_line/2],per_line/2); fprintf(f, "\n"); 2883 if (i<len) fprintf(f, "[%03X] ",i); 2884 } 2885 } 2886 if ((i%per_line) != 0) 2887 { 2888 int n; 2889 2890 n = per_line - (i%per_line); 2891 fprintf(f, " "); 2892 if (n>(per_line/2)) fprintf(f, " "); 2893 while (n--) 2894 { 2895 fprintf(f, " "); 2896 } 2897 n = MIN(per_line/2,i%per_line); 2898 out_ascii(f,&buf[i-(i%per_line)],n); fprintf(f, " "); 2899 n = (i%per_line) - n; 2900 if (n>0) out_ascii(f,&buf[i-n],n); 2901 fprintf(f, "\n"); 2902 } 2903} 2904 2905void print_asc(int level, unsigned char *buf,int len) 2906{ 2907 int i; 2908 for (i=0;i<len;i++) 2909 DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.')); 2910} 2911 2912void dump_data(int level,char *buf1,int len) 2913{ 2914 unsigned char *buf = (unsigned char *)buf1; 2915 int i=0; 2916 if (len<=0) return; 2917 2918 DEBUG(level,("[%03X] ",i)); 2919 for (i=0;i<len;) { 2920 DEBUG(level,("%02X ",(int)buf[i])); 2921 i++; 2922 if (i%8 == 0) DEBUG(level,(" ")); 2923 if (i%16 == 0) { 2924 print_asc(level,&buf[i-16],8); DEBUG(level,(" ")); 2925 print_asc(level,&buf[i-8],8); DEBUG(level,("\n")); 2926 if (i<len) DEBUG(level,("[%03X] ",i)); 2927 } 2928 } 2929 if (i%16) { 2930 int n; 2931 2932 n = 16 - (i%16); 2933 DEBUG(level,(" ")); 2934 if (n>8) DEBUG(level,(" ")); 2935 while (n--) DEBUG(level,(" ")); 2936 2937 n = MIN(8,i%16); 2938 print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" ")); 2939 n = (i%16) - n; 2940 if (n>0) print_asc(level,&buf[i-n],n); 2941 DEBUG(level,("\n")); 2942 } 2943} 2944 2945char *tab_depth(int depth) 2946{ 2947 static pstring spaces; 2948 memset(spaces, ' ', depth * 4); 2949 spaces[depth * 4] = 0; 2950 return spaces; 2951} 2952 2953/***************************************************************************** 2954 * Provide a checksum on a string 2955 * 2956 * Input: s - the null-terminated character string for which the checksum 2957 * will be calculated. 2958 * 2959 * Output: The checksum value calculated for s. 2960 * 2961 * **************************************************************************** 2962 */ 2963int str_checksum(const char *s) 2964{ 2965 int res = 0; 2966 int c; 2967 int i=0; 2968 2969 while(*s) { 2970 c = *s; 2971 res ^= (c << (i % 15)) ^ (c >> (15-(i%15))); 2972 s++; 2973 i++; 2974 } 2975 return(res); 2976} /* str_checksum */ 2977 2978 2979 2980/***************************************************************** 2981zero a memory area then free it. Used to catch bugs faster 2982*****************************************************************/ 2983void zero_free(void *p, size_t size) 2984{ 2985 memset(p, 0, size); 2986 free(p); 2987} 2988 2989 2990/***************************************************************** 2991set our open file limit to a requested max and return the limit 2992*****************************************************************/ 2993int set_maxfiles(int requested_max) 2994{ 2995#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)) 2996 struct rlimit rlp; 2997 int saved_current_limit; 2998 2999 if(getrlimit(RLIMIT_NOFILE, &rlp)) { 3000 DEBUG(0,("set_maxfiles: getrlimit (1) for RLIMIT_NOFILE failed with error %s\n", 3001 strerror(errno) )); 3002 /* just guess... */ 3003 return requested_max; 3004 } 3005 3006 /* 3007 * Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to 3008 * account for the extra fd we need 3009 * as well as the log files and standard 3010 * handles etc. Save the limit we want to set in case 3011 * we are running on an OS that doesn't support this limit (AIX) 3012 * which always returns RLIM_INFINITY for rlp.rlim_max. 3013 */ 3014 3015 saved_current_limit = rlp.rlim_cur = MIN(requested_max,rlp.rlim_max); 3016 3017 if(setrlimit(RLIMIT_NOFILE, &rlp)) { 3018 DEBUG(0,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d files failed with error %s\n", 3019 (int)rlp.rlim_cur, strerror(errno) )); 3020 /* just guess... */ 3021 return saved_current_limit; 3022 } 3023 3024 if(getrlimit(RLIMIT_NOFILE, &rlp)) { 3025 DEBUG(0,("set_maxfiles: getrlimit (2) for RLIMIT_NOFILE failed with error %s\n", 3026 strerror(errno) )); 3027 /* just guess... */ 3028 return saved_current_limit; 3029 } 3030 3031#if defined(RLIM_INFINITY) 3032 if(rlp.rlim_cur == RLIM_INFINITY) 3033 return saved_current_limit; 3034#endif 3035 3036 if((int)rlp.rlim_cur > saved_current_limit) 3037 return saved_current_limit; 3038 3039 return rlp.rlim_cur; 3040#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */ 3041 /* 3042 * No way to know - just guess... 3043 */ 3044 return requested_max; 3045#endif 3046} 3047 3048/***************************************************************** 3049 splits out the start of the key (HKLM or HKU) and the rest of the key 3050 *****************************************************************/ 3051BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name) 3052{ 3053 pstring tmp; 3054 3055 if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp))) 3056 { 3057 return False; 3058 } 3059 3060 (*reg_type) = 0; 3061 3062 DEBUG(10, ("reg_split_key: hive %s\n", tmp)); 3063 3064 if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE")) 3065 { 3066 (*reg_type) = HKEY_LOCAL_MACHINE; 3067 } 3068 else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS")) 3069 { 3070 (*reg_type) = HKEY_USERS; 3071 } 3072 else 3073 { 3074 DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp)); 3075 return False; 3076 } 3077 3078 if (next_token(NULL, tmp, "\n\r", sizeof(tmp))) 3079 { 3080 fstrcpy(key_name, tmp); 3081 } 3082 else 3083 { 3084 key_name[0] = 0; 3085 } 3086 3087 DEBUG(10, ("reg_split_key: name %s\n", key_name)); 3088 3089 return True; 3090} 3091 3092 3093/***************************************************************** 3094like mktemp() but make sure that no % characters are used 3095% characters are bad for us because of the macro subs 3096 *****************************************************************/ 3097char *smbd_mktemp(char *template) 3098{ 3099 char *p = mktemp(template); 3100 char *p2; 3101 SMB_STRUCT_STAT st; 3102 3103 if (!p) return NULL; 3104 3105 while ((p2=strchr(p,'%'))) { 3106 p2[0] = 'A'; 3107 while (sys_stat(p,&st) == 0 && p2[0] < 'Z') { 3108 /* damn, it exists */ 3109 p2[0]++; 3110 } 3111 if (p2[0] == 'Z') { 3112 /* oh well ... better return something */ 3113 p2[0] = '%'; 3114 return p; 3115 } 3116 } 3117 3118 return p; 3119} 3120 3121/***************************************************************** 3122possibly replace mkstemp if it is broken 3123 *****************************************************************/ 3124int smb_mkstemp(char *template) 3125{ 3126#if HAVE_SECURE_MKSTEMP 3127 return mkstemp(template); 3128#else 3129 /* have a reasonable go at emulating it. Hope that 3130 the system mktemp() isn't completly hopeless */ 3131 if (!mktemp(template)) return -1; 3132 return open(template, O_CREAT|O_EXCL|O_RDWR, 0600); 3133#endif 3134} 3135 3136 3137/***************************************************************** 3138like strdup but for memory 3139 *****************************************************************/ 3140void *memdup(void *p, size_t size) 3141{ 3142 void *p2; 3143 p2 = malloc(size); 3144 if (!p2) return NULL; 3145 memcpy(p2, p, size); 3146 return p2; 3147} 3148 3149/***************************************************************** 3150get local hostname and cache result 3151 *****************************************************************/ 3152char *myhostname(void) 3153{ 3154 static pstring ret; 3155 if (ret[0] == 0) { 3156 get_myname(ret); 3157 } 3158 return ret; 3159} 3160 3161/******************************************************************* 3162 Given a filename - get its directory name 3163 NB: Returned in static storage. Caveats: 3164 o Not safe in thread environment. 3165 o Caller must not free. 3166 o If caller wishes to preserve, they should copy. 3167********************************************************************/ 3168 3169char *parent_dirname(const char *path) 3170{ 3171 static pstring dirpath; 3172 char *p; 3173 3174 if (!path) 3175 return(NULL); 3176 3177 pstrcpy(dirpath, path); 3178 p = strrchr(dirpath, '/'); /* Find final '/', if any */ 3179 if (!p) { 3180 pstrcpy(dirpath, "."); /* No final "/", so dir is "." */ 3181 } else { 3182 if (p == dirpath) 3183 ++p; /* For root "/", leave "/" in place */ 3184 *p = '\0'; 3185 } 3186 return dirpath; 3187} 3188