diff options
Diffstat (limited to 'source/lib/util.c')
-rw-r--r-- | source/lib/util.c | 3319 |
1 files changed, 1672 insertions, 1647 deletions
diff --git a/source/lib/util.c b/source/lib/util.c index 7bd6298c4ca..0003b8b42d5 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Samba utility functions - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1997 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,10 @@ */ #include "includes.h" -#include "loadparm.h" + +#if (defined(NETGROUP) && defined (AUTOMOUNT)) +#include "rpcsvc/ypclnt.h" +#endif pstring scope = ""; @@ -30,8 +33,6 @@ BOOL passive = False; int Protocol = PROTOCOL_COREPLUS; -int serverzone=0; - /* a default finfo structure to ensure all fields are sensible */ file_info def_finfo = {-1,0,0,0,0,0,0,""}; @@ -41,20 +42,14 @@ FILE *dbf = NULL; /* the client file descriptor */ int Client = -1; -/* info on the client */ -struct from_host Client_info= -{"UNKNOWN","0.0.0.0",NULL}; - /* the last IP received from */ struct in_addr lastip; /* the last port received from */ int lastport=0; -/* my IP, the broadcast IP and the Netmask */ -struct in_addr myip; -struct in_addr bcast_ip; -struct in_addr Netmask; +/* this is used by the chaining code */ +int chain_size = 0; int trans_num = 0; @@ -63,11 +58,7 @@ int trans_num = 0; */ int case_default = CASE_LOWER; - -/* size of reads during a direct file to file transfer */ -int ReadSize = 16*1024; - -pstring debugf = "/tmp/log.samba"; +pstring debugf = ""; int syslog_level; /* the following control case operations - they are put here so the @@ -81,16 +72,25 @@ BOOL case_mangle; fstring remote_machine=""; fstring local_machine=""; fstring remote_arch="UNKNOWN"; +static enum remote_arch_types ra_type = RA_UNKNOWN; fstring remote_proto="UNKNOWN"; pstring myhostname=""; pstring user_socket_options=""; + pstring sesssetup_user=""; +pstring samlogon_user=""; +BOOL sam_logon_in_ssb = False; -static char *filename_dos(char *path,char *buf); +pstring myname = ""; +fstring myworkgroup = ""; +char **my_netbios_names; + +int smb_read_error = 0; static BOOL stdout_logging = False; +static char *filename_dos(char *path,char *buf); /******************************************************************* get ready for syslog stuff @@ -101,7 +101,11 @@ void setup_logging(char *pname,BOOL interactive) if (!interactive) { char *p = strrchr(pname,'/'); if (p) pname = p+1; +#ifdef LOG_DAEMON openlog(pname, LOG_PID, LOG_DAEMON); +#else /* LOG_DAEMON - for old systems that have no facility codes. */ + openlog(pname, LOG_PID); +#endif /* LOG_DAEMON */ } #endif if (interactive) { @@ -130,6 +134,7 @@ void reopen_logs(void) if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL)) { + int oldumask = umask(022); strcpy(debugf,fname); if (dbf) fclose(dbf); if (append_log) @@ -137,6 +142,7 @@ void reopen_logs(void) else dbf = fopen(debugf,"w"); if (dbf) setbuf(dbf,NULL); + umask(oldumask); } } else @@ -151,71 +157,78 @@ void reopen_logs(void) /******************************************************************* +check if the log has grown too big +********************************************************************/ +static void check_log_size(void) +{ + static int debug_count=0; + int maxlog; + struct stat st; + + if (debug_count++ < 100 || getuid() != 0) return; + + maxlog = lp_max_log_size() * 1024; + if (!dbf || maxlog <= 0) return; + + if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) { + fclose(dbf); dbf = NULL; + reopen_logs(); + if (dbf && file_size(debugf) > maxlog) { + pstring name; + fclose(dbf); dbf = NULL; + sprintf(name,"%s.old",debugf); + sys_rename(debugf,name); + reopen_logs(); + } + } + debug_count=0; +} + + +/******************************************************************* write an debug message on the debugfile. This is called by the DEBUG macro ********************************************************************/ #ifdef __STDC__ -int Debug1(char *format_str, ...) + int Debug1(char *format_str, ...) { #else -int Debug1(va_alist) + int Debug1(va_alist) va_dcl { char *format_str; #endif va_list ap; - + int old_errno = errno; + + if (stdout_logging) { #ifdef __STDC__ - va_start(ap, format_str); + va_start(ap, format_str); #else - va_start(ap); - format_str = va_arg(ap,char *); + va_start(ap); + format_str = va_arg(ap,char *); #endif - - if (stdout_logging) { vfprintf(dbf,format_str,ap); va_end(ap); + errno = old_errno; return(0); } - - { - static int debug_count=0; - - debug_count++; - if (debug_count == 100) { - int maxlog = lp_max_log_size() * 1024; - if (dbf && maxlog > 0) - { - struct stat st; - - if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) { - fclose(dbf); dbf = NULL; - reopen_logs(); - if (dbf && file_size(debugf) > maxlog) { - pstring name; - fclose(dbf); dbf = NULL; - sprintf(name,"%s.old",debugf); - sys_rename(debugf,name); - reopen_logs(); - } - } - } - debug_count=0; - } - } #ifdef SYSLOG if (!lp_syslog_only()) #endif { - if (!dbf) - { - dbf = fopen(debugf,"w"); - if (dbf) - setbuf(dbf,NULL); - else - return(0); - } + if (!dbf) { + int oldumask = umask(022); + dbf = fopen(debugf,"w"); + umask(oldumask); + if (dbf) { + setbuf(dbf,NULL); + } else { + errno = old_errno; + return(0); + } + } } #ifdef SYSLOG @@ -241,7 +254,14 @@ va_dcl else priority = priority_map[syslog_level]; +#ifdef __STDC__ + va_start(ap, format_str); +#else + va_start(ap); + format_str = va_arg(ap,char *); +#endif vsprintf(msgbuf, format_str, ap); + va_end(ap); msgbuf[255] = '\0'; syslog(priority, "%s", msgbuf); @@ -252,277 +272,37 @@ va_dcl if (!lp_syslog_only()) #endif { - vfprintf(dbf,format_str,ap); - fflush(dbf); - } - - va_end(ap); - return(0); -} - -/**************************************************************************** -routine to do file locking -****************************************************************************/ -BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) -{ -#if HAVE_FCNTL_LOCK - struct flock lock; - int ret; - -#if 1 - uint32 mask = 0xC0000000; - - /* make sure the count is reasonable, we might kill the lockd otherwise */ - count &= ~mask; - - /* the offset is often strange - remove 2 of its bits if either of - the top two bits are set. Shift the top ones by two bits. This - still allows OLE2 apps to operate, but should stop lockd from - dieing */ - if ((offset & mask) != 0) - offset = (offset & ~mask) | ((offset & mask) >> 2); -#else - unsigned long mask = ((unsigned)1<<31); - - /* interpret negative counts as large numbers */ - if (count < 0) - count &= ~mask; - - /* no negative offsets */ - offset &= ~mask; - - /* count + offset must be in range */ - while ((offset < 0 || (offset + count < 0)) && mask) - { - offset &= ~mask; - mask = mask >> 1; - } -#endif - - - DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); - - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = (int)offset; - lock.l_len = (int)count; - lock.l_pid = 0; - - errno = 0; - - ret = fcntl(fd,op,&lock); - - if (errno != 0) - DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); - - /* a lock query */ - if (op == F_GETLK) - { - if ((ret != -1) && - (lock.l_type != F_UNLCK) && - (lock.l_pid != 0) && - (lock.l_pid != getpid())) - { - DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid)); - return(True); - } - - /* it must be not locked or locked by me */ - return(False); - } - - /* a lock set or unset */ - if (ret == -1) - { - DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n", - offset,count,op,type,strerror(errno))); - - /* perhaps it doesn't support this sort of locking?? */ - if (errno == EINVAL) - { - DEBUG(3,("locking not supported? returning True\n")); - return(True); - } - - return(False); - } - - /* everything went OK */ - DEBUG(5,("Lock call successful\n")); - - return(True); -#else - return(False); -#endif -} - -/******************************************************************* -lock a file - returning a open file descriptor or -1 on failure -The timeout is in seconds. 0 means no timeout -********************************************************************/ -int file_lock(char *name,int timeout) -{ - int fd = open(name,O_RDWR|O_CREAT,0666); - time_t t=0; - if (fd < 0) return(-1); - -#if HAVE_FCNTL_LOCK - if (timeout) t = time(NULL); - while (!timeout || (time(NULL)-t < timeout)) { - if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd); - msleep(LOCK_RETRY_TIMEOUT); - } - return(-1); -#else - return(fd); -#endif -} - -/******************************************************************* -unlock a file locked by file_lock -********************************************************************/ -void file_unlock(int fd) -{ - if (fd<0) return; -#if HAVE_FCNTL_LOCK - fcntl_lock(fd,F_SETLK,0,1,F_UNLCK); -#endif - close(fd); -} - -/******************************************************************* -a gettimeofday wrapper -********************************************************************/ -void GetTimeOfDay(struct timeval *tval) -{ -#ifdef GETTIMEOFDAY1 - gettimeofday(tval); -#else - gettimeofday(tval,NULL); -#endif -} - -int extra_time_offset = 0; - -static int timediff = 0; - -/******************************************************************* -init the time differences -********************************************************************/ -void TimeInit(void) -{ - struct tm tm_utc,tm_local; - time_t t; - - t = time(NULL); - - tm_utc = *(gmtime(&t)); - tm_local = *(localtime(&t)); - -#ifdef HAVE_GMTOFF - timediff = -tm_local.tm_gmtoff; +#ifdef __STDC__ + va_start(ap, format_str); #else - timediff = mktime(&tm_utc) - mktime(&tm_local); + va_start(ap); + format_str = va_arg(ap,char *); #endif - - if (serverzone == 0) { - serverzone = timediff - DSTDiff(t); - DEBUG(4,("Serverzone is %d\n",serverzone)); - } -} - - -/******************************************************************* -return the DST offset for a particular time -We keep a table of DST offsets to prevent calling localtime() on each -call of this function. This saves a LOT of time on many unixes. -********************************************************************/ -int DSTDiff(time_t t) -{ - static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL; - static int table_size = 0; - int i; - BOOL is_dst = False; - - if (t == 0) t = time(NULL); - -#ifndef NO_ISDST - for (i=0;i<table_size;i++) - if (t >= dst_table[i].start && t <= dst_table[i].end) break; - - if (i<table_size) { - is_dst = dst_table[i].is_dst; - } else { - time_t low,high; - - dst_table = (struct dst_table *)Realloc(dst_table, - sizeof(dst_table[0])*(i+1)); - if (!dst_table) { - table_size = 0; - return(0); - } - - table_size++; - - dst_table[i].is_dst = is_dst = (localtime(&t)->tm_isdst?True:False);; - dst_table[i].start = dst_table[i].end = t; - - /* no entry will cover more than 6 months */ - low = t - 3*30*24*60*60; - high = t + 3*30*24*60*60; - - /* widen the new entry using two bisection searches */ - while (low+60*60 < dst_table[i].start) { - t = low + (dst_table[i].start-low)/2; - if ((localtime(&t)->tm_isdst?True:False) == is_dst) - dst_table[i].start = t; - else - low = t; + vfprintf(dbf,format_str,ap); + va_end(ap); + fflush(dbf); } - while (high-60*60 > dst_table[i].end) { - t = high + (high-dst_table[i].end)/2; - if ((localtime(&t)->tm_isdst?True:False) == is_dst) - dst_table[i].end = t; - else - high = t; - } + check_log_size(); -/* - DEBUG(1,("Added DST entry from %s ", - asctime(localtime(&dst_table[i].start)))); - DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)), - dst_table[i].is_dst)); -*/ - } -#endif + errno = old_errno; - return((is_dst?60*60:0) - (extra_time_offset*60)); + return(0); } /**************************************************************************** -return the difference between local and GMT time -****************************************************************************/ -int TimeDiff(time_t t) + find a suitable temporary directory. The result should be copied immediately + as it may be overwritten by a subsequent call + ****************************************************************************/ +char *tmpdir(void) { - static BOOL initialised = False; - if (!initialised) {initialised=True; TimeInit();} - return(timediff - DSTDiff(t)); + char *p; + if ((p = getenv("TMPDIR"))) { + return p; + } + return "/tmp"; } -/**************************************************************************** -try to optimise the localtime call, it can be quite expenive on some machines -timemul is normally LOCAL_TO_GMT, GMT_TO_LOCAL or 0 -****************************************************************************/ -struct tm *LocalTime(time_t *t,int timemul) -{ - time_t t2 = *t; - - if (timemul) - t2 += timemul * TimeDiff(t2); - - return(gmtime(&t2)); -} /**************************************************************************** @@ -733,6 +513,12 @@ struct #ifdef SO_RCVLOWAT {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT}, #endif +#ifdef SO_SNDTIMEO + {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT}, +#endif +#ifdef SO_RCVTIMEO + {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT}, +#endif {NULL,0,0,0,0}}; @@ -805,32 +591,6 @@ void close_sockets(void ) } /**************************************************************************** - return the date and time as a string -****************************************************************************/ -char *timestring(void ) -{ - static char TimeBuf[100]; - time_t t; - t = time(NULL); -#ifdef NO_STRFTIME - strcpy(TimeBuf, asctime(LocalTime(&t,GMT_TO_LOCAL))); -#elif defined(CLIX) || defined(CONVEX) - strftime(TimeBuf,100,"%m/%d/%y %I:%M:%S %p",LocalTime(&t,GMT_TO_LOCAL)); -#elif defined(AMPM) - strftime(TimeBuf,100,"%D %r",LocalTime(&t,GMT_TO_LOCAL)); -#elif defined(TZ_TIME) - { - strftime(TimeBuf,100,"%D:%T",LocalTime(&t,0)); - sprintf(TimeBuf+strlen(TimeBuf)," %+03d%02d", - -TimeDiff(t)/(60*60),-(TimeDiff(t)/60)%60); - } -#else - strftime(TimeBuf,100,"%D %T",LocalTime(&t,GMT_TO_LOCAL)); -#endif - return(TimeBuf); -} - -/**************************************************************************** determine whether we are in the specified group ****************************************************************************/ BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups) @@ -873,7 +633,7 @@ char *StrCpy(char *dest,char *src) /**************************************************************************** line strncpy but always null terminates. Make sure there is room! ****************************************************************************/ -char *StrnCpy(char *dest,const char *src,int n) +char *StrnCpy(char *dest,char *src,int n) { char *d = dest; if (!dest) return(NULL); @@ -938,48 +698,61 @@ static int name_interpret(char *in,char *out) /**************************************************************************** mangle a name into netbios format + + Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum. ****************************************************************************/ -int name_mangle(char *In,char *Out,char name_type) -{ - fstring name; - char buf[20]; - char *in = (char *)&buf[0]; - char *out = (char *)Out; - char *p, *label; - int i; +int name_mangle( char *In, char *Out, char name_type ) + { + int i; + int c; + int len; + char buf[20]; + char *p = Out; + + /* Safely copy the input string, In, into buf[]. */ + (void)memset( buf, 0, 20 ); + if( '*' == In[0] ) + buf[0] = '*'; + else + (void)sprintf( buf, "%-15.15s%c", In, name_type ); - if (In[0] != '*') { - StrnCpy(name,In,sizeof(name)-1); - sprintf(buf,"%-15.15s%c",name,name_type); - } else { - buf[0]='*'; - memset(&buf[1],0,16); - } + /* Place the length of the first field into the output buffer. */ + p[0] = 32; + p++; - *out++ = 32; - for (i=0;i<16;i++) { - char c = toupper(in[i]); - out[i*2] = (c>>4) + 'A'; - out[i*2+1] = (c & 0xF) + 'A'; - } - out[32]=0; - out += 32; - - label = scope; - while (*label) + /* Now convert the name to the rfc1001/1002 format. */ + for( i = 0; i < 16; i++ ) { - p = strchr(label, '.'); - if (p == 0) - p = label + strlen(label); - *out++ = p - label; - memcpy(out, label, p - label); - out += p - label; - label += p - label + (*p == '.'); + c = toupper( buf[i] ); + p[i*2] = ( (c >> 4) & 0x000F ) + 'A'; + p[(i*2)+1] = (c & 0x000F) + 'A'; + } + p += 32; + p[0] = '\0'; + + /* Add the scope string. */ + for( i = 0, len = 0; NULL != scope; i++, len++ ) + { + switch( scope[i] ) + { + case '\0': + p[0] = len; + if( len > 0 ) + p[len+1] = 0; + return( name_len(Out) ); + case '.': + p[0] = len; + p += (len + 1); + len = 0; + break; + default: + p[len+1] = scope[i]; + break; + } } - *out = 0; - return(name_len(Out)); -} + return( name_len(Out) ); + } /* name_mangle */ /******************************************************************* check if a file exists @@ -1014,12 +787,17 @@ time_t file_modtime(char *fname) BOOL directory_exist(char *dname,struct stat *st) { struct stat st2; + BOOL ret; + if (!st) st = &st2; if (sys_stat(dname,st) != 0) return(False); - return(S_ISDIR(st->st_mode)); + ret = S_ISDIR(st->st_mode); + if(!ret) + errno = ENOTDIR; + return ret; } /******************************************************************* @@ -1033,159 +811,6 @@ uint32 file_size(char *file_name) return(buf.st_size); } -/**************************************************************************** -check if it's a null mtime -****************************************************************************/ -static BOOL null_mtime(time_t mtime) -{ - if (mtime == 0 || mtime == 0xFFFFFFFF) - return(True); - return(False); -} - -/******************************************************************* - create a 16 bit dos packed date -********************************************************************/ -static uint16 make_dos_date1(time_t unixdate,struct tm *t) -{ - uint16 ret=0; - ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1); - ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5)); - return(ret); -} - -/******************************************************************* - create a 16 bit dos packed time -********************************************************************/ -static uint16 make_dos_time1(time_t unixdate,struct tm *t) -{ - uint16 ret=0; - ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3)); - ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5)); - return(ret); -} - -/******************************************************************* - create a 32 bit dos packed date/time from some parameters - This takes a GMT time and returns a packed localtime structure -********************************************************************/ -static uint32 make_dos_date(time_t unixdate) -{ - struct tm *t; - uint32 ret=0; - - t = LocalTime(&unixdate,GMT_TO_LOCAL); - - ret = make_dos_date1(unixdate,t); - ret = ((ret&0xFFFF)<<16) | make_dos_time1(unixdate,t); - - return(ret); -} - -/******************************************************************* -put a dos date into a buffer (time/date format) -This takes GMT time and puts local time in the buffer -********************************************************************/ -void put_dos_date(char *buf,int offset,time_t unixdate) -{ - uint32 x = make_dos_date(unixdate); - SIVAL(buf,offset,x); -} - -/******************************************************************* -put a dos date into a buffer (date/time format) -This takes GMT time and puts local time in the buffer -********************************************************************/ -void put_dos_date2(char *buf,int offset,time_t unixdate) -{ - uint32 x = make_dos_date(unixdate); - x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); - SIVAL(buf,offset,x); -} - -/******************************************************************* -put a dos 32 bit "unix like" date into a buffer. This routine takes -GMT and converts it to LOCAL time before putting it (most SMBs assume -localtime for this sort of date) -********************************************************************/ -void put_dos_date3(char *buf,int offset,time_t unixdate) -{ - if (!null_mtime(unixdate)) - unixdate += GMT_TO_LOCAL*TimeDiff(unixdate); - SIVAL(buf,offset,unixdate); -} - -/******************************************************************* - interpret a 32 bit dos packed date/time to some parameters -********************************************************************/ -static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second) -{ - uint32 p0,p1,p2,p3; - - p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; - p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF; - - *second = 2*(p0 & 0x1F); - *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3); - *hour = (p1>>3)&0xFF; - *day = (p2&0x1F); - *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1; - *year = ((p3>>1)&0xFF) + 80; -} - -/******************************************************************* - create a unix date (int GMT) from a dos date (which is actually in - localtime) -********************************************************************/ -time_t make_unix_date(void *date_ptr) -{ - uint32 dos_date=0; - struct tm t; - time_t ret; - - dos_date = IVAL(date_ptr,0); - - if (dos_date == 0) return(0); - - interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon, - &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); - t.tm_wday = 1; - t.tm_yday = 1; - t.tm_isdst = -1; - - /* mktime() also does the local to GMT time conversion for us. XXXXX - Do all unixes do this the same?? */ - ret = mktime(&t); - - return(ret); -} - -/******************************************************************* -like make_unix_date() but the words are reversed -********************************************************************/ -time_t make_unix_date2(void *date_ptr) -{ - uint32 x,x2; - - x = IVAL(date_ptr,0); - x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); - SIVAL(&x,0,x2); - - return(make_unix_date((void *)&x)); -} - -/******************************************************************* - create a unix GMT date from a dos date in 32 bit "unix like" format -these generally arrive as localtimes, with corresponding DST -********************************************************************/ -time_t make_unix_date3(void *date_ptr) -{ - time_t t = IVAL(date_ptr,0); - if (!null_mtime(t)) - t += LOCAL_TO_GMT*TimeDiff(t); - return(t); -} - /******************************************************************* return a string representing an attribute for a file ********************************************************************/ @@ -1211,10 +836,63 @@ char *attrib_string(int mode) ********************************************************************/ int StrCaseCmp(char *s, char *t) { - for (; tolower(*s) == tolower(*t); ++s, ++t) - if (!*s) return 0; + /* compare until we run out of string, either t or s, or find a difference */ + /* We *must* use toupper rather than tolower here due to the + asynchronous upper to lower mapping. + */ +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + int diff; + for (;;) + { + if (!*s || !*t) + return toupper (*s) - toupper (*t); + else if (is_sj_alph (*s) && is_sj_alph (*t)) + { + diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + } + else if (is_shift_jis (*s) && is_shift_jis (*t)) + { + diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t); + if (diff) + return diff; + diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + } + else if (is_shift_jis (*s)) + return 1; + else if (is_shift_jis (*t)) + return -1; + else + { + diff = toupper (*s) - toupper (*t); + if (diff) + return diff; + s++; + t++; + } + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + while (*s && *t && toupper(*s) == toupper(*t)) + { + s++; + t++; + } - return tolower(*s) - tolower(*t); + return(toupper(*s) - toupper(*t)); + } } /******************************************************************* @@ -1222,19 +900,79 @@ int StrCaseCmp(char *s, char *t) ********************************************************************/ int StrnCaseCmp(char *s, char *t, int n) { - while (n-- && *s && *t) { - if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t)); - s++; t++; + /* compare until we run out of string, either t or s, or chars */ + /* We *must* use toupper rather than tolower here due to the + asynchronous upper to lower mapping. + */ +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + int diff; + for (;n > 0;) + { + if (!*s || !*t) + return toupper (*s) - toupper (*t); + else if (is_sj_alph (*s) && is_sj_alph (*t)) + { + diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + n -= 2; + } + else if (is_shift_jis (*s) && is_shift_jis (*t)) + { + diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t); + if (diff) + return diff; + diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + n -= 2; + } + else if (is_shift_jis (*s)) + return 1; + else if (is_shift_jis (*t)) + return -1; + else + { + diff = toupper (*s) - toupper (*t); + if (diff) + return diff; + s++; + t++; + n--; + } + } + return 0; } - if (n) return(tolower(*s) - tolower(*t)); + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + while (n-- && *s && *t && toupper(*s) == toupper(*t)) + { + s++; + t++; + } - return(0); + /* not run out of chars - strings are different lengths */ + if (n) + return(toupper(*s) - toupper(*t)); + + /* identical up to where we run out of chars, + and strings are same length */ + return(0); + } } /******************************************************************* compare 2 strings ********************************************************************/ -BOOL strequal(char *s1,char *s2) +BOOL strequal(char *s1, char *s2) { if (s1 == s2) return(True); if (!s1 || !s2) return(False); @@ -1271,23 +1009,36 @@ BOOL strcsequal(char *s1,char *s2) void strlower(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + { + if (is_sj_upper (s[0], s[1])) + s[1] = sj_tolower2 (s[1]); + s += 2; + } + else if (is_kana (*s)) + { + s++; + } + else + { + if (isupper(*s)) + *s = tolower(*s); + s++; + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ { -#ifdef KANJI - if (is_shift_jis (*s)) { - s += 2; - } else if (is_kana (*s)) { - s++; - } else { - if (isupper(*s)) - *s = tolower(*s); - s++; - } -#else if (isupper(*s)) - *s = tolower(*s); + *s = tolower(*s); s++; -#endif /* KANJI */ } + } } /******************************************************************* @@ -1296,23 +1047,36 @@ void strlower(char *s) void strupper(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + { + if (is_sj_lower (s[0], s[1])) + s[1] = sj_toupper2 (s[1]); + s += 2; + } + else if (is_kana (*s)) + { + s++; + } + else + { + if (islower(*s)) + *s = toupper(*s); + s++; + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ { -#ifdef KANJI - if (is_shift_jis (*s)) { - s += 2; - } else if (is_kana (*s)) { - s++; - } else { - if (islower(*s)) - *s = toupper(*s); - s++; - } -#else if (islower(*s)) - *s = toupper(*s); + *s = toupper(*s); s++; -#endif } + } } /******************************************************************* @@ -1344,23 +1108,30 @@ BOOL strisnormal(char *s) void string_replace(char *s,char oldc,char newc) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + s += 2; + else if (is_kana (*s)) + s++; + else + { + if (oldc == *s) + *s = newc; + s++; + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ { -#ifdef KANJI - if (is_shift_jis (*s)) { - s += 2; - } else if (is_kana (*s)) { - s++; - } else { - if (oldc == *s) - *s = newc; - s++; - } -#else if (oldc == *s) - *s = newc; + *s = newc; s++; -#endif /* KANJI */ } + } } /**************************************************************************** @@ -1370,13 +1141,10 @@ void unix_format(char *fname) { pstring namecopy; string_replace(fname,'\\','/'); -#ifndef KANJI - dos2unix_format(fname, True); -#endif /* KANJI */ if (*fname == '/') { - strcpy(namecopy,fname); + pstrcpy(namecopy,fname); strcpy(fname,"."); strcat(fname,namecopy); } @@ -1387,9 +1155,6 @@ void unix_format(char *fname) ****************************************************************************/ void dos_format(char *fname) { -#ifndef KANJI - unix2dos_format(fname, True); -#endif /* KANJI */ string_replace(fname,'/','\\'); } @@ -1400,6 +1165,7 @@ void dos_format(char *fname) void show_msg(char *buf) { int i; + int j; int bcc=0; if (DEBUGLEVEL < 5) return; @@ -1425,10 +1191,29 @@ void show_msg(char *buf) DEBUG(5,("smb_bcc=%d\n",bcc)); if (DEBUGLEVEL < 10) return; - for (i=0;i<MIN(bcc,128);i++) - DEBUG(10,("%X ",CVAL(smb_buf(buf),i))); + for (i = 0; i < MIN(bcc, 512); i += 16) + { + for (j = 0; j < 16 && i+j < MIN(bcc,512); j++) + { + + DEBUG(10,("%2X ",CVAL(smb_buf(buf),i+j))); + if (j == 7) DEBUG(10, (" ")); + + } + DEBUG(10,(" ")); + + for (j = 0; j < 16 && i+j < MIN(bcc,512); j++) + { + unsigned char c = CVAL(smb_buf(buf),i+j); + if (c < 32 || c > 128) c = '.'; + DEBUG(10,("%c",c)); + + if (j == 7) DEBUG(10, (" ")); + } + DEBUG(10,("\n")); } +} /******************************************************************* return the length of an smb packet @@ -1512,7 +1297,7 @@ return the SMB offset into an SMB buffer ********************************************************************/ int smb_offset(char *p,char *buf) { - return(PTR_DIFF(p,buf+4)); + return(PTR_DIFF(p,buf+4) + chain_size); } @@ -1570,7 +1355,7 @@ void dos_clean_name(char *s) pstring s1; *p = 0; - strcpy(s1,p+3); + pstrcpy(s1,p+3); if ((p=strrchr(s,'\\')) != NULL) *p = 0; @@ -1596,12 +1381,19 @@ void unix_clean_name(char *s) /* remove any double slashes */ string_sub(s, "//","/"); + /* Remove leading ./ characters */ + if(strncmp(s, "./", 2) == 0) { + trim_string(s, "./", NULL); + if(*s == 0) + strcpy(s,"./"); + } + while ((p = strstr(s,"/../")) != NULL) { pstring s1; *p = 0; - strcpy(s1,p+3); + pstrcpy(s1,p+3); if ((p=strrchr(s,'/')) != NULL) *p = 0; @@ -1628,24 +1420,10 @@ int ChDir(char *path) DEBUG(3,("chdir to %s\n",path)); res = sys_chdir(path); if (!res) - strcpy(LastDir,path); + pstrcpy(LastDir,path); return(res); } - -/******************************************************************* - return the absolute current directory path. A dumb version. -********************************************************************/ -static char *Dumb_GetWd(char *s) -{ -#ifdef USE_GETCWD - return ((char *)getcwd(s,sizeof(pstring))); -#else - return ((char *)getwd(s)); -#endif -} - - /* number of list structures for a caching GetWd function. */ #define MAX_GETWDCACHE (50) @@ -1672,7 +1450,7 @@ char *GetWd(char *str) *s = 0; if (!use_getwd_cache) - return(Dumb_GetWd(str)); + return(sys_getwd(str)); /* init the cache */ if (!getwd_cache_init) @@ -1691,7 +1469,7 @@ char *GetWd(char *str) if (stat(".",&st) == -1) { DEBUG(0,("Very strange, couldn't stat \".\"\n")); - return(Dumb_GetWd(str)); + return(sys_getwd(str)); } @@ -1735,9 +1513,9 @@ char *GetWd(char *str) The very slow getcwd, which spawns a process on some systems, or the not quite so bad getwd. */ - if (!Dumb_GetWd(s)) + if (!sys_getwd(s)) { - DEBUG(0,("Getwd failed, errno %d\n",errno)); + DEBUG(0,("Getwd failed, errno %s\n",strerror(errno))); return (NULL); } @@ -1790,6 +1568,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) DEBUG(3,("Illegal file name? (%s)\n",s)); return(False); } + + if (strlen(s) == 0) + strcpy(s,"./"); + return(True); } @@ -1798,7 +1580,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) /* remove any double slashes */ string_sub(s,"//","/"); - strcpy(basename,s); + pstrcpy(basename,s); p = strrchr(basename,'/'); if (!p) @@ -1868,12 +1650,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) if (relative) { if (newname[l] == '/') - strcpy(s,newname + l + 1); + pstrcpy(s,newname + l + 1); else - strcpy(s,newname+l); + pstrcpy(s,newname+l); } else - strcpy(s,newname); + pstrcpy(s,newname); } ChDir(wd); @@ -1897,10 +1679,10 @@ static void expand_one(char *Mask,int len) int lfill = (len+1) - strlen(Mask); int l1= (p1 - Mask); pstring tmp; - strcpy(tmp,Mask); + pstrcpy(tmp,Mask); memset(tmp+l1,'?',lfill); - strcpy(tmp + l1 + lfill,Mask + l1 + 1); - strcpy(Mask,tmp); + pstrcpy(tmp + l1 + lfill,Mask + l1 + 1); + pstrcpy(Mask,tmp); } } @@ -1924,20 +1706,20 @@ void expand_mask(char *Mask,BOOL doext) filename_dos(Mask,filepart); - strcpy(mbeg,filepart); + pstrcpy(mbeg,filepart); if ((p1 = strchr(mbeg,'.')) != NULL) { hasdot = True; *p1 = 0; p1++; - strcpy(mext,p1); + pstrcpy(mext,p1); } else { strcpy(mext,""); if (strlen(mbeg) > 8) { - strcpy(mext,mbeg + 8); + pstrcpy(mext,mbeg + 8); mbeg[8] = 0; } } @@ -1955,7 +1737,7 @@ void expand_mask(char *Mask,BOOL doext) if (*mext) expand_one(mext,3); - strcpy(Mask,dirpart); + pstrcpy(Mask,dirpart); if (*dirpart || absolute) strcat(Mask,"\\"); strcat(Mask,mbeg); strcat(Mask,"."); @@ -1971,21 +1753,30 @@ does a string have any uppercase chars in it? BOOL strhasupper(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) { -#ifdef KANJI - if (is_shift_jis (*s)) { - s += 2; - } else if (is_kana (*s)) { - s++; - } else { - if (isupper(*s)) return(True); - s++; - } -#else - if (isupper(*s)) return(True); + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + s += 2; + else if (is_kana (*s)) + s++; + else + { + if (isupper(*s)) + return(True); + s++; + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + if (isupper(*s)) + return(True); s++; -#endif /* KANJI */ } + } return(False); } @@ -1995,21 +1786,38 @@ does a string have any lowercase chars in it? BOOL strhaslower(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) { -#ifdef KANJI - if (is_shift_jis (*s)) { - s += 2; - } else if (is_kana (*s)) { - s++; - } else { - if (islower(*s)) return(True); - s++; - } -#else - if (islower(*s)) return(True); + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + { + if (is_sj_upper (s[0], s[1])) + return(True); + if (is_sj_lower (s[0], s[1])) + return (True); + s += 2; + } + else if (is_kana (*s)) + { + s++; + } + else + { + if (islower(*s)) + return(True); + s++; + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + if (islower(*s)) + return(True); s++; -#endif /* KANJI */ } + } return(False); } @@ -2019,12 +1827,33 @@ find the number of chars in a string int count_chars(char *s,char c) { int count=0; - while (*s) + +#if !defined(KANJI_WIN95_COMPATIBILITY) + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + while (*s) + { + if (is_shift_jis (*s)) + s += 2; + else + { + if (*s == c) + count++; + s++; + } + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + while (*s) { if (*s == c) - count++; + count++; s++; } + } return(count); } @@ -2037,7 +1866,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode char *p; pstring mask2; - strcpy(mask2,mask); + pstrcpy(mask2,mask); if ((mode & aDIR) != 0) size = 0; @@ -2089,6 +1918,35 @@ void close_low_fds(void) } } +/**************************************************************************** +Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, +else +if SYSV use O_NDELAY +if BSD use FNDELAY +****************************************************************************/ +int set_blocking(int fd, BOOL set) +{ + int val; +#ifdef O_NONBLOCK +#define FLAG_TO_SET O_NONBLOCK +#else +#ifdef SYSV +#define FLAG_TO_SET O_NDELAY +#else /* BSD */ +#define FLAG_TO_SET FNDELAY +#endif +#endif + + if((val = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + if(set) /* Turn blocking on - ie. clear nonblock flag */ + val &= ~FLAG_TO_SET; + else + val |= FLAG_TO_SET; + return fcntl( fd, F_SETFL, val); +#undef FLAG_TO_SET +} + /**************************************************************************** write to a socket @@ -2119,68 +1977,18 @@ int read_udp_socket(int fd,char *buf,int len) bzero((char *)&sock,socklen); bzero((char *)&lastip,sizeof(lastip)); ret = recvfrom(fd,buf,len,0,&sock,&socklen); - if (ret <= 0) - { - DEBUG(2,("read socket failed. ERRNO=%d\n",errno)); - return(0); - } + if (ret <= 0) { + DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno))); + return(0); + } lastip = *(struct in_addr *) &sock.sa_data[2]; lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port); - return(ret); -} - -/**************************************************************************** -Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, -else -if SYSV use O_NDELAY -if BSD use FNDELAY -****************************************************************************/ -int set_blocking(int fd, BOOL set) -{ -int val; -#ifdef O_NONBLOCK -#define FLAG_TO_SET O_NONBLOCK -#else -#ifdef SYSV -#define FLAG_TO_SET O_NDELAY -#else /* BSD */ -#define FLAG_TO_SET FNDELAY -#endif -#endif - - if((val = fcntl(fd, F_GETFL, 0))==-1) - return -1; - if(set) /* Turn blocking on - ie. clear nonblock flag */ - val &= ~FLAG_TO_SET; - else - val |= FLAG_TO_SET; - return fcntl( fd, F_SETFL, val); -#undef FLAG_TO_SET -} - + DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n", + inet_ntoa(lastip), lastport, ret)); -/**************************************************************************** -Calculate the difference in timeout values. Return 1 if val1 > val2, -0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval -may be == val1 or val2 -****************************************************************************/ -static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2) -{ - int usecdiff = val1->tv_usec - val2->tv_usec; - int secdiff = val1->tv_sec - val2->tv_sec; - if(usecdiff < 0) { - usecdiff = 1000000 + usecdiff; - secdiff--; - } - retval->tv_sec = secdiff; - retval->tv_usec = usecdiff; - if(secdiff < 0) - return -1; - if(secdiff > 0) - return 1; - return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0); + return(ret); } /**************************************************************************** @@ -2188,46 +1996,39 @@ read data from a device with a timout in msec. mincount = if timeout, minimum to read before returning maxcount = number to be read. ****************************************************************************/ -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact) +int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out) { fd_set fds; int selrtn; int readret; int nread = 0; - struct timeval timeout, tval1, tval2, tvaldiff; - int error_limit = 5; + struct timeval timeout; /* just checking .... */ if (maxcnt <= 0) return(0); - if(time_out == -2) - time_out = DEFAULT_PIPE_TIMEOUT; + smb_read_error = 0; /* Blocking read */ - if(time_out < 0) { + if (time_out <= 0) { if (mincnt == 0) mincnt = maxcnt; - while (nread < mincnt) - { - readret = read(fd, buf + nread, maxcnt - nread); - if (readret <= 0) return(nread); - nread += readret; + while (nread < mincnt) { + readret = read(fd, buf + nread, maxcnt - nread); + if (readret == 0) { + smb_read_error = READ_EOF; + return -1; } + + if (readret == -1) { + smb_read_error = READ_ERROR; + return -1; + } + nread += readret; + } return(nread); } - /* Non blocking read */ - if(time_out == 0) { - set_blocking(fd, False); - nread = read_data(fd, buf, mincnt); - if (nread < maxcnt) - nread += read(fd,buf+nread,maxcnt-nread); - if(nread == -1 && errno == EWOULDBLOCK) - nread = 0; - set_blocking(fd,True); - return nread; - } - /* Most difficult - timeout read */ /* If this is ever called on a disk file and mincnt is greater then the filesize then @@ -2238,71 +2039,40 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL timeout.tv_sec = time_out / 1000; timeout.tv_usec = 1000 * (time_out % 1000); - /* As most UNIXes don't modify the value of timeout - when they return from select we need to get the timeofday (in usec) - now, and also after the select returns so we know - how much time has elapsed */ - - if (exact) - GetTimeOfDay( &tval1); - nread = 0; /* Number of bytes we have read */ - - for(;;) + for (nread=0; nread<mincnt; ) { FD_ZERO(&fds); FD_SET(fd,&fds); selrtn = sys_select(&fds,&timeout); - + /* Check if error */ if(selrtn == -1) { - errno = EBADF; + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; return -1; } /* Did we timeout ? */ if (selrtn == 0) { - if (nread < mincnt) return -1; - break; /* Yes */ + smb_read_error = READ_TIMEOUT; + return -1; } readret = read(fd, buf+nread, maxcnt-nread); - if (readret == 0 && nread < mincnt) { - /* error_limit should not really be needed, but some systems - do strange things ... I don't want to just continue - indefinately in case we get an infinite loop */ - if (error_limit--) continue; - return(-1); + if (readret == 0) { + /* we got EOF on the file descriptor */ + smb_read_error = READ_EOF; + return -1; } - if (readret < 0) { - /* force a particular error number for - portability */ - DEBUG(5,("read gave error %s\n",strerror(errno))); - errno = EBADF; + if (readret == -1) { + /* the descriptor is probably dead */ + smb_read_error = READ_ERROR; return -1; } nread += readret; - - /* If we have read more than mincnt then return */ - if (nread >= mincnt) - break; - - /* We need to do another select - but first reduce the - time_out by the amount of time already elapsed - if - this is less than zero then return */ - if (exact) { - GetTimeOfDay(&tval2); - (void)tval_sub( &tvaldiff, &tval2, &tval1); - - if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) - break; /* We timed out */ - } - - /* Save the time of day as we need to do the select - again (saves a system call) */ - tval1 = tval2; } /* Return the number we got */ @@ -2369,16 +2139,19 @@ int read_data(int fd,char *buffer,int N) int ret; int total=0; + smb_read_error = 0; + while (total < N) { ret = read(fd,buffer + total,N - total); - - /* this is for portability */ - if (ret < 0) - errno = EBADF; - - if (ret <= 0) - return total; + if (ret == 0) { + smb_read_error = READ_EOF; + return 0; + } + if (ret == -1) { + smb_read_error = READ_ERROR; + return -1; + } total += ret; } return total; @@ -2397,8 +2170,8 @@ int write_data(int fd,char *buffer,int N) { ret = write(fd,buffer + total,N - total); - if (ret <= 0) - return total; + if (ret == -1) return -1; + if (ret == 0) return total; total += ret; } @@ -2406,142 +2179,28 @@ int write_data(int fd,char *buffer,int N) } -/* variables used by the read prediction module */ -int rp_fd = -1; -int rp_offset = 0; -int rp_length = 0; -int rp_alloced = 0; -int rp_predict_fd = -1; -int rp_predict_offset = 0; -int rp_predict_length = 0; -int rp_timeout = 5; -time_t rp_time = 0; -char *rp_buffer = NULL; -BOOL predict_skip=False; -time_t smb_last_time=(time_t)0; - -/**************************************************************************** -handle read prediction on a file -****************************************************************************/ -int read_predict(int fd,int offset,char *buf,char **ptr,int num) -{ - int ret = 0; - int possible = rp_length - (offset - rp_offset); - - possible = MIN(possible,num); - - /* give data if possible */ - if (fd == rp_fd && - offset >= rp_offset && - possible>0 && - smb_last_time-rp_time < rp_timeout) - { - ret = possible; - if (buf) - memcpy(buf,rp_buffer + (offset-rp_offset),possible); - else - *ptr = rp_buffer + (offset-rp_offset); - DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num)); - } - - if (ret == num) { - predict_skip = True; - } else { - predict_skip = False; - - /* prepare the next prediction */ - rp_predict_fd = fd; - rp_predict_offset = offset + num; - rp_predict_length = num; - } - - if (ret < 0) ret = 0; - - return(ret); -} - -/**************************************************************************** -pre-read some data -****************************************************************************/ -void do_read_prediction() -{ - if (predict_skip) return; - - if (rp_predict_fd == -1) - return; - - rp_fd = rp_predict_fd; - rp_offset = rp_predict_offset; - rp_length = 0; - - rp_predict_fd = -1; - - rp_predict_length = MIN(rp_predict_length,2*ReadSize); - rp_predict_length = MAX(rp_predict_length,1024); - rp_offset = (rp_offset/1024)*1024; - rp_predict_length = (rp_predict_length/1024)*1024; - - if (rp_predict_length > rp_alloced) - { - rp_buffer = Realloc(rp_buffer,rp_predict_length); - rp_alloced = rp_predict_length; - if (!rp_buffer) - { - DEBUG(0,("can't allocate read-prediction buffer\n")); - rp_predict_fd = -1; - rp_fd = -1; - rp_alloced = 0; - return; - } - } - - if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) { - rp_fd = -1; - rp_predict_fd = -1; - return; - } - - rp_length = read(rp_fd,rp_buffer,rp_predict_length); - rp_time = time(NULL); - if (rp_length < 0) - rp_length = 0; -} - -/**************************************************************************** -invalidate read-prediction on a fd -****************************************************************************/ -void invalidate_read_prediction(int fd) -{ - if (rp_fd == fd) - rp_fd = -1; - if (rp_predict_fd == fd) - rp_predict_fd = -1; -} - - /**************************************************************************** transfer some data between two fd's ****************************************************************************/ int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) { static char *buf=NULL; + static int size=0; char *buf1,*abuf; - static int size = 0; int total = 0; DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen)); - if ((size < ReadSize) && buf) { - free(buf); - buf = NULL; + if (size == 0) { + size = lp_readsize(); + size = MAX(size,1024); } - size = MAX(ReadSize,1024); - while (!buf && size>0) { buf = (char *)Realloc(buf,size+8); if (!buf) size /= 2; } + if (!buf) { DEBUG(0,("Can't allocate transfer buffer!\n")); exit(1); @@ -2616,30 +2275,19 @@ int read_smb_length(int fd,char *inbuf,int timeout) while (!ok) { if (timeout > 0) - ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4); - else + ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4); + else ok = (read_data(fd,buffer,4) == 4); if (!ok) - { - if (timeout>0) - { - DEBUG(10,("select timeout (%d)\n", timeout)); - return(-1); - } - else - { - DEBUG(6,("couldn't read from client\n")); - exit(1); - } - } + return(-1); len = smb_len(buffer); msg_type = CVAL(buffer,0); if (msg_type == 0x85) { - DEBUG(5,( "Got keepalive packet\n")); + DEBUG(5,("Got keepalive packet\n")); ok = False; } } @@ -2652,13 +2300,15 @@ int read_smb_length(int fd,char *inbuf,int timeout) /**************************************************************************** - read an smb from a fd and return it's length + read an smb from a fd. Note that the buffer *MUST* be of size + BUFFER_SIZE+SAFETY_MARGIN. The timeout is in milli seconds ****************************************************************************/ -BOOL receive_smb(int fd,char *buffer,int timeout) +BOOL receive_smb(int fd,char *buffer, int timeout) { - int len; - BOOL ok; + int len,ret; + + smb_read_error = 0; bzero(buffer,smb_size + 100); @@ -2666,24 +2316,217 @@ BOOL receive_smb(int fd,char *buffer,int timeout) if (len == -1) return(False); - if (len > BUFFER_SIZE) - { - DEBUG(0,("Invalid packet length! (%d bytes)\n",len)); - if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) - exit(1); - } + if (len > BUFFER_SIZE) { + DEBUG(0,("Invalid packet length! (%d bytes).\n",len)); + if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) + exit(1); + } + + ret = read_data(fd,buffer+4,len); + if (ret != len) { + smb_read_error = READ_ERROR; + return False; + } + + return(True); +} + +/**************************************************************************** + read a message from a udp fd. +The timeout is in milli seconds +****************************************************************************/ +BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout) +{ + struct sockaddr_in from; + int fromlen = sizeof(from); + int32 msg_len = 0; + + if(timeout != 0) + { + struct timeval to; + fd_set fds; + int selrtn; + + FD_ZERO(&fds); + FD_SET(fd,&fds); - ok = (read_data(fd,buffer+4,len) == len); + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; - if (!ok) + selrtn = sys_select(&fds,&to); + + /* Check if error */ + if(selrtn == -1) { - close_sockets(); - exit(1); + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return False; + } + + /* Did we timeout ? */ + if (selrtn == 0) + { + smb_read_error = READ_TIMEOUT; + return False; } + } - return(True); + /* + * Read a loopback udp message. + */ + msg_len = recvfrom(fd, &buffer[UDP_CMD_HEADER_LEN], + buffer_len - UDP_CMD_HEADER_LEN, 0, + (struct sockaddr *)&from, &fromlen); + + if(msg_len < 0) + { + DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno))); + return False; + } + + /* Validate message length. */ + if(msg_len > (buffer_len - UDP_CMD_HEADER_LEN)) + { + DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n", + msg_len, + buffer_len - UDP_CMD_HEADER_LEN)); + return False; + } + + /* Validate message from address (must be localhost). */ + if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) + { + DEBUG(0,("receive_local_message: invalid 'from' address \ +(was %x should be 127.0.0.1\n", from.sin_addr.s_addr)); + return False; + } + + /* Setup the message header */ + SIVAL(buffer,UDP_CMD_LEN_OFFSET,msg_len); + SSVAL(buffer,UDP_CMD_PORT_OFFSET,ntohs(from.sin_port)); + + return True; +} + +/**************************************************************************** + structure to hold a linked list of local udp messages. + for processing. +****************************************************************************/ + +typedef struct _udp_message_list { + struct _udp_message_list *msg_next; + char *msg_buf; + int msg_len; +} udp_message_list; + +static udp_message_list *udp_msg_head = NULL; + +/**************************************************************************** + Function to push a linked list of local udp messages ready + for processing. +****************************************************************************/ +BOOL push_local_message(char *buf, int msg_len) +{ + udp_message_list *msg = (udp_message_list *)malloc(sizeof(udp_message_list)); + + if(msg == NULL) + { + DEBUG(0,("push_local_message: malloc fail (1)\n")); + return False; + } + + msg->msg_buf = (char *)malloc(msg_len); + if(msg->msg_buf == NULL) + { + DEBUG(0,("push_local_message: malloc fail (2)\n")); + free((char *)msg); + return False; + } + + memcpy(msg->msg_buf, buf, msg_len); + msg->msg_len = msg_len; + + msg->msg_next = udp_msg_head; + udp_msg_head = msg; + + return True; } +/**************************************************************************** + Do a select on an two fd's - with timeout. + + If a local udp message has been pushed onto the + queue (this can only happen during oplock break + processing) return this first. + + If the first smbfd is ready then read an smb from it. + if the second (loopback UDP) fd is ready then read a message + from it and setup the buffer header to identify the length + and from address. + Returns False on timeout or error. + Else returns True. + +The timeout is in milli seconds +****************************************************************************/ +BOOL receive_message_or_smb(int smbfd, int oplock_fd, + char *buffer, int buffer_len, + int timeout, BOOL *got_smb) +{ + fd_set fds; + int selrtn; + struct timeval to; + + *got_smb = False; + + /* + * Check to see if we already have a message on the udp queue. + * If so - copy and return it. + */ + + if(udp_msg_head) + { + udp_message_list *msg = udp_msg_head; + memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len)); + udp_msg_head = msg->msg_next; + + /* Free the message we just copied. */ + free((char *)msg->msg_buf); + free((char *)msg); + return True; + } + + FD_ZERO(&fds); + FD_SET(smbfd,&fds); + FD_SET(oplock_fd,&fds); + + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; + + selrtn = sys_select(&fds,timeout>0?&to:NULL); + + /* Check if error */ + if(selrtn == -1) { + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return False; + } + + /* Did we timeout ? */ + if (selrtn == 0) { + smb_read_error = READ_TIMEOUT; + return False; + } + + if (FD_ISSET(smbfd,&fds)) + { + *got_smb = True; + return receive_smb(smbfd, buffer, 0); + } + else + { + return receive_local_message(oplock_fd, buffer, buffer_len, 0); + } +} /**************************************************************************** send an smb to a fd @@ -2742,21 +2585,27 @@ int name_extract(char *buf,int ofs,char *name) strcpy(name,""); if (d < -50 || d > 50) return(0); return(name_interpret(p,name)); -} +} - /**************************************************************************** return the total storage length of a mangled name ****************************************************************************/ -int name_len(char *s) -{ - char *s0=s; - unsigned char c = *(unsigned char *)s; - if ((c & 0xC0) == 0xC0) +int name_len( char *s ) + { + int len; + + /* If the two high bits of the byte are set, return 2. */ + if( 0xC0 == (*(unsigned char *)s & 0xC0) ) return(2); - while (*s) s += (*s)+1; - return(PTR_DIFF(s,s0)+1); -} + + /* Add up the length bytes. */ + for( len = 1; (*s); s += (*s) + 1 ) + { + len += *s + 1; + } + + return( len ); + } /* name_len */ /**************************************************************************** send a single packet to a port on another machine @@ -2792,8 +2641,8 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type) ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0); if (!ret) - DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n", - inet_ntoa(ip),port,errno)); + DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n", + inet_ntoa(ip),port,strerror(errno))); close(out_fd); return(ret); @@ -2871,7 +2720,12 @@ BOOL string_init(char **dest,char *src) } else { - *dest = (char *)malloc(l+1); + (*dest) = (char *)malloc(l+1); + if ((*dest) == NULL) { + DEBUG(0,("Out of memory in string_init\n")); + return False; + } + strcpy(*dest,src); } return(True); @@ -3040,35 +2894,35 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) if (strequal(p1,"*")) return(True); - DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); + DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); if (trans2) { - strcpy(ebase,p1); - strcpy(sbase,p2); + fstrcpy(ebase,p1); + fstrcpy(sbase,p2); } else { if ((p=strrchr(p1,'.'))) { *p = 0; - strcpy(ebase,p1); - strcpy(eext,p+1); + fstrcpy(ebase,p1); + fstrcpy(eext,p+1); } else { - strcpy(ebase,p1); + fstrcpy(ebase,p1); eext[0] = 0; } if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) { *p = 0; - strcpy(sbase,p2); - strcpy(sext,p+1); + fstrcpy(sbase,p2); + fstrcpy(sext,p+1); } else { - strcpy(sbase,p2); - strcpy(sext,""); + fstrcpy(sbase,p2); + fstrcpy(sext,""); } } matched = do_match(sbase,ebase,case_sig) && (trans2 || do_match(sext,eext,case_sig)); - DEBUG(5,("mask_match returning %d\n", matched)); + DEBUG(8,("mask_match returning %d\n", matched)); return matched; } @@ -3087,7 +2941,7 @@ void become_daemon(void) /* detach from the terminal */ #ifdef USE_SETSID setsid(); -#else +#else /* USE_SETSID */ #ifdef TIOCNOTTY { int i = open("/dev/tty", O_RDWR); @@ -3097,221 +2951,13 @@ void become_daemon(void) close(i); } } -#endif -#endif -#endif -} - -/**************************************************************************** -calculate the default netmask for an address -****************************************************************************/ -static void default_netmask(struct in_addr *inm, struct in_addr *iad) -{ - unsigned long ad = ntohl(iad->s_addr); - unsigned long nm; - /* - ** Guess a netmask based on the class of the IP address given. - */ - if ( (ad & 0x80000000) == 0 ) { - /* class A address */ - nm = 0xFF000000; - } else if ( (ad & 0xC0000000) == 0x80000000 ) { - /* class B address */ - nm = 0xFFFF0000; - } else if ( (ad & 0xE0000000) == 0xC0000000 ) { - /* class C address */ - nm = 0xFFFFFF00; - } else { - /* class D or E; netmask doesn't make much sense - guess 4 bits */ - nm = 0xFFFFFFF0; - } - inm->s_addr = htonl(nm); +#endif /* TIOCNOTTY */ +#endif /* USE_SETSID */ + /* Close fd's 0,1,2. Needed if started by rsh */ + close_low_fds(); +#endif /* NO_FORK_DEBUG */ } -/**************************************************************************** - get the broadcast address for our address -(troyer@saifr00.ateng.az.honeywell.com) -****************************************************************************/ -void get_broadcast(struct in_addr *if_ipaddr, - struct in_addr *if_bcast, - struct in_addr *if_nmask) -{ - BOOL found = False; -#ifndef NO_GET_BROADCAST - int sock = -1; /* AF_INET raw socket desc */ - char buff[1024]; - struct ifreq *ifr=NULL; - int i; - -#if defined(EVEREST) - int n_interfaces; - struct ifconf ifc; - struct ifreq *ifreqs; -#elif defined(USE_IFREQ) - struct ifreq ifreq; - struct strioctl strioctl; - struct ifconf *ifc; -#else - struct ifconf ifc; -#endif -#endif - - /* get a default netmask and broadcast */ - default_netmask(if_nmask, if_ipaddr); - -#ifndef NO_GET_BROADCAST - /* Create a socket to the INET kernel. */ -#if USE_SOCKRAW - if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0) -#else - if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0) -#endif - { - DEBUG(0,( "Unable to open socket to get broadcast address\n")); - return; - } - - /* Get a list of the configured interfaces */ -#ifdef EVEREST - /* This is part of SCO Openserver 5: The ioctls are no longer part - if the lower level STREAMS interface glue. They are now real - ioctl calls */ - - if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) { - DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno))); - } else { - DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces)); - - ifc.ifc_len = sizeof(struct ifreq) * n_interfaces; - ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len); - - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) - DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno))); - else { - ifr = ifc.ifc_req; - - for (i = 0; i < n_interfaces; ++i) { - if (if_ipaddr->s_addr == - ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) { - found = True; - break; - } - } - } - } -#elif defined(USE_IFREQ) - ifc = (struct ifconf *)buff; - ifc->ifc_len = BUFSIZ - sizeof(struct ifconf); - strioctl.ic_cmd = SIOCGIFCONF; - strioctl.ic_dp = (char *)ifc; - strioctl.ic_len = sizeof(buff); - if (ioctl(sock, I_STR, &strioctl) < 0) { - DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno))); - } else { - ifr = (struct ifreq *)ifc->ifc_req; - - /* Loop through interfaces, looking for given IP address */ - for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { - if (if_ipaddr->s_addr == - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { - found = True; - break; - } - } - } -#elif defined(__FreeBSD__) || defined(NETBSD) - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { - DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); - } else { - ifr = ifc.ifc_req; - /* Loop through interfaces, looking for given IP address */ - i = ifc.ifc_len; - while (i > 0) { - if (if_ipaddr->s_addr == - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { - found = True; - break; - } - i -= ifr->ifr_addr.sa_len + IFNAMSIZ; - ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ); - } - } -#else - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { - DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); - } else { - ifr = ifc.ifc_req; - - /* Loop through interfaces, looking for given IP address */ - for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { -#ifdef BSDI - if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break; -#endif - if (if_ipaddr->s_addr == - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { - found = True; - break; - } - } - } -#endif - - if (!found) { - DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr))); - } else { - /* Get the netmask address from the kernel */ -#ifdef USE_IFREQ - ifreq = *ifr; - - strioctl.ic_cmd = SIOCGIFNETMASK; - strioctl.ic_dp = (char *)&ifreq; - strioctl.ic_len = sizeof(struct ifreq); - if (ioctl(sock, I_STR, &strioctl) < 0) - DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno))); - else - *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; -#else - if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0) - DEBUG(0,("SIOCGIFNETMASK failed\n")); - else - *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; -#endif - - DEBUG(2,("Netmask for %s = %s\n", ifr->ifr_name, - inet_ntoa(*if_nmask))); - } - - /* Close up shop */ - (void) close(sock); - -#endif - - /* sanity check on the netmask */ - { - unsigned long nm = ntohl(if_nmask->s_addr); - if ((nm >> 24) != 0xFF) { - DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask))); - default_netmask(if_nmask, if_ipaddr); - } - } - - /* derive the broadcast assuming a 1's broadcast, as this is what - all MS operating systems do, we have to comply even if the unix - box is setup differently */ - { - unsigned long ad = ntohl(if_ipaddr->s_addr); - unsigned long nm = ntohl(if_nmask->s_addr); - unsigned long bc = (ad & nm) | (0xffffffff & ~nm); - if_bcast->s_addr = htonl(bc); - } - - DEBUG(2,("Derived broadcast address %s\n", inet_ntoa(*if_bcast))); -} /* get_broadcast */ - /**************************************************************************** put up a yes/no prompt @@ -3462,7 +3108,7 @@ int byte_checksum(char *buf,int len) /**************************************************************************** this is a version of setbuffer() for those machines that only have setvbuf ****************************************************************************/ -void setbuffer(FILE *f,char *buf,int bufsize) + void setbuffer(FILE *f,char *buf,int bufsize) { setvbuf(f,buf,_IOFBF,bufsize); } @@ -3512,6 +3158,13 @@ expand a pointer to be a particular size void *Realloc(void *p,int size) { void *ret=NULL; + + if (size == 0) { + if (p) free(p); + DEBUG(5,("Realloc asked for 0 bytes\n")); + return NULL; + } + if (!p) ret = (void *)malloc(size); else @@ -3523,30 +3176,11 @@ void *Realloc(void *p,int size) return(ret); } -/**************************************************************************** -set the time on a file -****************************************************************************/ -BOOL set_filetime(char *fname,time_t mtime) -{ - struct utimbuf times; - - if (null_mtime(mtime)) return(True); - - times.modtime = times.actime = mtime; - - if (sys_utime(fname,×)) { - DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno))); - } - - return(True); -} - - #ifdef NOSTRDUP /**************************************************************************** duplicate a string ****************************************************************************/ -char *strdup(char *s) + char *strdup(char *s) { char *ret = NULL; if (!s) return(NULL); @@ -3567,94 +3201,10 @@ void Abort(void ) exit(2); } - -#ifdef REPLACE_STRLEN -/**************************************************************************** -a replacement strlen() that returns int for solaris -****************************************************************************/ -int Strlen(char *s) -{ - int ret=0; - if (!s) return(0); - while (*s++) ret++; - return(ret); -} -#endif - - -/**************************************************************************** -return a time at the start of the current month -****************************************************************************/ -time_t start_of_month(void) -{ - time_t t = time(NULL); - struct tm *t2; - - t2 = gmtime(&t); - - t2->tm_mday = 1; - t2->tm_hour = 0; - t2->tm_min = 0; - t2->tm_sec = 0; - - return(mktime(t2)); -} - - -/******************************************************************* - check for a sane unix date -********************************************************************/ -BOOL sane_unix_date(time_t unixdate) -{ - struct tm t,today; - time_t t_today = time(NULL); - - t = *(LocalTime(&unixdate,LOCAL_TO_GMT)); - today = *(LocalTime(&t_today,LOCAL_TO_GMT)); - - if (t.tm_year < 80) - return(False); - - if (t.tm_year > today.tm_year) - return(False); - - if (t.tm_year == today.tm_year && - t.tm_mon > today.tm_mon) - return(False); - - - if (t.tm_year == today.tm_year && - t.tm_mon == today.tm_mon && - t.tm_mday > (today.tm_mday+1)) - return(False); - - return(True); -} - - - -#ifdef NO_FTRUNCATE - /******************************************************************* -ftruncate for operating systems that don't have it -********************************************************************/ -int ftruncate(int f,long l) -{ - struct flock fl; - - fl.l_whence = 0; - fl.l_len = 0; - fl.l_start = l; - fl.l_type = F_WRLCK; - return fcntl(f, F_FREESP, &fl); -} -#endif - - - /**************************************************************************** get my own name and IP ****************************************************************************/ -BOOL get_myname(char *myname,struct in_addr *ip) +BOOL get_myname(char *my_name,struct in_addr *ip) { struct hostent *hp; pstring hostname; @@ -3675,13 +3225,13 @@ BOOL get_myname(char *myname,struct in_addr *ip) return False; } - if (myname) + if (my_name) { /* split off any parts after an initial . */ char *p = strchr(hostname,'.'); if (p) *p = 0; - strcpy(myname,hostname); + fstrcpy(my_name,hostname); } if (ip) @@ -3696,7 +3246,7 @@ true if two IP addresses are equal ****************************************************************************/ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) { - unsigned long a1,a2; + uint32 a1,a2; a1 = ntohl(ip1.s_addr); a2 = ntohl(ip2.s_addr); return(a1 == a2); @@ -3706,7 +3256,7 @@ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) /**************************************************************************** open a socket of the specified type, port and address for incoming data ****************************************************************************/ -int open_socket_in(int type, int port, int dlevel) +int open_socket_in(int type, int port, int dlevel,uint32 socket_addr) { struct hostent *hp; struct sockaddr_in sock; @@ -3714,11 +3264,7 @@ int open_socket_in(int type, int port, int dlevel) int res; /* get my host name */ -#ifdef MAXHOSTNAMELEN if (gethostname(host_name, MAXHOSTNAMELEN) == -1) -#else - if (gethostname(host_name, sizeof(host_name)) == -1) -#endif { DEBUG(0,("gethostname failed\n")); return -1; } /* get host info */ @@ -3735,7 +3281,7 @@ int open_socket_in(int type, int port, int dlevel) #endif sock.sin_port = htons( port ); sock.sin_family = hp->h_addrtype; - sock.sin_addr.s_addr = INADDR_ANY; + sock.sin_addr.s_addr = socket_addr; res = socket(hp->h_addrtype, type, 0); if (res == -1) { DEBUG(0,("socket failed\n")); return -1; } @@ -3749,16 +3295,16 @@ int open_socket_in(int type, int port, int dlevel) if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { if (port) { - if (port == 139 || port == 137) - DEBUG(dlevel,("bind failed on port %d (%s)\n", - port,strerror(errno))); + if (port == SMB_PORT || port == NMB_PORT) + DEBUG(dlevel,("bind failed on port %d socket_addr=%s (%s)\n", + port,inet_ntoa(sock.sin_addr),strerror(errno))); close(res); if (dlevel > 0 && port < 1000) port = 7999; if (port >= 1000 && port < 9000) - return(open_socket_in(type,port+1,dlevel)); + return(open_socket_in(type,port+1,dlevel,socket_addr)); } return(-1); @@ -3772,10 +3318,12 @@ int open_socket_in(int type, int port, int dlevel) /**************************************************************************** create an outgoing socket **************************************************************************/ -int open_socket_out(int type, struct in_addr *addr, int port ) +int open_socket_out(int type, struct in_addr *addr, int port ,int timeout) { struct sockaddr_in sock_out; - int res; + int res,ret; + int connect_loop = 250; /* 250 milliseconds */ + int loops = (timeout * 1000) / connect_loop; /* create a socket to write to */ res = socket(PF_INET, type, 0); @@ -3790,15 +3338,45 @@ int open_socket_out(int type, struct in_addr *addr, int port ) sock_out.sin_port = htons( port ); sock_out.sin_family = PF_INET; + /* set it non-blocking */ + set_blocking(res,False); + DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port)); /* and connect it to the destination */ - if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) { - DEBUG(0,("connect error: %s\n",strerror(errno))); - close(res); - return(-1); +connect_again: + ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out)); + + /* Some systems return EAGAIN when they mean EINPROGRESS */ + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN) && loops--) { + msleep(connect_loop); + goto connect_again; + } + + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN)) { + DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port)); + close(res); + return -1; + } + +#ifdef EISCONN + if (ret < 0 && errno == EISCONN) { + errno = 0; + ret = 0; + } +#endif + + if (ret < 0) { + DEBUG(1,("error connecting to %s:%d (%s)\n", + inet_ntoa(*addr),port,strerror(errno))); + return -1; } + /* set it blocking again */ + set_blocking(res,True); + return res; } @@ -3847,27 +3425,38 @@ int interpret_security(char *str,int def) /**************************************************************************** interpret an internet address or name into an IP address in 4 byte form ****************************************************************************/ -unsigned long interpret_addr(char *str) +uint32 interpret_addr(char *str) { struct hostent *hp; - unsigned long res; + uint32 res; + int i; + BOOL pure_address = True; if (strcmp(str,"0.0.0.0") == 0) return(0); if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF); + for (i=0; pure_address && str[i]; i++) + if (!(isdigit(str[i]) || str[i] == '.')) + pure_address = False; + /* if it's in the form of an IP address then get the lib to interpret it */ - if (isdigit(str[0])) { + if (pure_address) { res = inet_addr(str); } else { - /* otherwise assume it's a network name of some sort and use Get_Hostbyname */ + /* otherwise assume it's a network name of some sort and use + Get_Hostbyname */ if ((hp = Get_Hostbyname(str)) == 0) { DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str)); return 0; } + if(hp->h_addr == NULL) { + DEBUG(3,("Get_Hostbyname: host address is invalid for host %s.\n",str)); + return 0; + } putip((char *)&res,(char *)hp->h_addr); } - if (res == (unsigned long)-1) return(0); + if (res == (uint32)-1) return(0); return(res); } @@ -3878,8 +3467,8 @@ unsigned long interpret_addr(char *str) struct in_addr *interpret_addr2(char *str) { static struct in_addr ret; - unsigned long a = interpret_addr(str); - putip((char *)&ret,(char *)&a); + uint32 a = interpret_addr(str); + ret.s_addr = a; return(&ret); } @@ -3888,121 +3477,251 @@ struct in_addr *interpret_addr2(char *str) ******************************************************************/ BOOL zero_ip(struct in_addr ip) { - unsigned long a; + uint32 a; putip((char *)&a,(char *)&ip); return(a == 0); } -#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60)) - -/**************************************************************************** -interpret an 8 byte "filetime" structure to a time_t -It's originally in "100ns units since jan 1st 1601" -It appears to be kludge-GMT (at least for file listings). This means -its the GMT you get by taking a localtime and adding the -serverzone. This is NOT the same as GMT in some cases. This routine -converts this to real GMT. -****************************************************************************/ -time_t interpret_long_date(char *p) +/******************************************************************* + matchname - determine if host name matches IP address + ******************************************************************/ +static BOOL matchname(char *remotehost,struct in_addr addr) { - double d; - time_t ret; - uint32 tlow,thigh; - tlow = IVAL(p,0); - thigh = IVAL(p,4); - - if (thigh == 0) return(0); + struct hostent *hp; + int i; + + if ((hp = Get_Hostbyname(remotehost)) == 0) { + DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost)); + return False; + } - d = ((double)thigh)*4.0*(double)(1<<30); - d += (tlow&0xFFF00000); - d *= 1.0e-7; - - /* now adjust by 369 years to make the secs since 1970 */ - d -= TIME_FIXUP_CONSTANT; + /* + * Make sure that gethostbyname() returns the "correct" host name. + * Unfortunately, gethostbyname("localhost") sometimes yields + * "localhost.domain". Since the latter host name comes from the + * local DNS, we just have to trust it (all bets are off if the local + * DNS is perverted). We always check the address list, though. + */ + + if (strcasecmp(remotehost, hp->h_name) + && strcasecmp(remotehost, "localhost")) { + DEBUG(0,("host name/name mismatch: %s != %s", + remotehost, hp->h_name)); + return False; + } + + /* Look up the host address in the address list we just got. */ + for (i = 0; hp->h_addr_list[i]; i++) { + if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0) + return True; + } - if (d>=MAXINT) - return(0); + /* + * The host name does not map to the original host address. Perhaps + * someone has compromised a name server. More likely someone botched + * it, but that could be dangerous, too. + */ + + DEBUG(0,("host name/address mismatch: %s != %s", + inet_ntoa(addr), hp->h_name)); + return False; +} - ret = (time_t)(d+0.5); +/******************************************************************* + Reset the 'done' variables so after a client process is created + from a fork call these calls will be re-done. This should be + expanded if more variables need reseting. + ******************************************************************/ - /* this takes us from kludge-GMT to real GMT */ - ret += TimeDiff(ret) - serverzone; +static BOOL global_client_name_done = False; +static BOOL global_client_addr_done = False; - return(ret); +void reset_globals_after_fork() +{ + global_client_name_done = False; + global_client_addr_done = False; } + +/******************************************************************* + return the DNS name of the client + ******************************************************************/ +char *client_name(void) +{ + extern int Client; + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static pstring name_buf; + struct hostent *hp; + if (global_client_name_done) + return name_buf; -/**************************************************************************** -put a 8 byte filetime from a time_t -This takes real GMT as input and converts to kludge-GMT -****************************************************************************/ -void put_long_date(char *p,time_t t) -{ - uint32 tlow,thigh; - double d; + strcpy(name_buf,"UNKNOWN"); - if (t==0) { - SIVAL(p,0,0); SIVAL(p,4,0); - return; + if (getpeername(Client, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return name_buf; + } + + /* Look up the remote host name. */ + if ((hp = gethostbyaddr((char *) &sockin->sin_addr, + sizeof(sockin->sin_addr), + AF_INET)) == 0) { + DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr())); + StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1); + } else { + StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1); + if (!matchname(name_buf, sockin->sin_addr)) { + DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr())); + strcpy(name_buf,"UNKNOWN"); + } } + global_client_name_done = True; + return name_buf; +} - /* this converts GMT to kludge-GMT */ - t -= TimeDiff(t) - serverzone; +/******************************************************************* + return the IP addr of the client as a string + ******************************************************************/ +char *client_addr(void) +{ + extern int Client; + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static fstring addr_buf; - d = (double) (t); + if (global_client_addr_done) + return addr_buf; - d += TIME_FIXUP_CONSTANT; + strcpy(addr_buf,"0.0.0.0"); - d *= 1.0e7; + if (getpeername(Client, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return addr_buf; + } - thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30)))); - tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30)); + fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); - SIVAL(p,0,tlow); - SIVAL(p,4,thigh); + global_client_addr_done = True; + return addr_buf; } -/******************************************************************* -sub strings with useful parameters -********************************************************************/ -void standard_sub_basic(char *s) +char *automount_server(char *user_name) { - if (!strchr(s,'%')) return; + static pstring server_name; + +#if (defined(NETGROUP) && defined (AUTOMOUNT)) + int nis_error; /* returned by yp all functions */ + char *nis_result; /* yp_match inits this */ + int nis_result_len; /* and set this */ + char *nis_domain; /* yp_get_default_domain inits this */ + char *nis_map = (char *)lp_nis_home_map_name(); + int home_server_len; + + /* set to default of local machine */ + pstrcpy(server_name, local_machine); + + if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) + { + DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); + } - string_sub(s,"%R",remote_proto); - string_sub(s,"%a",remote_arch); - string_sub(s,"%m",remote_machine); - string_sub(s,"%L",local_machine); + DEBUG(5, ("NIS Domain: %s\n", nis_domain)); - if (!strchr(s,'%')) return; + if ((nis_error = yp_match(nis_domain, nis_map, + user_name, strlen(user_name), + &nis_result, &nis_result_len)) != 0) + { + DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); + } - string_sub(s,"%v",VERSION); - string_sub(s,"%h",myhostname); - string_sub(s,"%U",sesssetup_user); + if (!nis_error && lp_nis_home_map()) + { + home_server_len = strcspn(nis_result,":"); + DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len)); + if (home_server_len > sizeof(pstring)) + { + home_server_len = sizeof(pstring); + } + strncpy(server_name, nis_result, home_server_len); + } +#else + /* use the local machine name instead of the auto-map server */ + pstrcpy(server_name, local_machine); +#endif - if (!strchr(s,'%')) return; + DEBUG(4,("Home server: %s\n", server_name)); - string_sub(s,"%I",Client_info.addr); - string_sub(s,"%M",Client_info.name); - string_sub(s,"%T",timestring()); + return server_name; +} - if (!strchr(s,'%')) return; +/******************************************************************* +sub strings with useful parameters +Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and +Paul Rippin <pr3245@nopc.eurostat.cec.be> +********************************************************************/ +void standard_sub_basic(char *str) +{ + char *s, *p; + char pidstr[10]; + struct passwd *pass; + char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user; - { - char pidstr[10]; - sprintf(pidstr,"%d",(int)getpid()); - string_sub(s,"%d",pidstr); - } + for (s = str ; (p = strchr(s,'%')) != NULL ; s = p ) + { + switch (*(p+1)) + { + case 'G' : + { + if ((pass = Get_Pwnam(sesssetup_user,False))!=NULL) + { + string_sub(p,"%G",gidtoname(pass->pw_gid)); + } + else + { + p += 2; + } + break; + } + case 'N' : string_sub(p,"%N", automount_server(username)); break; + case 'I' : string_sub(p,"%I", client_addr()); break; + case 'L' : string_sub(p,"%L", local_machine); break; + case 'M' : string_sub(p,"%M", client_name()); break; + case 'R' : string_sub(p,"%R", remote_proto); break; + case 'T' : string_sub(p,"%T", timestring()); break; + case 'U' : string_sub(p,"%U", username); break; + case 'a' : string_sub(p,"%a", remote_arch); break; + case 'd' : + { + sprintf(pidstr,"%d",(int)getpid()); + string_sub(p,"%d", pidstr); + break; + } + case 'h' : string_sub(p,"%h", myhostname); break; + case 'm' : string_sub(p,"%m", remote_machine); break; + case 'v' : string_sub(p,"%v", VERSION); break; + case '\0': p++; break; /* don't run off end if last character is % */ + default : p+=2; break; + } + } + return; +} - if (!strchr(s,'%')) return; +/******************************************************************* +are two IPs on the same subnet? +********************************************************************/ +BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) +{ + uint32 net1,net2,nmask; - { - struct passwd *pass = Get_Pwnam(sesssetup_user,False); - if (pass) { - string_sub(s,"%G",gidtoname(pass->pw_gid)); - } - } + nmask = ntohl(mask.s_addr); + net1 = ntohl(ip1.s_addr); + net2 = ntohl(ip2.s_addr); + + return((net1 & nmask) == (net2 & nmask)); } @@ -4022,34 +3741,6 @@ int PutUniCode(char *dst,char *src) return(ret); } - -pstring smbrun_path = SMBRUN; - -/**************************************************************************** -run a command via system() using smbrun -****************************************************************************/ -int smbrun(char *cmd,char *outfile) -{ - int ret; - pstring syscmd; - - if (!file_exist(smbrun_path,NULL)) - { - DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",smbrun_path)); - return(1); - } - - sprintf(syscmd,"%s \"(%s 2>&1) > %s\"", - smbrun_path,cmd, - outfile?outfile:"/dev/null"); - - DEBUG(5,("smbrun - running %s ",syscmd)); - ret = system(syscmd); - DEBUG(5,("gave %d\n",ret)); - return(ret); -} - - /**************************************************************************** a wrapper for gethostbyname() that tries with all lower and all upper case if the initial name fails @@ -4071,7 +3762,7 @@ struct hostent *Get_Hostbyname(char *name) return(NULL); } - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -4080,7 +3771,7 @@ struct hostent *Get_Hostbyname(char *name) /* try with all lowercase */ strlower(name2); - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -4089,7 +3780,7 @@ struct hostent *Get_Hostbyname(char *name) /* try with all uppercase */ strupper(name2); - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -4118,7 +3809,7 @@ BOOL process_exists(int pid) fstring s; if (!tested) { tested = True; - sprintf(s,"/proc/%05d",getpid()); + sprintf(s,"/proc/%05d",(int)getpid()); ok = file_exist(s,NULL); } if (ok) { @@ -4127,11 +3818,8 @@ BOOL process_exists(int pid) } } - /* a best guess for non root access */ - if (geteuid() != 0) return(True); - - /* otherwise use kill */ - return(pid == getpid() || kill(pid,0) == 0); + /* CGH 8/16/96 - added ESRCH test */ + return(pid == getpid() || kill(pid,0) == 0 || errno != ESRCH); #endif } @@ -4163,16 +3851,20 @@ char *gidtoname(int gid) /******************************************************************* block sigs ********************************************************************/ -void BlockSignals(BOOL block) +void BlockSignals(BOOL block,int signum) { #ifdef USE_SIGBLOCK - int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV) - |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)| - sigmask(SIGINT)); + int block_mask = sigmask(signum); + static int oldmask = 0; if (block) - sigblock(block_mask); + oldmask = sigblock(block_mask); else - sigunblock(block_mask); + sigsetmask(oldmask); +#elif defined(USE_SIGPROCMASK) + sigset_t set; + sigemptyset(&set); + sigaddset(&set,signum); + sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL); #endif } @@ -4182,8 +3874,7 @@ my own panic function - not suitable for general use ********************************************************************/ void ajt_panic(void) { - pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &"; - smbrun(cmd,NULL); + system("/usr/bin/X11/xedit -display ljus:0 /tmp/ERROR_FAULT"); } #endif @@ -4209,15 +3900,6 @@ char *readdirname(void *p) dname = ptr->d_name; -#ifdef KANJI - { - static pstring buf; - strcpy(buf, dname); - unix_to_dos(buf, True); - dname = buf; - } -#endif - #ifdef NEXT2 if (telldir(p) < 0) return(NULL); #endif @@ -4233,278 +3915,621 @@ char *readdirname(void *p) broken_readdir = True; } if (broken_readdir) - return(dname-2); + dname = dname - 2; } #endif + { + static pstring buf; + pstrcpy(buf, dname); + unix_to_dos(buf, True); + dname = buf; + } + return(dname); } +/******************************************************************* + Utility function used to decide if the last component + of a path matches a (possibly wildcarded) entry in a namelist. +********************************************************************/ +BOOL is_in_path(char *name, name_compare_entry *namelist) +{ + pstring last_component; + char *p; -#if (defined(SecureWare) && defined(SCO)) -/* This is needed due to needing the nap() function but we don't want - to include the Xenix libraries since that will break other things... - BTW: system call # 0x0c28 is the same as calling nap() */ -long nap(long milliseconds) { - return syscall(0x0c28, milliseconds); -} -#endif + DEBUG(8, ("is_in_path: %s\n", name)); -#ifdef NO_INITGROUPS -#include <sys/types.h> -#include <limits.h> -#include <grp.h> + /* if we have no list it's obviously not in the path */ + if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) + { + DEBUG(8,("is_in_path: no name list.\n")); + return False; + } -#ifndef NULL -#define NULL (void *)0 -#endif + /* Get the last component of the unix name. */ + p = strrchr(name, '/'); + strncpy(last_component, p ? p : name, sizeof(last_component)-1); + last_component[sizeof(last_component)-1] = '\0'; -/**************************************************************************** - some systems don't have an initgroups call -****************************************************************************/ -int initgroups(char *name,gid_t id) -{ -#ifdef NO_SETGROUPS - /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ - return(0); -#else - gid_t grouplst[NGROUPS_MAX]; - int i,j; - struct group *g; - char *gr; - - grouplst[0] = id; - i = 1; - while (i < NGROUPS_MAX && - ((g = (struct group *)getgrent()) != (struct group *)NULL)) + for(; namelist->name != NULL; namelist++) + { + if(namelist->is_wild) { - if (g->gr_gid == id) - continue; - j = 0; - gr = g->gr_mem[0]; - while (gr && (*gr != (char)NULL)) { - if (strcmp(name,gr) == 0) { - grouplst[i] = g->gr_gid; - i++; - gr = (char *)NULL; - break; - } - gr = g->gr_mem[++j]; + /* look for a wildcard match. */ + if (mask_match(last_component, namelist->name, case_sensitive, False)) + { + DEBUG(8,("is_in_path: mask match succeeded\n")); + return True; } } - endgrent(); - return(setgroups(i,grouplst)); -#endif + else + { + if((case_sensitive && (strcmp(last_component, namelist->name) == 0))|| + (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0))) + { + DEBUG(8,("is_in_path: match succeeded\n")); + return True; + } + } + } + DEBUG(8,("is_in_path: match not found\n")); + + return False; } -#endif +/******************************************************************* + Strip a '/' separated list into an array of + name_compare_enties structures suitable for + passing to is_in_path(). We do this for + speed so we can pre-parse all the names in the list + and don't do it for each call to is_in_path(). + namelist is modified here and is assumed to be + a copy owned by the caller. + We also check if the entry contains a wildcard to + remove a potentially expensive call to mask_match + if possible. +********************************************************************/ + +void set_namearray(name_compare_entry **ppname_array, char *namelist) +{ + char *name_end; + char *nameptr = namelist; + int num_entries = 0; + int i; + + (*ppname_array) = NULL; + + if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) + return; + + /* We need to make two passes over the string. The + first to count the number of elements, the second + to split it. + */ + while(*nameptr) + { + if ( *nameptr == '/' ) + { + /* cope with multiple (useless) /s) */ + nameptr++; + continue; + } + /* find the next / */ + name_end = strchr(nameptr, '/'); + + /* oops - the last check for a / didn't find one. */ + if (name_end == NULL) + break; + + /* next segment please */ + nameptr = name_end + 1; + num_entries++; + } + + if(num_entries == 0) + return; + + if(( (*ppname_array) = (name_compare_entry *)malloc( + (num_entries + 1) * sizeof(name_compare_entry))) == NULL) + { + DEBUG(0,("set_namearray: malloc fail\n")); + return; + } + + /* Now copy out the names */ + nameptr = namelist; + i = 0; + while(*nameptr) + { + if ( *nameptr == '/' ) + { + /* cope with multiple (useless) /s) */ + nameptr++; + continue; + } + /* find the next / */ + if ((name_end = strchr(nameptr, '/')) != NULL) + { + *name_end = 0; + } + + /* oops - the last check for a / didn't find one. */ + if(name_end == NULL) + break; + + (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) || + (strchr( nameptr, '*')!=NULL)); + if(((*ppname_array)[i].name = strdup(nameptr)) == NULL) + { + DEBUG(0,("set_namearray: malloc fail (1)\n")); + return; + } -#if WRAP_MALLOC + /* next segment please */ + nameptr = name_end + 1; + i++; + } + + (*ppname_array)[i].name = NULL; -/* undo the wrapping temporarily */ -#undef malloc -#undef realloc -#undef free + return; +} /**************************************************************************** -wrapper for malloc() to catch memory errors +routine to free a namearray. ****************************************************************************/ -void *malloc_wrapped(int size,char *file,int line) + +void free_namearray(name_compare_entry *name_array) { -#ifdef xx_old_malloc - void *res = xx_old_malloc(size); -#else - void *res = malloc(size); -#endif - DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n", - file,line, - size,(unsigned int)res)); - return(res); + if(name_array == 0) + return; + + if(name_array->name != NULL) + free(name_array->name); + + free((char *)name_array); } /**************************************************************************** -wrapper for realloc() to catch memory errors +routine to do file locking ****************************************************************************/ -void *realloc_wrapped(void *ptr,int size,char *file,int line) +BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) { -#ifdef xx_old_realloc - void *res = xx_old_realloc(ptr,size); +#if HAVE_FCNTL_LOCK + struct flock lock; + int ret; + +#if 1 + uint32 mask = 0xC0000000; + + /* make sure the count is reasonable, we might kill the lockd otherwise */ + count &= ~mask; + + /* the offset is often strange - remove 2 of its bits if either of + the top two bits are set. Shift the top ones by two bits. This + still allows OLE2 apps to operate, but should stop lockd from + dieing */ + if ((offset & mask) != 0) + offset = (offset & ~mask) | ((offset & mask) >> 2); #else - void *res = realloc(ptr,size); + uint32 mask = ((unsigned)1<<31); + + /* interpret negative counts as large numbers */ + if (count < 0) + count &= ~mask; + + /* no negative offsets */ + offset &= ~mask; + + /* count + offset must be in range */ + while ((offset < 0 || (offset + count < 0)) && mask) + { + offset &= ~mask; + mask = mask >> 1; + } #endif - DEBUG(3,("Realloc\n")); - DEBUG(3,("free called from %s(%d) with ptr=0x%X\n", - file,line, - (unsigned int)ptr)); - DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n", - file,line, - size,(unsigned int)res)); - return(res); -} -/**************************************************************************** -wrapper for free() to catch memory errors -****************************************************************************/ -void free_wrapped(void *ptr,char *file,int line) -{ -#ifdef xx_old_free - xx_old_free(ptr); + + DEBUG(8,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); + + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = (int)offset; + lock.l_len = (int)count; + lock.l_pid = 0; + + errno = 0; + + ret = fcntl(fd,op,&lock); + + if (errno != 0) + DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); + + /* a lock query */ + if (op == F_GETLK) + { + if ((ret != -1) && + (lock.l_type != F_UNLCK) && + (lock.l_pid != 0) && + (lock.l_pid != getpid())) + { + DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid)); + return(True); + } + + /* it must be not locked or locked by me */ + return(False); + } + + /* a lock set or unset */ + if (ret == -1) + { + DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n", + offset,count,op,type,strerror(errno))); + + /* perhaps it doesn't support this sort of locking?? */ + if (errno == EINVAL) + { + DEBUG(3,("locking not supported? returning True\n")); + return(True); + } + + return(False); + } + + /* everything went OK */ + DEBUG(8,("Lock call successful\n")); + + return(True); #else - free(ptr); + return(False); #endif - DEBUG(3,("free called from %s(%d) with ptr=0x%X\n", - file,line,(unsigned int)ptr)); - return; } -/* and re-do the define for spots lower in this file */ -#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__) -#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__) -#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__) +/******************************************************************* +lock a file - returning a open file descriptor or -1 on failure +The timeout is in seconds. 0 means no timeout +********************************************************************/ +int file_lock(char *name,int timeout) +{ + int fd = open(name,O_RDWR|O_CREAT,0666); + time_t t=0; + if (fd < 0) return(-1); +#if HAVE_FCNTL_LOCK + if (timeout) t = time(NULL); + while (!timeout || (time(NULL)-t < timeout)) { + if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd); + msleep(LOCK_RETRY_TIMEOUT); + } + return(-1); +#else + return(fd); #endif +} -#ifdef REPLACE_STRSTR -/**************************************************************************** -Mips version of strstr doesn't seem to work correctly. -There is a #define in includes.h to redirect calls to this function. -****************************************************************************/ -char *Strstr(char *s, char *p) +/******************************************************************* +unlock a file locked by file_lock +********************************************************************/ +void file_unlock(int fd) { - int len = strlen(p); + if (fd<0) return; +#if HAVE_FCNTL_LOCK + fcntl_lock(fd,F_SETLK,0,1,F_UNLCK); +#endif + close(fd); +} - while ( *s != '\0' ) { - if ( strncmp(s, p, len) == 0 ) - return s; - s++; - } +/******************************************************************* +is the name specified one of my netbios names +returns true is it is equal, false otherwise +********************************************************************/ +BOOL is_myname(char *s) +{ + int n; + BOOL ret = False; - return NULL; + for (n=0; my_netbios_names[n]; n++) { + if (strequal(my_netbios_names[n], s)) + ret=True; + } + DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret)); + return(ret); } -#endif /* REPLACE_STRSTR */ - -#ifdef REPLACE_MKTIME /******************************************************************* -a mktime() replacement for those who don't have it - contributed by -C.A. Lademann <cal@zls.com> +set the horrid remote_arch string based on an enum. ********************************************************************/ -#define MINUTE 60 -#define HOUR 60*MINUTE -#define DAY 24*HOUR -#define YEAR 365*DAY -time_t Mktime(struct tm *t) -{ - struct tm *u; - time_t epoch = 0; - int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - y, m, i; - - if(t->tm_year < 70) - return((time_t)-1); - - epoch = (t->tm_year - 70) * YEAR + - (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY; - - y = t->tm_year; - m = 0; - - for(i = 0; i < t->tm_mon; i++) { - epoch += mon [m] * DAY; - if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) - epoch += DAY; - - if(++m > 11) { - m = 0; - y++; - } +void set_remote_arch(enum remote_arch_types type) +{ + ra_type = type; + switch( type ) + { + case RA_WFWG: + strcpy(remote_arch, "WfWg"); + return; + case RA_OS2: + strcpy(remote_arch, "OS2"); + return; + case RA_WIN95: + strcpy(remote_arch, "Win95"); + return; + case RA_WINNT: + strcpy(remote_arch, "WinNT"); + return; + case RA_SAMBA: + strcpy(remote_arch,"Samba"); + return; + default: + ra_type = RA_UNKNOWN; + strcpy(remote_arch, "UNKNOWN"); + break; } +} - epoch += (t->tm_mday - 1) * DAY; - epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec; - - if((u = localtime(&epoch)) != NULL) { - t->tm_sec = u->tm_sec; - t->tm_min = u->tm_min; - t->tm_hour = u->tm_hour; - t->tm_mday = u->tm_mday; - t->tm_mon = u->tm_mon; - t->tm_year = u->tm_year; - t->tm_wday = u->tm_wday; - t->tm_yday = u->tm_yday; - t->tm_isdst = u->tm_isdst; -#ifndef NO_TM_NAME - memcpy(t->tm_name, u->tm_name, LTZNMAX); -#endif +/******************************************************************* + Get the remote_arch type. +********************************************************************/ +enum remote_arch_types get_remote_arch() +{ + return ra_type; +} + + +/******************************************************************* +skip past some unicode strings in a buffer +********************************************************************/ +char *skip_unicode_string(char *buf,int n) +{ + while (n--) + { + while (*buf) + buf += 2; + buf += 2; } + return(buf); +} + +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistrn2(uint16 *buf, int len) +{ + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + nexti = (nexti+1)%8; + for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++) + { + *p = *buf; + } + *p = 0; + return lbuf; +} + +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistr2(uint16 *buf) +{ + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + nexti = (nexti+1)%8; + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++) + { + *p = *buf; + } + *p = 0; + return lbuf; +} + +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistr(char *buf) +{ + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + + nexti = (nexti+1)%8; - return(epoch); + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf += 2) + { + *p = *buf; + } + *p = 0; + return lbuf; } -#endif /* REPLACE_MKTIME */ +/******************************************************************* +strncpy for unicode strings +********************************************************************/ +int unistrncpy(char *dst, char *src, int len) +{ + int num_wchars = 0; + + while (*src && len > 0) + { + *dst++ = *src++; + *dst++ = *src++; + len--; + num_wchars++; + } + *dst++ = 0; + *dst++ = 0; + return num_wchars; +} -#ifdef REPLACE_RENAME -/* Rename a file. (from libiberty in GNU binutils) */ -int -rename (zfrom, zto) - const char *zfrom; - const char *zto; + +/******************************************************************* +strcpy for unicode strings. returns length (in num of wide chars) +********************************************************************/ +int unistrcpy(char *dst, char *src) { - if (link (zfrom, zto) < 0) - { - if (errno != EEXIST) - return -1; - if (unlink (zto) < 0 - || link (zfrom, zto) < 0) - return -1; - } - return unlink (zfrom); + int num_wchars = 0; + + while (*src) + { + *dst++ = *src++; + *dst++ = *src++; + num_wchars++; + } + *dst++ = 0; + *dst++ = 0; + + return num_wchars; } -#endif -#ifdef REPLACE_INNETGR -/* - * Search for a match in a netgroup. This replaces it on broken systems. - */ -int InNetGr(group, host, user, dom) - char *group, *host, *user, *dom; +/******************************************************************* +safe string copy into a fstring +********************************************************************/ +void fstrcpy(char *dest, char *src) { - char *hst, *usr, *dm; - - setnetgrent(group); - while (getnetgrent(&hst, &usr, &dm)) - if (((host == 0) || (hst == 0) || !strcmp(host, hst)) && - ((user == 0) || (usr == 0) || !strcmp(user, usr)) && - ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) { - endnetgrent(); - return (1); + int maxlength = sizeof(fstring) - 1; + if (!dest) { + DEBUG(0,("ERROR: NULL dest in fstrcpy\n")); + return; + } + + if (!src) { + *dest = 0; + return; + } + + while (maxlength-- && *src) + *dest++ = *src++; + *dest = 0; + if (*src) { + DEBUG(0,("ERROR: string overflow by %d in fstrcpy\n", + strlen(src))); + } +} + +/******************************************************************* +safe string copy into a pstring +********************************************************************/ +void pstrcpy(char *dest, char *src) +{ + int maxlength = sizeof(pstring) - 1; + if (!dest) { + DEBUG(0,("ERROR: NULL dest in pstrcpy\n")); + return; + } + + if (!src) { + *dest = 0; + return; } - endnetgrent(); - return (0); + + while (maxlength-- && *src) + *dest++ = *src++; + *dest = 0; + if (*src) { + DEBUG(0,("ERROR: string overflow by %d in pstrcpy\n", + strlen(src))); + } +} + + +/******************************************************************* +align a pointer to a multiple of 4 bytes +********************************************************************/ +char *align4(char *q, char *base) +{ + if ((q - base) & 3) + { + q += 4 - ((q - base) & 3); + } + return q; } -#endif +/******************************************************************* +align a pointer to a multiple of 2 bytes +********************************************************************/ +char *align2(char *q, char *base) +{ + if ((q - base) & 1) + { + q++; + } + return q; +} -#if WRAP_MEMCPY -#undef memcpy /******************************************************************* -a wrapper around memcpy for diagnostic purposes +align a pointer to a multiple of align_offset bytes. looks like it +will work for offsets of 0, 2 and 4... ********************************************************************/ -void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line) +char *align_offset(char *q, char *base, int align_offset_len) { - if (l>64 && (((int)d)%4) != (((int)s)%4)) - DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line)); -#ifdef xx_old_memcpy - return(xx_old_memcpy(d,s,l)); -#else - return(memcpy(d,s,l)); -#endif + int mod = ((q - base) & (align_offset_len-1)); + if (align_offset_len != 0 && mod != 0) + { + q += align_offset_len - mod; + } + return q; +} + +static void print_asc(int level, unsigned char *buf,int len) +{ + int i; + for (i=0;i<len;i++) + DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.')); +} + +void dump_data(int level,char *buf1,int len) +{ + unsigned char *buf = (unsigned char *)buf1; + int i=0; + if (len<=0) return; + + DEBUG(level,("[%03X] ",i)); + for (i=0;i<len;) { + DEBUG(level,("%02X ",(int)buf[i])); + i++; + if (i%8 == 0) DEBUG(level,(" ")); + if (i%16 == 0) { + print_asc(level,&buf[i-16],8); DEBUG(level,(" ")); + print_asc(level,&buf[i-8],8); DEBUG(level,("\n")); + if (i<len) DEBUG(level,("[%03X] ",i)); + } + } + if (i%16) { + int n; + + n = 16 - (i%16); + DEBUG(level,(" ")); + if (n>8) DEBUG(level,(" ")); + while (n--) DEBUG(level,(" ")); + + n = MIN(8,i%16); + print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" ")); + n = (i%16) - n; + if (n>0) print_asc(level,&buf[i-n],n); + DEBUG(level,("\n")); + } } -#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__) -#endif +char *tab_depth(int depth) +{ + static pstring spaces; + memset(spaces, ' ', depth * 4); + spaces[depth * 4] = 0; + return spaces; +} |