diff options
Diffstat (limited to 'source/lib/util.c')
-rw-r--r-- | source/lib/util.c | 5002 |
1 files changed, 2662 insertions, 2340 deletions
diff --git a/source/lib/util.c b/source/lib/util.c index 7bd6298c4ca..8561c4f3f4a 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-1998 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,41 +20,44 @@ */ #include "includes.h" -#include "loadparm.h" + +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) +#ifdef WITH_NISPLUS_HOME +#include <rpcsvc/nis.h> +#else +#include "rpcsvc/ypclnt.h" +#endif +#endif + +#ifdef WITH_SSL +#include <ssl.h> +#undef Realloc /* SSLeay defines this and samba has a function of this name */ +extern SSL *ssl; +extern int sslFd; +#endif /* WITH_SSL */ pstring scope = ""; -int DEBUGLEVEL = 1; +extern int DEBUGLEVEL; 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,""}; -/* these are some file handles where debug info will be stored */ -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,13 +66,6 @@ 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"; -int syslog_level; - /* the following control case operations - they are put here so the client can link easily */ BOOL case_sensitive; @@ -81,448 +77,39 @@ 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=""; - - -static char *filename_dos(char *path,char *buf); - -static BOOL stdout_logging = False; - - -/******************************************************************* - get ready for syslog stuff - ******************************************************************/ -void setup_logging(char *pname,BOOL interactive) -{ -#ifdef SYSLOG - if (!interactive) { - char *p = strrchr(pname,'/'); - if (p) pname = p+1; - openlog(pname, LOG_PID, LOG_DAEMON); - } -#endif - if (interactive) { - stdout_logging = True; - dbf = stdout; - } -} +pstring sesssetup_user=""; +pstring samlogon_user=""; -BOOL append_log=False; +BOOL sam_logon_in_ssb = False; +pstring global_myname = ""; +fstring global_myworkgroup = ""; +char **my_netbios_names; -/**************************************************************************** -reopen the log files -****************************************************************************/ -void reopen_logs(void) -{ - extern FILE *dbf; - pstring fname; - - if (DEBUGLEVEL > 0) - { - strcpy(fname,debugf); - if (lp_loaded() && (*lp_logfile())) - strcpy(fname,lp_logfile()); +int smb_read_error = 0; - if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL)) - { - strcpy(debugf,fname); - if (dbf) fclose(dbf); - if (append_log) - dbf = fopen(debugf,"a"); - else - dbf = fopen(debugf,"w"); - if (dbf) setbuf(dbf,NULL); - } - } - else - { - if (dbf) - { - fclose(dbf); - dbf = NULL; - } - } -} - - -/******************************************************************* -write an debug message on the debugfile. This is called by the DEBUG -macro -********************************************************************/ -#ifdef __STDC__ -int Debug1(char *format_str, ...) -{ -#else -int Debug1(va_alist) -va_dcl -{ - char *format_str; -#endif - va_list ap; - -#ifdef __STDC__ - va_start(ap, format_str); -#else - va_start(ap); - format_str = va_arg(ap,char *); -#endif +static char *filename_dos(char *path,char *buf); - if (stdout_logging) { - vfprintf(dbf,format_str,ap); - va_end(ap); - 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); - } - } - -#ifdef SYSLOG - if (syslog_level < lp_syslog()) - { - /* - * map debug levels to syslog() priorities - * note that not all DEBUG(0, ...) calls are - * necessarily errors - */ - static int priority_map[] = { - LOG_ERR, /* 0 */ - LOG_WARNING, /* 1 */ - LOG_NOTICE, /* 2 */ - LOG_INFO, /* 3 */ - }; - int priority; - pstring msgbuf; - - if (syslog_level >= sizeof(priority_map) / sizeof(priority_map[0]) || - syslog_level < 0) - priority = LOG_DEBUG; - else - priority = priority_map[syslog_level]; - - vsprintf(msgbuf, format_str, ap); - - msgbuf[255] = '\0'; - syslog(priority, "%s", msgbuf); - } -#endif - -#ifdef SYSLOG - 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) + find a suitable temporary directory. The result should be copied immediately + as it may be overwritten by a subsequent call + ****************************************************************************/ +char *tmpdir(void) { -#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; -#else - timediff = mktime(&tm_utc) - mktime(&tm_local); -#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; - } - - 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; - } - -/* - 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)); -*/ + char *p; + if ((p = getenv("TMPDIR"))) { + return p; } -#endif - - return((is_dst?60*60:0) - (extra_time_offset*60)); + return "/tmp"; } -/**************************************************************************** -return the difference between local and GMT time -****************************************************************************/ -int TimeDiff(time_t t) -{ - static BOOL initialised = False; - if (!initialised) {initialised=True; TimeInit();} - return(timediff - DSTDiff(t)); -} - -/**************************************************************************** -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)); -} /**************************************************************************** @@ -544,10 +131,11 @@ static char *last_ptr=NULL; Based on a routine by GJC@VILLAGE.COM. Extensively modified by Andrew.Tridgell@anu.edu.au ****************************************************************************/ -BOOL next_token(char **ptr,char *buff,char *sep) +BOOL next_token(char **ptr,char *buff,char *sep, int bufsize) { char *s; BOOL quoted; + int len=1; if (!ptr) ptr = &last_ptr; if (!ptr) return(False); @@ -564,12 +152,14 @@ BOOL next_token(char **ptr,char *buff,char *sep) if (! *s) return(False); /* copy over the token */ - for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++) + for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) { - if (*s == '\"') - quoted = !quoted; - else - *buff++ = *s; + if (*s == '\"') { + quoted = !quoted; + } else { + len++; + *buff++ = *s; + } } *ptr = (*s) ? s+1 : s; @@ -616,71 +206,10 @@ char **toktocliplist(int *ctok, char *sep) return ret; } -#ifndef HAVE_MEMMOVE -/******************************************************************* -safely copies memory, ensuring no overlap problems. -this is only used if the machine does not have it's own memmove(). -this is not the fastest algorithm in town, but it will do for our -needs. -********************************************************************/ -void *MemMove(void *dest,void *src,int size) -{ - unsigned long d,s; - int i; - if (dest==src || !size) return(dest); - - d = (unsigned long)dest; - s = (unsigned long)src; - - if ((d >= (s+size)) || (s >= (d+size))) { - /* no overlap */ - memcpy(dest,src,size); - return(dest); - } - - if (d < s) - { - /* we can forward copy */ - if (s-d >= sizeof(int) && - !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { - /* do it all as words */ - int *idest = (int *)dest; - int *isrc = (int *)src; - size /= sizeof(int); - for (i=0;i<size;i++) idest[i] = isrc[i]; - } else { - /* simplest */ - char *cdest = (char *)dest; - char *csrc = (char *)src; - for (i=0;i<size;i++) cdest[i] = csrc[i]; - } - } - else - { - /* must backward copy */ - if (d-s >= sizeof(int) && - !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { - /* do it all as words */ - int *idest = (int *)dest; - int *isrc = (int *)src; - size /= sizeof(int); - for (i=size-1;i>=0;i--) idest[i] = isrc[i]; - } else { - /* simplest */ - char *cdest = (char *)dest; - char *csrc = (char *)src; - for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; - } - } - return(dest); -} -#endif - - /**************************************************************************** prompte a dptr (to make it recently used) ****************************************************************************/ -void array_promote(char *array,int elsize,int element) +static void array_promote(char *array,int elsize,int element) { char *p; if (element == 0) @@ -733,6 +262,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}}; @@ -742,9 +277,9 @@ set user socket options ****************************************************************************/ void set_socket_options(int fd, char *options) { - string tok; + fstring tok; - while (next_token(&options,tok," \t,")) + while (next_token(&options,tok," \t,", sizeof(tok))) { int ret=0,i; int value = 1; @@ -800,50 +335,28 @@ void set_socket_options(int fd, char *options) ****************************************************************************/ void close_sockets(void ) { +#ifdef WITH_SSL + sslutil_disconnect(Client); +#endif /* WITH_SSL */ + close(Client); Client = 0; } /**************************************************************************** - 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) +BOOL in_group(gid_t group, int current_gid, int ngroups, GID_T *groups) { - int i; + int i; - if (group == current_gid) return(True); + if (group == current_gid) return(True); - for (i=0;i<ngroups;i++) - if (group == groups[i]) - return(True); + for (i=0;i<ngroups;i++) + if (group == groups[i]) + return(True); - return(False); + return(False); } /**************************************************************************** @@ -853,13 +366,8 @@ char *StrCpy(char *dest,char *src) { char *d = dest; -#if AJT /* I don't want to get lazy with these ... */ - if (!dest || !src) { - DEBUG(0,("ERROR: NULL StrCpy() called!\n")); - ajt_panic(); - } -#endif + SMB_ASSERT(dest && src); if (!dest) return(NULL); if (!src) { @@ -873,7 +381,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); @@ -896,6 +404,46 @@ void putip(void *dest,void *src) } +#define TRUNCATE_NETBIOS_NAME 1 + +/******************************************************************* + convert, possibly using a stupid microsoft-ism which has destroyed + the transport independence of netbios (for CIFS vendors that usually + use the Win95-type methods, not for NT to NT communication, which uses + DCE/RPC and therefore full-length unicode strings...) a dns name into + a netbios name. + + the netbios name (NOT necessarily null-terminated) is truncated to 15 + characters. + + ******************************************************************/ +char *dns_to_netbios_name(char *dns_name) +{ + static char netbios_name[16]; + int i; + StrnCpy(netbios_name, dns_name, 15); + netbios_name[15] = 0; + +#ifdef TRUNCATE_NETBIOS_NAME + /* ok. this is because of a stupid microsoft-ism. if the called host + name contains a '.', microsoft clients expect you to truncate the + netbios name up to and including the '.' this even applies, by + mistake, to workgroup (domain) names, which is _really_ daft. + */ + for (i = 15; i >= 0; i--) + { + if (netbios_name[i] == '.') + { + netbios_name[i] = 0; + break; + } + } +#endif /* TRUNCATE_NETBIOS_NAME */ + + return netbios_name; +} + + /**************************************************************************** interpret the weird netbios "name". Return the name type ****************************************************************************/ @@ -938,58 +486,71 @@ 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)slprintf( buf, sizeof(buf) - 1, "%-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 ********************************************************************/ -BOOL file_exist(char *fname,struct stat *sbuf) +BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf) { - struct stat st; + SMB_STRUCT_STAT st; if (!sbuf) sbuf = &st; - if (sys_stat(fname,sbuf) != 0) + if (dos_stat(fname,sbuf) != 0) return(False); return(S_ISREG(sbuf->st_mode)); @@ -1000,9 +561,9 @@ check a files mod time ********************************************************************/ time_t file_modtime(char *fname) { - struct stat st; + SMB_STRUCT_STAT st; - if (sys_stat(fname,&st) != 0) + if (dos_stat(fname,&st) != 0) return(0); return(st.st_mtime); @@ -1011,196 +572,48 @@ time_t file_modtime(char *fname) /******************************************************************* check if a directory exists ********************************************************************/ -BOOL directory_exist(char *dname,struct stat *st) +BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st) { - struct stat st2; + SMB_STRUCT_STAT st2; + BOOL ret; + if (!st) st = &st2; - if (sys_stat(dname,st) != 0) + if (dos_stat(dname,st) != 0) return(False); - return(S_ISDIR(st->st_mode)); + ret = S_ISDIR(st->st_mode); + if(!ret) + errno = ENOTDIR; + return ret; } /******************************************************************* returns the size in bytes of the named file ********************************************************************/ -uint32 file_size(char *file_name) +SMB_OFF_T file_size(char *file_name) { - struct stat buf; + SMB_STRUCT_STAT buf; buf.st_size = 0; - sys_stat(file_name,&buf); + dos_stat(file_name,&buf); 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 ********************************************************************/ char *attrib_string(int mode) { - static char attrstr[10]; + static fstring attrstr; attrstr[0] = 0; - if (mode & aVOLID) strcat(attrstr,"V"); - if (mode & aDIR) strcat(attrstr,"D"); - if (mode & aARCH) strcat(attrstr,"A"); - if (mode & aHIDDEN) strcat(attrstr,"H"); - if (mode & aSYSTEM) strcat(attrstr,"S"); - if (mode & aRONLY) strcat(attrstr,"R"); + if (mode & aVOLID) fstrcat(attrstr,"V"); + if (mode & aDIR) fstrcat(attrstr,"D"); + if (mode & aARCH) fstrcat(attrstr,"A"); + if (mode & aHIDDEN) fstrcat(attrstr,"H"); + if (mode & aSYSTEM) fstrcat(attrstr,"S"); + if (mode & aRONLY) fstrcat(attrstr,"R"); return(attrstr); } @@ -1211,10 +624,72 @@ 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) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + 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 +697,89 @@ 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) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + 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++; + n--; + } - 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 +816,51 @@ BOOL strcsequal(char *s1,char *s2) void strlower(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + 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)) - *s = tolower(*s); - s++; - } -#else - if (isupper(*s)) - *s = tolower(*s); - s++; -#endif /* KANJI */ + /* 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 */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else + { + if (isupper(*s)) + *s = tolower(*s); + s++; + } + } + } } /******************************************************************* @@ -1296,23 +869,51 @@ void strlower(char *s) void strupper(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + 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)) - *s = toupper(*s); - s++; - } -#else - if (islower(*s)) - *s = toupper(*s); - s++; -#endif + /* 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 */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else + { + if (islower(*s)) + *s = toupper(*s); + s++; + } + } + } } /******************************************************************* @@ -1343,24 +944,19 @@ BOOL strisnormal(char *s) ****************************************************************************/ void string_replace(char *s,char oldc,char newc) { + int skip; while (*s) + { + skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { -#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 */ } + } } /**************************************************************************** @@ -1368,18 +964,7 @@ void string_replace(char *s,char oldc,char newc) ****************************************************************************/ void unix_format(char *fname) { - pstring namecopy; string_replace(fname,'\\','/'); -#ifndef KANJI - dos2unix_format(fname, True); -#endif /* KANJI */ - - if (*fname == '/') - { - strcpy(namecopy,fname); - strcpy(fname,"."); - strcat(fname,namecopy); - } } /**************************************************************************** @@ -1387,49 +972,53 @@ void unix_format(char *fname) ****************************************************************************/ void dos_format(char *fname) { -#ifndef KANJI - unix2dos_format(fname, True); -#endif /* KANJI */ string_replace(fname,'/','\\'); } - /******************************************************************* show a smb message structure ********************************************************************/ void show_msg(char *buf) { - int i; - int bcc=0; - if (DEBUGLEVEL < 5) - return; + int i; + int bcc=0; + + if (DEBUGLEVEL < 5) return; + + DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n", + smb_len(buf), + (int)CVAL(buf,smb_com), + (int)CVAL(buf,smb_rcls), + (int)CVAL(buf,smb_reh), + (int)SVAL(buf,smb_err), + (int)CVAL(buf,smb_flg), + (int)SVAL(buf,smb_flg2))); + DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", + (int)SVAL(buf,smb_tid), + (int)SVAL(buf,smb_pid), + (int)SVAL(buf,smb_uid), + (int)SVAL(buf,smb_mid), + (int)CVAL(buf,smb_wct))); + + for (i=0;i<(int)CVAL(buf,smb_wct);i++) + { + DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i, + SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i))); + } - DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n", - smb_len(buf), - (int)CVAL(buf,smb_com), - (int)CVAL(buf,smb_rcls), - (int)CVAL(buf,smb_reh), - (int)SVAL(buf,smb_err), - (int)CVAL(buf,smb_flg), - (int)SVAL(buf,smb_flg2))); - DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", - (int)SVAL(buf,smb_tid), - (int)SVAL(buf,smb_pid), - (int)SVAL(buf,smb_uid), - (int)SVAL(buf,smb_mid), - (int)CVAL(buf,smb_wct))); - for (i=0;i<(int)CVAL(buf,smb_wct);i++) - DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i, - SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i))); - bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); - 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))); - DEBUG(10,("\n")); -} + bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); + DEBUG(5,("smb_bcc=%d\n",bcc)); + + if (DEBUGLEVEL < 10) return; + + if (DEBUGLEVEL < 50) + { + bcc = MIN(bcc, 512); + } + + dump_data(10, smb_buf(buf), bcc); +} /******************************************************************* return the length of an smb packet ********************************************************************/ @@ -1478,7 +1067,7 @@ int set_message(char *buf,int num_words,int num_bytes,BOOL zero) /******************************************************************* return the number of smb words ********************************************************************/ -int smb_numwords(char *buf) +static int smb_numwords(char *buf) { return (CVAL(buf,smb_wct)); } @@ -1494,7 +1083,7 @@ int smb_buflen(char *buf) /******************************************************************* return a pointer to the smb_buf data area ********************************************************************/ -int smb_buf_ofs(char *buf) +static int smb_buf_ofs(char *buf) { return (smb_size + CVAL(buf,smb_wct)*2); } @@ -1512,7 +1101,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); } @@ -1532,23 +1121,30 @@ trim the specified elements off the front and back of a string BOOL trim_string(char *s,char *front,char *back) { BOOL ret = False; - while (front && *front && strncmp(s,front,strlen(front)) == 0) - { - char *p = s; - ret = True; - while (1) - { - if (!(*p = p[strlen(front)])) - break; - p++; - } - } - while (back && *back && strlen(s) >= strlen(back) && - (strncmp(s+strlen(s)-strlen(back),back,strlen(back))==0)) + size_t front_len = (front && *front) ? strlen(front) : 0; + size_t back_len = (back && *back) ? strlen(back) : 0; + size_t s_len; + + while (front_len && strncmp(s, front, front_len) == 0) + { + char *p = s; + ret = True; + while (1) { - ret = True; - s[strlen(s)-strlen(back)] = 0; + if (!(*p = p[front_len])) + break; + p++; } + } + + s_len = strlen(s); + while (back_len && s_len >= back_len && + (strncmp(s + s_len - back_len, back, back_len)==0)) + { + ret = True; + s[s_len - back_len] = 0; + s_len = strlen(s); + } return(ret); } @@ -1570,13 +1166,13 @@ 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; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"\\.."); @@ -1596,18 +1192,25 @@ 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) + pstrcpy(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; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"/.."); @@ -1626,122 +1229,110 @@ int ChDir(char *path) if (*path == '/' && strcsequal(LastDir,path)) return(0); DEBUG(3,("chdir to %s\n",path)); - res = sys_chdir(path); + res = dos_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) struct { - ino_t inode; - dev_t dev; - char *text; + SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ + SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ + char *text; /* The pathname in DOS format. */ BOOL valid; } ino_list[MAX_GETWDCACHE]; BOOL use_getwd_cache=True; /******************************************************************* - return the absolute current directory path + return the absolute current directory path - given a UNIX pathname. + Note that this path is returned in DOS format, not UNIX + format. ********************************************************************/ char *GetWd(char *str) { pstring s; static BOOL getwd_cache_init = False; - struct stat st, st2; + SMB_STRUCT_STAT st, st2; int i; *s = 0; if (!use_getwd_cache) - return(Dumb_GetWd(str)); + return(dos_getwd(str)); /* init the cache */ if (!getwd_cache_init) + { + getwd_cache_init = True; + for (i=0;i<MAX_GETWDCACHE;i++) { - getwd_cache_init = True; - for (i=0;i<MAX_GETWDCACHE;i++) - { - string_init(&ino_list[i].text,""); - ino_list[i].valid = False; - } + string_init(&ino_list[i].text,""); + ino_list[i].valid = False; } + } /* Get the inode of the current directory, if this doesn't work we're in trouble :-) */ - if (stat(".",&st) == -1) - { - DEBUG(0,("Very strange, couldn't stat \".\"\n")); - return(Dumb_GetWd(str)); - } + if (dos_stat(".",&st) == -1) + { + DEBUG(0,("Very strange, couldn't stat \".\"\n")); + return(dos_getwd(str)); + } for (i=0; i<MAX_GETWDCACHE; i++) if (ino_list[i].valid) - { + { - /* If we have found an entry with a matching inode and dev number - then find the inode number for the directory in the cached string. - If this agrees with that returned by the stat for the current - directory then all is o.k. (but make sure it is a directory all - the same...) */ + /* If we have found an entry with a matching inode and dev number + then find the inode number for the directory in the cached string. + If this agrees with that returned by the stat for the current + directory then all is o.k. (but make sure it is a directory all + the same...) */ - if (st.st_ino == ino_list[i].inode && - st.st_dev == ino_list[i].dev) - { - if (stat(ino_list[i].text,&st2) == 0) - { - if (st.st_ino == st2.st_ino && - st.st_dev == st2.st_dev && - (st2.st_mode & S_IFMT) == S_IFDIR) - { - strcpy (str, ino_list[i].text); - - /* promote it for future use */ - array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); - return (str); - } - else - { - /* If the inode is different then something's changed, - scrub the entry and start from scratch. */ - ino_list[i].valid = False; - } - } - } + if (st.st_ino == ino_list[i].inode && + st.st_dev == ino_list[i].dev) + { + if (dos_stat(ino_list[i].text,&st2) == 0) + { + if (st.st_ino == st2.st_ino && + st.st_dev == st2.st_dev && + (st2.st_mode & S_IFMT) == S_IFDIR) + { + pstrcpy (str, ino_list[i].text); + + /* promote it for future use */ + array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); + return (str); + } + else + { + /* If the inode is different then something's changed, + scrub the entry and start from scratch. */ + ino_list[i].valid = False; + } + } } + } /* We don't have the information to hand so rely on traditional methods. The very slow getcwd, which spawns a process on some systems, or the not quite so bad getwd. */ - if (!Dumb_GetWd(s)) - { - DEBUG(0,("Getwd failed, errno %d\n",errno)); - return (NULL); - } + if (!dos_getwd(s)) + { + DEBUG(0,("Getwd failed, errno %s\n",strerror(errno))); + return (NULL); + } - strcpy(str,s); + pstrcpy(str,s); DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev)); @@ -1774,12 +1365,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) #else pstring dir2; pstring wd; - pstring basename; + pstring base_name; pstring newname; char *p=NULL; BOOL relative = (*s != '/'); - *dir2 = *wd = *basename = *newname = 0; + *dir2 = *wd = *base_name = *newname = 0; if (widelinks) { @@ -1790,6 +1381,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) DEBUG(3,("Illegal file name? (%s)\n",s)); return(False); } + + if (strlen(s) == 0) + pstrcpy(s,"./"); + return(True); } @@ -1798,8 +1393,8 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) /* remove any double slashes */ string_sub(s,"//","/"); - strcpy(basename,s); - p = strrchr(basename,'/'); + pstrcpy(base_name,s); + p = strrchr(base_name,'/'); if (!p) return(True); @@ -1824,7 +1419,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) } - if (p && (p != basename)) + if (p && (p != base_name)) { *p = 0; if (strcmp(p+1,".")==0) @@ -1833,10 +1428,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) *p = '/'; } - if (ChDir(basename) != 0) + if (ChDir(base_name) != 0) { ChDir(wd); - DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename)); + DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name)); return(False); } @@ -1847,10 +1442,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) return(False); } - if (p && (p != basename)) + if (p && (p != base_name)) { - strcat(newname,"/"); - strcat(newname,p+1); + pstrcat(newname,"/"); + pstrcat(newname,p+1); } { @@ -1868,18 +1463,18 @@ 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); if (strlen(s) == 0) - strcpy(s,"./"); + pstrcpy(s,"./"); DEBUG(3,("reduced to %s\n",s)); return(True); @@ -1897,14 +1492,34 @@ 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); } } /**************************************************************************** +parse out a directory name from a path name. Assumes dos style filenames. +****************************************************************************/ +static char *dirname_dos(char *path,char *buf) +{ + char *p = strrchr(path,'\\'); + + if (!p) + pstrcpy(buf,path); + else + { + *p = 0; + pstrcpy(buf,path); + *p = '\\'; + } + + return(buf); +} + + +/**************************************************************************** expand a wildcard expression, replacing *s with ?s ****************************************************************************/ void expand_mask(char *Mask,BOOL doext) @@ -1924,42 +1539,42 @@ 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,""); + pstrcpy(mext,""); if (strlen(mbeg) > 8) { - strcpy(mext,mbeg + 8); + pstrcpy(mext,mbeg + 8); mbeg[8] = 0; } } if (*mbeg == 0) - strcpy(mbeg,"????????"); + pstrcpy(mbeg,"????????"); if ((*mext == 0) && doext && !hasdot) - strcpy(mext,"???"); + pstrcpy(mext,"???"); if (strequal(mbeg,"*") && *mext==0) - strcpy(mext,"*"); + pstrcpy(mext,"*"); /* expand *'s */ expand_one(mbeg,8); if (*mext) expand_one(mext,3); - strcpy(Mask,dirpart); - if (*dirpart || absolute) strcat(Mask,"\\"); - strcat(Mask,mbeg); - strcat(Mask,"."); - strcat(Mask,mext); + pstrcpy(Mask,dirpart); + if (*dirpart || absolute) pstrcat(Mask,"\\"); + pstrcat(Mask,mbeg); + pstrcat(Mask,"."); + pstrcat(Mask,mext); DEBUG(6,("Mask expanded to [%s]\n",Mask)); } @@ -1971,21 +1586,44 @@ does a string have any uppercase chars in it? BOOL strhasupper(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + 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); - s++; -#endif /* KANJI */ + /* 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 */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (isupper(*s)) + return(True); + s++; + } + } + } return(False); } @@ -1995,21 +1633,52 @@ does a string have any lowercase chars in it? BOOL strhaslower(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + 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); - s++; -#endif /* KANJI */ + /* 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 */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (islower(*s)) + return(True); + s++; + } } + } return(False); } @@ -2019,12 +1688,47 @@ 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) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + while (*s) { - if (*s == c) - count++; - s++; + if (is_shift_jis (*s)) + s += 2; + else + { + if (*s == c) + count++; + s++; + } } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + while (*s) + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (*s == c) + count++; + s++; + } + } + } return(count); } @@ -2032,12 +1736,12 @@ int count_chars(char *s,char c) /**************************************************************************** make a dir struct ****************************************************************************/ -void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date) +void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date) { char *p; pstring mask2; - strcpy(mask2,mask); + pstrcpy(mask2,mask); if ((mode & aDIR) != 0) size = 0; @@ -2057,7 +1761,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode CVAL(buf,21) = mode; put_dos_date(buf,22,date); SSVAL(buf,26,size & 0xFFFF); - SSVAL(buf,28,size >> 16); + SSVAL(buf,28,(size >> 16)&0xFFFF); StrnCpy(buf+30,fname,12); if (!case_sensitive) strupper(buf+30); @@ -2089,57 +1793,15 @@ void close_low_fds(void) } } - -/**************************************************************************** -write to a socket -****************************************************************************/ -int write_socket(int fd,char *buf,int len) -{ - int ret=0; - - if (passive) - return(len); - DEBUG(6,("write_socket(%d,%d)\n",fd,len)); - ret = write_data(fd,buf,len); - - DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret)); - return(ret); -} - -/**************************************************************************** -read from a socket -****************************************************************************/ -int read_udp_socket(int fd,char *buf,int len) -{ - int ret; - struct sockaddr sock; - int socklen; - - socklen = sizeof(sock); - 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); - } - - 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) +static int set_blocking(int fd, BOOL set) { -int val; + int val; #ifdef O_NONBLOCK #define FLAG_TO_SET O_NONBLOCK #else @@ -2150,7 +1812,7 @@ int val; #endif #endif - if((val = fcntl(fd, F_GETFL, 0))==-1) + if((val = fcntl(fd, F_GETFL, 0)) == -1) return -1; if(set) /* Turn blocking on - ie. clear nonblock flag */ val &= ~FLAG_TO_SET; @@ -2162,178 +1824,158 @@ int val; /**************************************************************************** -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 +write to a socket ****************************************************************************/ -static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2) +ssize_t write_socket(int fd,char *buf,size_t len) { - int usecdiff = val1->tv_usec - val2->tv_usec; - int secdiff = val1->tv_sec - val2->tv_sec; - if(usecdiff < 0) { - usecdiff = 1000000 + usecdiff; - secdiff--; + ssize_t ret=0; + + if (passive) + return(len); + DEBUG(6,("write_socket(%d,%d)\n",fd,len)); + ret = write_data(fd,buf,len); + + DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret)); + if(ret <= 0) + DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n", + len, fd, strerror(errno) )); + + return(ret); +} + +/**************************************************************************** +read from a socket +****************************************************************************/ +ssize_t read_udp_socket(int fd,char *buf,size_t len) +{ + ssize_t ret; + struct sockaddr_in sock; + int socklen; + + socklen = sizeof(sock); + bzero((char *)&sock,socklen); + bzero((char *)&lastip,sizeof(lastip)); + ret = (ssize_t)recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen); + if (ret <= 0) { + DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno))); + return(0); } - 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); + + lastip = sock.sin_addr; + lastport = ntohs(sock.sin_port); + + DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n", + inet_ntoa(lastip), lastport, ret)); + + return(ret); } /**************************************************************************** read data from a device with a timout in msec. mincount = if timeout, minimum to read before returning maxcount = number to be read. +time_out = timeout in milliseconds ****************************************************************************/ -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact) + +ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out) { fd_set fds; int selrtn; - int readret; - int nread = 0; - struct timeval timeout, tval1, tval2, tvaldiff; - int error_limit = 5; + ssize_t readret; + size_t nread = 0; + 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) { +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ + readret = read(fd, buf + nread, maxcnt - nread); +#endif /* WITH_SSL */ + + if (readret == 0) { + smb_read_error = READ_EOF; + return -1; } - return(nread); + + if (readret == -1) { + smb_read_error = READ_ERROR; + return -1; + } + nread += readret; + } + return((ssize_t)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 - system performance will suffer severely as - select always return true on disk files */ + mincnt is greater then the filesize then + system performance will suffer severely as + select always returns true on disk files */ /* Set initial timeout */ - 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(;;) - { - FD_ZERO(&fds); - FD_SET(fd,&fds); - - selrtn = sys_select(&fds,&timeout); - - /* Check if error */ - if(selrtn == -1) { - errno = EBADF; - return -1; - } - - /* Did we timeout ? */ - if (selrtn == 0) { - if (nread < mincnt) return -1; - break; /* Yes */ - } - - 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); - } + timeout.tv_sec = (time_t)(time_out / 1000); + timeout.tv_usec = (long)(1000 * (time_out % 1000)); - if (readret < 0) { - /* force a particular error number for - portability */ - DEBUG(5,("read gave error %s\n",strerror(errno))); - errno = EBADF; - return -1; - } - - nread += readret; + for (nread=0; nread < mincnt; ) + { + FD_ZERO(&fds); + FD_SET(fd,&fds); - /* 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); + selrtn = sys_select(fd+1,&fds,&timeout); + + /* Check if error */ + if(selrtn == -1) { + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return -1; + } - if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) - break; /* We timed out */ - } + /* Did we timeout ? */ + if (selrtn == 0) { + smb_read_error = READ_TIMEOUT; + return -1; + } - /* Save the time of day as we need to do the select - again (saves a system call) */ - tval1 = tval2; +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = read(fd, buf + nread, maxcnt - nread); } +#else /* WITH_SSL */ + readret = read(fd, buf+nread, maxcnt-nread); +#endif /* WITH_SSL */ - /* Return the number we got */ - return(nread); -} - -/**************************************************************************** -read data from the client. Maxtime is in milliseconds -****************************************************************************/ -int read_max_udp(int fd,char *buffer,int bufsize,int maxtime) -{ - fd_set fds; - int selrtn; - int nread; - struct timeval timeout; - - FD_ZERO(&fds); - FD_SET(fd,&fds); - - timeout.tv_sec = maxtime / 1000; - timeout.tv_usec = (maxtime % 1000) * 1000; - - selrtn = sys_select(&fds,maxtime>0?&timeout:NULL); - - if (!FD_ISSET(fd,&fds)) - return 0; + if (readret == 0) { + /* we got EOF on the file descriptor */ + smb_read_error = READ_EOF; + return -1; + } - nread = read_udp_socket(fd, buffer, bufsize); + if (readret == -1) { + /* the descriptor is probably dead */ + smb_read_error = READ_ERROR; + return -1; + } + + nread += readret; + } - /* return the number got */ - return(nread); + /* Return the number we got */ + return((ssize_t)nread); } /******************************************************************* @@ -2364,184 +2006,92 @@ BOOL send_keepalive(int client) /**************************************************************************** read data from the client, reading exactly N bytes. ****************************************************************************/ -int read_data(int fd,char *buffer,int N) +ssize_t read_data(int fd,char *buffer,size_t N) { - int ret; - int total=0; + ssize_t ret; + size_t total=0; + smb_read_error = 0; + while (total < N) - { + { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_read(ssl, buffer + total, N - total); + }else{ ret = read(fd,buffer + total,N - total); - - /* this is for portability */ - if (ret < 0) - errno = EBADF; - - if (ret <= 0) - return total; - total += ret; } - return total; -} +#else /* WITH_SSL */ + ret = read(fd,buffer + total,N - total); +#endif /* WITH_SSL */ - -/**************************************************************************** - write data to a fd -****************************************************************************/ -int write_data(int fd,char *buffer,int N) -{ - int total=0; - int ret; - - while (total < N) + if (ret == 0) { - ret = write(fd,buffer + total,N - total); - - if (ret <= 0) - return total; - - total += ret; + smb_read_error = READ_EOF; + return 0; } - return total; -} - - -/* 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) + if (ret == -1) { - 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)); + smb_read_error = READ_ERROR; + return -1; } - - 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; + total += ret; } - - if (ret < 0) ret = 0; - - return(ret); + return (ssize_t)total; } + /**************************************************************************** -pre-read some data + write data to a fd ****************************************************************************/ -void do_read_prediction() +ssize_t write_data(int fd,char *buffer,size_t N) { - 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; + size_t total=0; + ssize_t ret; - 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; - } + while (total < N) + { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_write(ssl,buffer + total,N - total); + }else{ + ret = write(fd,buffer + total,N - total); } +#else /* WITH_SSL */ + ret = write(fd,buffer + total,N - total); +#endif /* WITH_SSL */ - 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; -} + if (ret == -1) return -1; + if (ret == 0) return total; -/**************************************************************************** -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; + total += ret; + } + return (ssize_t)total; } /**************************************************************************** transfer some data between two fd's ****************************************************************************/ -int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) +SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T 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; + SMB_OFF_T total = 0; - DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen)); + DEBUG(4,("transfer_file n=%.0f (head=%d) called\n",(double)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); @@ -2553,159 +2103,195 @@ int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) n += headlen; while (n > 0) - { - int s = MIN(n,size); - int ret,ret2=0; + { + int s = (int)MIN(n,(SMB_OFF_T)size); + int ret,ret2=0; - ret = 0; + ret = 0; - if (header && (headlen >= MIN(s,1024))) { - buf1 = header; - s = headlen; - ret = headlen; - headlen = 0; - header = NULL; - } else { - buf1 = abuf; - } + if (header && (headlen >= MIN(s,1024))) { + buf1 = header; + s = headlen; + ret = headlen; + headlen = 0; + header = NULL; + } else { + buf1 = abuf; + } - if (header && headlen > 0) - { - ret = MIN(headlen,size); - memcpy(buf1,header,ret); - headlen -= ret; - header += ret; - if (headlen <= 0) header = NULL; - } + if (header && headlen > 0) + { + ret = MIN(headlen,size); + memcpy(buf1,header,ret); + headlen -= ret; + header += ret; + if (headlen <= 0) header = NULL; + } - if (s > ret) - ret += read(infd,buf1+ret,s-ret); + if (s > ret) + ret += read(infd,buf1+ret,s-ret); - if (ret > 0) - { - ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret); - if (ret2 > 0) total += ret2; - /* if we can't write then dump excess data */ - if (ret2 != ret) - transfer_file(infd,-1,n-(ret+headlen),NULL,0,0); - } - if (ret <= 0 || ret2 != ret) - return(total); - n -= ret; + if (ret > 0) + { + ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret); + if (ret2 > 0) total += ret2; + /* if we can't write then dump excess data */ + if (ret2 != ret) + transfer_file(infd,-1,n-(ret+headlen),NULL,0,0); } + if (ret <= 0 || ret2 != ret) + return(total); + n -= ret; + } return(total); } /**************************************************************************** read 4 bytes of a smb packet and return the smb length of the packet -possibly store the result in the buffer +store the result in the buffer +This version of the function will return a length of zero on receiving +a keepalive packet. +timeout is in milliseconds. ****************************************************************************/ -int read_smb_length(int fd,char *inbuf,int timeout) +static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout) { - char *buffer; - char buf[4]; - int len=0, msg_type; - BOOL ok=False; - - if (inbuf) - buffer = inbuf; - else - buffer = buf; + ssize_t len=0; + int msg_type; + BOOL ok = False; while (!ok) - { - if (timeout > 0) - ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4); - else - ok = (read_data(fd,buffer,4) == 4); + { + if (timeout > 0) + ok = (read_with_timeout(fd,inbuf,4,4,timeout) == 4); + else + ok = (read_data(fd,inbuf,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); - } - } + if (!ok) + return(-1); - len = smb_len(buffer); - msg_type = CVAL(buffer,0); + len = smb_len(inbuf); + msg_type = CVAL(inbuf,0); - if (msg_type == 0x85) - { - DEBUG(5,( "Got keepalive packet\n")); - ok = False; - } - } + if (msg_type == 0x85) + DEBUG(5,("Got keepalive packet\n")); + } DEBUG(10,("got smb length of %d\n",len)); return(len); } +/**************************************************************************** +read 4 bytes of a smb packet and return the smb length of the packet +store the result in the buffer. This version of the function will +never return a session keepalive (length of zero). +timeout is in milliseconds. +****************************************************************************/ +ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout) +{ + ssize_t len; + for(;;) + { + len = read_smb_length_return_keepalive(fd, inbuf, timeout); + + if(len < 0) + return len; + + /* Ignore session keepalives. */ + if(CVAL(inbuf,0) != 0x85) + break; + } + + return len; +} /**************************************************************************** - read an smb from a fd and return it's length -The timeout is in milli seconds + read an smb from a fd. Note that the buffer *MUST* be of size + BUFFER_SIZE+SAFETY_MARGIN. + The timeout is in milliseconds. + This function will return on a + receipt of a session keepalive packet. ****************************************************************************/ -BOOL receive_smb(int fd,char *buffer,int timeout) +BOOL receive_smb(int fd,char *buffer, unsigned int timeout) { - int len; - BOOL ok; + ssize_t len,ret; + + smb_read_error = 0; bzero(buffer,smb_size + 100); - len = read_smb_length(fd,buffer,timeout); - if (len == -1) + len = read_smb_length_return_keepalive(fd,buffer,timeout); + if (len < 0) return(False); - if (len > BUFFER_SIZE) - { - DEBUG(0,("Invalid packet length! (%d bytes)\n",len)); - if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) - exit(1); - } - - ok = (read_data(fd,buffer+4,len) == len); - - if (!ok) - { - close_sockets(); + if (len > BUFFER_SIZE) { + DEBUG(0,("Invalid packet length! (%d bytes).\n",len)); + if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) exit(1); - } + } + if(len > 0) { + ret = read_data(fd,buffer+4,len); + if (ret != len) { + smb_read_error = READ_ERROR; + return False; + } + } return(True); } +/**************************************************************************** + read an smb from a fd ignoring all keepalive packets. Note that the buffer + *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN. + The timeout is in milliseconds + + This is exactly the same as receive_smb except that it never returns + a session keepalive packet (just as receive_smb used to do). + receive_smb was changed to return keepalives as the oplock processing means this call + should never go into a blocking read. +****************************************************************************/ + +BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout) +{ + BOOL ret; + + for(;;) + { + ret = receive_smb(fd, buffer, timeout); + + if(ret == False) + return ret; + + /* Ignore session keepalive packets. */ + if(CVAL(buffer,0) != 0x85) + break; + } + return ret; +} /**************************************************************************** send an smb to a fd ****************************************************************************/ BOOL send_smb(int fd,char *buffer) { - int len; - int ret,nwritten=0; + size_t len; + size_t nwritten=0; + ssize_t ret; len = smb_len(buffer) + 4; while (nwritten < len) + { + ret = write_socket(fd,buffer+nwritten,len - nwritten); + if (ret <= 0) { - ret = write_socket(fd,buffer+nwritten,len - nwritten); - if (ret <= 0) - { - DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret)); - close_sockets(); - exit(1); - } - nwritten += ret; + DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret)); + close_sockets(); + exit(1); } - + nwritten += ret; + } return True; } @@ -2714,7 +2300,7 @@ BOOL send_smb(int fd,char *buffer) /**************************************************************************** find a pointer to a netbios name ****************************************************************************/ -char *name_ptr(char *buf,int ofs) +static char *name_ptr(char *buf,int ofs) { unsigned char c = *(unsigned char *)(buf+ofs); @@ -2739,24 +2325,30 @@ int name_extract(char *buf,int ofs,char *name) { char *p = name_ptr(buf,ofs); int d = PTR_DIFF(p,buf+ofs); - strcpy(name,""); + pstrcpy(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) +int name_len( char *s ) { - char *s0=s; - unsigned char c = *(unsigned char *)s; - if ((c & 0xC0) == 0xC0) + 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 +2384,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); @@ -2802,7 +2394,7 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type) /******************************************************************* sleep for a specified number of milliseconds ********************************************************************/ -void msleep(int t) +static void msleep(int t) { int tdiff=0; struct timeval tval,t1,t2; @@ -2817,7 +2409,7 @@ void msleep(int t) FD_ZERO(&fds); errno = 0; - sys_select(&fds,&tval); + sys_select(0,&fds,&tval); GetTimeOfDay(&t2); tdiff = TvalDiff(&t1,&t2); @@ -2834,16 +2426,15 @@ BOOL in_list(char *s,char *list,BOOL casesensitive) if (!list) return(False); - while (next_token(&p,tok,LIST_SEP)) - { - if (casesensitive) { - if (strcmp(tok,s) == 0) - return(True); - } else { - if (StrCaseCmp(tok,s) == 0) - return(True); - } + while (next_token(&p,tok,LIST_SEP,sizeof(tok))) { + if (casesensitive) { + if (strcmp(tok,s) == 0) + return(True); + } else { + if (StrCaseCmp(tok,s) == 0) + return(True); } + } return(False); } @@ -2863,16 +2454,24 @@ BOOL string_init(char **dest,char *src) if (l == 0) { - if (!null_string) - null_string = (char *)malloc(1); - - *null_string = 0; + if (!null_string) { + if((null_string = (char *)malloc(1)) == NULL) { + DEBUG(0,("string_init: malloc fail for null_string.\n")); + return False; + } + *null_string = 0; + } *dest = null_string; } else { - *dest = (char *)malloc(l+1); - strcpy(*dest,src); + (*dest) = (char *)malloc(l+1); + if ((*dest) == NULL) { + DEBUG(0,("Out of memory in string_init\n")); + return False; + } + + pstrcpy(*dest,src); } return(True); } @@ -2934,13 +2533,12 @@ BOOL string_sub(char *s,char *pattern,char *insert) return(ret); } - - /********************************************************* -* Recursive routine that is called by mask_match. -* Does the actual matching. +* Recursive routine that is called by unix_mask_match. +* Does the actual matching. This is the 'original code' +* used by the unix matcher. *********************************************************/ -BOOL do_match(char *str, char *regexp, int case_sig) +static BOOL unix_do_match(char *str, char *regexp, int case_sig) { char *p; @@ -2959,7 +2557,7 @@ BOOL do_match(char *str, char *regexp, int case_sig) while(*str) { while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) str++; - if(do_match(str,p,case_sig)) + if(unix_do_match(str,p,case_sig)) return True; if(!*str) return False; @@ -3002,8 +2600,10 @@ BOOL do_match(char *str, char *regexp, int case_sig) * Routine to match a given string with a regexp - uses * simplified regexp that takes * and ? only. Case can be * significant or not. +* This is the 'original code' used by the unix matcher. *********************************************************/ -BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) + +static BOOL unix_mask_match(char *str, char *regexp, int case_sig,BOOL trans2) { char *p; pstring p1, p2; @@ -3016,301 +2616,365 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) StrnCpy(p2,str,sizeof(pstring)-1); if (!strchr(p2,'.')) { - strcat(p2,"."); - } - -/* - if (!strchr(p1,'.')) { - strcat(p1,"."); + pstrcat(p2,"."); } -*/ - -#if 0 - if (strchr(p1,'.')) - { - string_sub(p1,"*.*","*"); - string_sub(p1,".*","*"); - } -#endif /* Remove any *? and ** as they are meaningless */ for(p = p1; *p; p++) while( *p == '*' && (p[1] == '?' ||p[1] == '*')) - (void)strcpy( &p[1], &p[2]); + (void)pstrcpy( &p[1], &p[2]); if (strequal(p1,"*")) return(True); - DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); + DEBUG(8,("unix_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)); + matched = unix_do_match(sbase,ebase,case_sig) && + (trans2 || unix_do_match(sext,eext,case_sig)); - DEBUG(5,("mask_match returning %d\n", matched)); + DEBUG(8,("unix_mask_match returning %d\n", matched)); return matched; } +/********************************************************* +* Recursive routine that is called by mask_match. +* Does the actual matching. Returns True if matched, +* False if failed. This is the 'new' NT style matcher. +*********************************************************/ - -/**************************************************************************** -become a daemon, discarding the controlling terminal -****************************************************************************/ -void become_daemon(void) +BOOL do_match(char *str, char *regexp, int case_sig) { -#ifndef NO_FORK_DEBUG - if (fork()) - exit(0); + char *p; - /* detach from the terminal */ -#ifdef USE_SETSID - setsid(); -#else -#ifdef TIOCNOTTY - { - int i = open("/dev/tty", O_RDWR); - if (i >= 0) - { - ioctl(i, (int) TIOCNOTTY, (char *)0); - close(i); + for( p = regexp; *p && *str; ) { + switch(*p) { + case '?': + str++; p++; + break; + + case '*': + /* Look for a character matching + the one after the '*' */ + p++; + if(!*p) + return True; /* Automatic match */ + while(*str) { + while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) + str++; + /* Now eat all characters that match, as + we want the *last* character to match. */ + while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str)))) + str++; + str--; /* We've eaten the match char after the '*' */ + if(do_match(str,p,case_sig)) { + return True; + } + if(!*str) { + return False; + } else { + str++; + } + } + return False; + + default: + if(case_sig) { + if(*str != *p) { + return False; + } + } else { + if(toupper(*str) != toupper(*p)) { + return False; + } } + str++, p++; + break; + } } -#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; + if(!*p && !*str) + return True; + + if (!*p && str[0] == '.' && str[1] == 0) { + return(True); } - inm->s_addr = htonl(nm); + + if (!*str && *p == '?') { + while (*p == '?') + p++; + return(!*p); + } + + if(!*str && (*p == '*' && p[1] == '\0')) { + return True; + } + + return False; } -/**************************************************************************** - 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 +/********************************************************* +* Routine to match a given string with a regexp - uses +* simplified regexp that takes * and ? only. Case can be +* significant or not. +* The 8.3 handling was rewritten by Ums Harald <Harald.Ums@pro-sieben.de> +* This is the new 'NT style' matcher. +*********************************************************/ - /* get a default netmask and broadcast */ - default_netmask(if_nmask, if_ipaddr); +BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) +{ + char *p; + pstring t_pattern, t_filename, te_pattern, te_filename; + fstring ebase,eext,sbase,sext; -#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) + BOOL matched = False; + + /* Make local copies of str and regexp */ + pstrcpy(t_pattern,regexp); + pstrcpy(t_filename,str); + +#if 0 + /* + * Not sure if this is a good idea. JRA. + */ + if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False)) + trans2 = False; #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 0 + if (!strchr(t_filename,'.')) { + pstrcat(t_filename,"."); + } +#endif - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) - DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno))); - else { - ifr = ifc.ifc_req; + /* Remove any *? and ** as they are meaningless */ + string_sub(t_pattern, "*?", "*"); + string_sub(t_pattern, "**", "*"); - 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; - } - } + if (strequal(t_pattern,"*")) + return(True); + + DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig)); + + if(trans2) { + /* + * Match each component of the regexp, split up by '.' + * characters. + */ + char *fp, *rp, *cp2, *cp1; + BOOL last_wcard_was_star = False; + int num_path_components, num_regexp_components; + + pstrcpy(te_pattern,t_pattern); + pstrcpy(te_filename,t_filename); + /* + * Remove multiple "*." patterns. + */ + string_sub(te_pattern, "*.*.", "*."); + num_regexp_components = count_chars(te_pattern, '.'); + num_path_components = count_chars(te_filename, '.'); + + /* + * Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z + */ + if(num_regexp_components == 0) + matched = do_match( te_filename, te_pattern, case_sig); + else { + for( cp1 = te_pattern, cp2 = te_filename; cp1;) { + fp = strchr(cp2, '.'); + if(fp) + *fp = '\0'; + rp = strchr(cp1, '.'); + if(rp) + *rp = '\0'; + + if(cp1[strlen(cp1)-1] == '*') + last_wcard_was_star = True; + else + last_wcard_was_star = False; + + if(!do_match(cp2, cp1, case_sig)) + break; + + cp1 = rp ? rp + 1 : NULL; + cp2 = fp ? fp + 1 : ""; + + if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) { + /* Eat the extra path components. */ + int i; + + for(i = 0; i < num_path_components - num_regexp_components; i++) { + fp = strchr(cp2, '.'); + if(fp) + *fp = '\0'; + + if((cp1 != NULL) && do_match( cp2, cp1, case_sig)) { + cp2 = fp ? fp + 1 : ""; + break; + } + cp2 = fp ? fp + 1 : ""; + } + num_path_components -= i; + } + } + if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star)) + matched = True; } - } -#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; + + /* ------------------------------------------------- + * Behaviour of Win95 + * for 8.3 filenames and 8.3 Wildcards + * ------------------------------------------------- + */ + if (strequal (t_filename, ".")) { + /* + * Patterns: *.* *. ?. ? are valid + * + */ + if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || + strequal(t_pattern, "?.") || strequal(t_pattern, "?")) + matched = True; + } else if (strequal (t_filename, "..")) { + /* + * Patterns: *.* *. ?. ? *.? are valid + * + */ + if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || + strequal(t_pattern, "?.") || strequal(t_pattern, "?") || + strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*")) + matched = True; + } else { + + if ((p = strrchr (t_pattern, '.'))) { + /* + * Wildcard has a suffix. + */ + *p = 0; + fstrcpy (ebase, t_pattern); + if (p[1]) { + fstrcpy (eext, p + 1); + } else { + /* pattern ends in DOT: treat as if there is no DOT */ + *eext = 0; + if (strequal (ebase, "*")) + return (True); + } + } else { + /* + * No suffix for wildcard. + */ + fstrcpy (ebase, t_pattern); + eext[0] = 0; } - } - } -#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; + + p = strrchr (t_filename, '.'); + if (p && (p[1] == 0) ) { + /* + * Filename has an extension of '.' only. + */ + *p = 0; /* nuke dot at end of string */ + p = 0; /* and treat it as if there is no extension */ } - 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; + + if (p) { + /* + * Filename has an extension. + */ + *p = 0; + fstrcpy (sbase, t_filename); + fstrcpy (sext, p + 1); + if (*eext) { + matched = do_match(sbase, ebase, case_sig) + && do_match(sext, eext, case_sig); + } else { + /* pattern has no extension */ + /* Really: match complete filename with pattern ??? means exactly 3 chars */ + matched = do_match(str, ebase, case_sig); + } + } else { + /* + * Filename has no extension. + */ + fstrcpy (sbase, t_filename); + fstrcpy (sext, ""); + if (*eext) { + /* pattern has extension */ + matched = do_match(sbase, ebase, case_sig) + && do_match(sext, eext, case_sig); + } else { + matched = do_match(sbase, ebase, case_sig); +#ifdef EMULATE_WEIRD_W95_MATCHING + /* + * Even Microsoft has some problems + * Behaviour Win95 -> local disk + * is different from Win95 -> smb drive from Nt 4.0 + * This branch would reflect the Win95 local disk behaviour + */ + if (!matched) { + /* a? matches aa and a in w95 */ + fstrcat (sbase, "."); + matched = do_match(sbase, ebase, case_sig); + } #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))); - } + DEBUG(8,("mask_match returning %d\n", matched)); - /* Close up shop */ - (void) close(sock); - -#endif + return matched; +} - /* 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); - } - } +/**************************************************************************** +become a daemon, discarding the controlling terminal +****************************************************************************/ +void become_daemon(void) +{ + if (fork()) { + _exit(0); + } - /* 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 */ + /* detach from the terminal */ +#ifdef HAVE_SETSID + setsid(); +#elif defined(TIOCNOTTY) + { + int i = open("/dev/tty", O_RDWR); + if (i != -1) { + ioctl(i, (int) TIOCNOTTY, (char *)0); + close(i); + } + } +#endif /* HAVE_SETSID */ + + /* Close fd's 0,1,2. Needed if started by rsh */ + close_low_fds(); +} /**************************************************************************** @@ -3402,18 +3066,18 @@ char *fgets_slash(char *s2,int maxlen,FILE *f) set the length of a file from a filedescriptor. Returns 0 on success, -1 on failure. ****************************************************************************/ -int set_filelen(int fd, long len) +int set_filelen(int fd, SMB_OFF_T len) { /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot extend a file with ftruncate. Provide alternate implementation for this */ -#if FTRUNCATE_CAN_EXTEND - return ftruncate(fd, len); +#ifdef HAVE_FTRUNCATE_EXTEND + return sys_ftruncate(fd, len); #else - struct stat st; + SMB_STRUCT_STAT st; char c = 0; - long currpos = lseek(fd, 0L, SEEK_CUR); + SMB_OFF_T currpos = sys_lseek(fd, (SMB_OFF_T)0, SEEK_CUR); if(currpos < 0) return -1; @@ -3421,7 +3085,7 @@ int set_filelen(int fd, long len) the requested size (call ftruncate), or shorter, in which case seek to len - 1 and write 1 byte of zero */ - if(fstat(fd, &st)<0) + if(sys_fstat(fd, &st)<0) return -1; #ifdef S_ISFIFO @@ -3431,38 +3095,24 @@ int set_filelen(int fd, long len) if(st.st_size == len) return 0; if(st.st_size > len) - return ftruncate(fd, len); + return sys_ftruncate(fd, len); - if(lseek(fd, len-1, SEEK_SET) != len -1) + if(sys_lseek(fd, len-1, SEEK_SET) != len -1) return -1; if(write(fd, &c, 1)!=1) return -1; /* Seek to where we were */ - lseek(fd, currpos, SEEK_SET); + sys_lseek(fd, currpos, SEEK_SET); return 0; #endif } -/**************************************************************************** -return the byte checksum of some data -****************************************************************************/ -int byte_checksum(char *buf,int len) -{ - unsigned char *p = (unsigned char *)buf; - int ret = 0; - while (len--) - ret += *p++; - return(ret); -} - - - #ifdef HPUX /**************************************************************************** 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); } @@ -3470,26 +3120,6 @@ void setbuffer(FILE *f,char *buf,int bufsize) /**************************************************************************** -parse out a directory name from a path name. Assumes dos style filenames. -****************************************************************************/ -char *dirname_dos(char *path,char *buf) -{ - char *p = strrchr(path,'\\'); - - if (!p) - strcpy(buf,path); - else - { - *p = 0; - strcpy(buf,path); - *p = '\\'; - } - - return(buf); -} - - -/**************************************************************************** parse out a filename from a path name. Assumes dos style filenames. ****************************************************************************/ static char *filename_dos(char *path,char *buf) @@ -3497,9 +3127,9 @@ static char *filename_dos(char *path,char *buf) char *p = strrchr(path,'\\'); if (!p) - strcpy(buf,path); + pstrcpy(buf,path); else - strcpy(buf,p+1); + pstrcpy(buf,p+1); return(buf); } @@ -3509,9 +3139,16 @@ static char *filename_dos(char *path,char *buf) /**************************************************************************** expand a pointer to be a particular size ****************************************************************************/ -void *Realloc(void *p,int size) +void *Realloc(void *p,size_t 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,138 +3160,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 *ret = NULL; - if (!s) return(NULL); - ret = (char *)malloc(strlen(s)+1); - if (!ret) return(NULL); - strcpy(ret,s); - return(ret); -} -#endif - - -/**************************************************************************** - Signal handler for SIGPIPE (write on a disconnected socket) -****************************************************************************/ -void Abort(void ) -{ - DEBUG(0,("Probably got SIGPIPE\nExiting\n")); - 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; @@ -3671,17 +3181,17 @@ BOOL get_myname(char *myname,struct in_addr *ip) /* get host info */ if ((hp = Get_Hostbyname(hostname)) == 0) { - DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname)); + DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",hostname)); 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 +3206,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 +3216,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,28 +3224,25 @@ 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 */ if ((hp = Get_Hostbyname(host_name)) == 0) { - DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",host_name)); + DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",host_name)); return -1; } bzero((char *)&sock,sizeof(sock)); memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length); -#if defined(__FreeBSD__) || defined(NETBSD) /* XXX not the right ifdef */ + +#ifdef HAVE_SOCK_SIN_LEN sock.sin_len = sizeof(sock); #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 +3256,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 +3279,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 +3299,46 @@ 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))); + close(res); + return -1; + } + + /* set it blocking again */ + set_blocking(res,True); + return res; } @@ -3826,48 +3366,42 @@ int interpret_protocol(char *str,int def) return(def); } -/**************************************************************************** -interpret a security level -****************************************************************************/ -int interpret_security(char *str,int def) -{ - if (strequal(str,"SERVER")) - return(SEC_SERVER); - if (strequal(str,"USER")) - return(SEC_USER); - if (strequal(str,"SHARE")) - return(SEC_SHARE); - - DEBUG(0,("Unrecognised security level %s\n",str)); - - return(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((int)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 +3412,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 +3422,534 @@ 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); + struct hostent *hp; + int i; + + if ((hp = Get_Hostbyname(remotehost)) == 0) { + DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost)); + return False; + } + + /* + * 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; + } + + /* + * 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; +} - if (thigh == 0) return(0); +/******************************************************************* + 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. + ******************************************************************/ + +static BOOL global_client_name_done = False; +static BOOL global_client_addr_done = False; + +void reset_globals_after_fork(void) +{ + global_client_name_done = False; + global_client_addr_done = False; - d = ((double)thigh)*4.0*(double)(1<<30); - d += (tlow&0xFFF00000); - d *= 1.0e-7; + /* + * Re-seed the random crypto generator, so all smbd's + * started from the same parent won't generate the same + * sequence. + */ + { + unsigned char dummy; + generate_random_buffer( &dummy, 1, True); + } +} - /* now adjust by 369 years to make the secs since 1970 */ - d -= TIME_FIXUP_CONSTANT; +/******************************************************************* + return the DNS name of the client + ******************************************************************/ +char *client_name(int fd) +{ + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static pstring name_buf; + struct hostent *hp; + static int last_fd=-1; + + if (global_client_name_done && last_fd == fd) + return name_buf; + + last_fd = fd; + global_client_name_done = False; + + pstrcpy(name_buf,"UNKNOWN"); + + if (fd == -1) { + return name_buf; + } + + if (getpeername(fd, &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(fd))); + StrnCpy(name_buf,client_addr(fd),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(fd))); + pstrcpy(name_buf,"UNKNOWN"); + } + } + global_client_name_done = True; + return name_buf; +} - if (d>=MAXINT) - return(0); +/******************************************************************* + return the IP addr of the client as a string + ******************************************************************/ +char *client_addr(int fd) +{ + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static fstring addr_buf; + static int last_fd = -1; - ret = (time_t)(d+0.5); + if (global_client_addr_done && fd == last_fd) + return addr_buf; - /* this takes us from kludge-GMT to real GMT */ - ret += TimeDiff(ret) - serverzone; + last_fd = fd; + global_client_addr_done = False; - return(ret); + fstrcpy(addr_buf,"0.0.0.0"); + + if (fd == -1) { + return addr_buf; + } + + if (getpeername(fd, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return addr_buf; + } + + fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); + + global_client_addr_done = True; + return addr_buf; } +#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT)) +/****************************************************************** + Remove any mount options such as -rsize=2048,wsize=2048 etc. + Based on a fix from <Thomas.Hepper@icem.de>. +*******************************************************************/ -/**************************************************************************** -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) +static void strip_mount_options( pstring *str) { - uint32 tlow,thigh; - double d; + if (**str == '-') + { + char *p = *str; + while(*p && !isspace(*p)) + p++; + while(*p && isspace(*p)) + p++; + if(*p) { + pstring tmp_str; - if (t==0) { - SIVAL(p,0,0); SIVAL(p,4,0); - return; + pstrcpy(tmp_str, p); + pstrcpy(*str, tmp_str); + } } +} - /* this converts GMT to kludge-GMT */ - t -= TimeDiff(t) - serverzone; +/******************************************************************* + Patch from jkf@soton.ac.uk + Split Luke's automount_server into YP lookup and string splitter + so can easily implement automount_path(). + As we may end up doing both, cache the last YP result. +*******************************************************************/ - d = (double) (t); +#ifdef WITH_NISPLUS_HOME +static char *automount_lookup(char *user_name) +{ + static fstring last_key = ""; + static pstring last_value = ""; + + char *nis_map = (char *)lp_nis_home_map_name(); + + char nis_domain[NIS_MAXNAMELEN + 1]; + char buffer[NIS_MAXATTRVAL + 1]; + nis_result *result; + nis_object *object; + entry_obj *entry; + + strncpy(nis_domain, (char *)nis_local_directory(), NIS_MAXNAMELEN); + nis_domain[NIS_MAXNAMELEN] = '\0'; + + DEBUG(5, ("NIS+ Domain: %s\n", nis_domain)); + + if (strcmp(user_name, last_key)) + { + slprintf(buffer, sizeof(buffer)-1, "[%s=%s]%s.%s", "key", user_name, nis_map, nis_domain); + DEBUG(5, ("NIS+ querystring: %s\n", buffer)); + + if (result = nis_list(buffer, RETURN_RESULT, NULL, NULL)) + { + if (result->status != NIS_SUCCESS) + { + DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status))); + fstrcpy(last_key, ""); pstrcpy(last_value, ""); + } + else + { + object = result->objects.objects_val; + if (object->zo_data.zo_type == ENTRY_OBJ) + { + entry = &object->zo_data.objdata_u.en_data; + DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type)); + DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val)); + + pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val); + string_sub(last_value, "&", user_name); + fstrcpy(last_key, user_name); + } + } + } + nis_freeresult(result); + } + + strip_mount_options(&last_value); - d += TIME_FIXUP_CONSTANT; + DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; +} +#else /* WITH_NISPLUS_HOME */ +static char *automount_lookup(char *user_name) +{ + static fstring last_key = ""; + static pstring last_value = ""; + + 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(); - d *= 1.0e7; + if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) + { + DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); + return last_value; + } - thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30)))); - tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30)); + DEBUG(5, ("NIS Domain: %s\n", nis_domain)); - SIVAL(p,0,tlow); - SIVAL(p,4,thigh); + if (!strcmp(user_name, last_key)) + { + nis_result = last_value; + nis_result_len = strlen(last_value); + nis_error = 0; + } + else + { + 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\" while looking up \"%s\" in map \"%s\"\n", + yperr_string(nis_error), user_name, nis_map)); + } + if (!nis_error && nis_result_len >= sizeof(pstring)) + { + nis_result_len = sizeof(pstring)-1; + } + fstrcpy(last_key, user_name); + strncpy(last_value, nis_result, nis_result_len); + last_value[nis_result_len] = '\0'; + } + + strip_mount_options(&last_value); + + DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; } +#endif /* WITH_NISPLUS_HOME */ +#endif /******************************************************************* -sub strings with useful parameters -********************************************************************/ -void standard_sub_basic(char *s) + Patch from jkf@soton.ac.uk + This is Luke's original function with the NIS lookup code + moved out to a separate function. +*******************************************************************/ +static char *automount_server(char *user_name) { - if (!strchr(s,'%')) return; + static pstring server_name; - string_sub(s,"%R",remote_proto); - string_sub(s,"%a",remote_arch); - string_sub(s,"%m",remote_machine); - string_sub(s,"%L",local_machine); + /* use the local machine name as the default */ + /* this will be the default if WITH_AUTOMOUNT is not used or fails */ + pstrcpy(server_name, local_machine); - if (!strchr(s,'%')) return; +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) - string_sub(s,"%v",VERSION); - string_sub(s,"%h",myhostname); - string_sub(s,"%U",sesssetup_user); + if (lp_nis_home_map()) + { + int home_server_len; + char *automount_value = automount_lookup(user_name); + home_server_len = strcspn(automount_value,":"); + 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, automount_value, home_server_len); + server_name[home_server_len] = '\0'; + } +#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; +/******************************************************************* + Patch from jkf@soton.ac.uk + Added this to implement %p (NIS auto-map version of %H) +*******************************************************************/ +static char *automount_path(char *user_name) +{ + static pstring server_path; - { - char pidstr[10]; - sprintf(pidstr,"%d",(int)getpid()); - string_sub(s,"%d",pidstr); - } + /* use the passwd entry as the default */ + /* this will be the default if WITH_AUTOMOUNT is not used or fails */ + /* pstrcpy() copes with get_home_dir() returning NULL */ + pstrcpy(server_path, get_home_dir(user_name)); - if (!strchr(s,'%')) return; +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) - { - struct passwd *pass = Get_Pwnam(sesssetup_user,False); - if (pass) { - string_sub(s,"%G",gidtoname(pass->pw_gid)); - } - } + if (lp_nis_home_map()) + { + char *home_path_start; + char *automount_value = automount_lookup(user_name); + home_path_start = strchr(automount_value,':'); + if (home_path_start != NULL) + { + DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n", + home_path_start?(home_path_start+1):"")); + pstrcpy(server_path, home_path_start+1); + } + } +#endif + + DEBUG(4,("Home server path: %s\n", server_path)); + + return server_path; +} + + +/******************************************************************* +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; + + for (s = str ; s && *s && (p = strchr(s,'%')); s = p ) + { + switch (*(p+1)) + { + case 'G' : + { + if ((pass = Get_Pwnam(username,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(Client)); break; + case 'L' : string_sub(p,"%L", local_machine); break; + case 'M' : string_sub(p,"%M", client_name(Client)); 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' : + { + slprintf(pidstr,sizeof(pidstr) - 1, "%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 '$' : /* Expand environment variables */ + { + /* Contributed by Branko Cibej <branko.cibej@hermes.si> */ + fstring envname; + char *envval; + char *q, *r; + int copylen; + + if (*(p+2) != '(') + { + p+=2; + break; + } + if ((q = strchr(p,')')) == NULL) + { + DEBUG(0,("standard_sub_basic: Unterminated environment \ + variable [%s]\n", p)); + p+=2; + break; + } + + r = p+3; + copylen = MIN((q-r),(sizeof(envname)-1)); + strncpy(envname,r,copylen); + envname[copylen] = '\0'; + + if ((envval = getenv(envname)) == NULL) + { + DEBUG(0,("standard_sub_basic: Environment variable [%s] not set\n", + envname)); + p+=2; + break; + } + + copylen = MIN((q+1-p),(sizeof(envname)-1)); + strncpy(envname,p,copylen); + envname[copylen] = '\0'; + string_sub(p,envname,envval); + break; + } + case '\0': p++; break; /* don't run off end if last character is % */ + default : p+=2; break; + } + } + return; +} + + +/**************************************************************************** +do some standard substitutions in a string +****************************************************************************/ +void standard_sub(connection_struct *conn,char *str) +{ + char *p, *s, *home; + + for (s=str; (p=strchr(s, '%'));s=p) { + switch (*(p+1)) { + case 'H': + if ((home = get_home_dir(conn->user))) { + string_sub(p,"%H",home); + } else { + p += 2; + } + break; + + case 'P': + string_sub(p,"%P",conn->connectpath); + break; + + case 'S': + string_sub(p,"%S", + lp_servicename(SNUM(conn))); + break; + + case 'g': + string_sub(p,"%g", + gidtoname(conn->gid)); + break; + case 'u': + string_sub(p,"%u",conn->user); + break; + + /* Patch from jkf@soton.ac.uk Left the %N (NIS + * server name) in standard_sub_basic as it is + * a feature for logon servers, hence uses the + * username. The %p (NIS server path) code is + * here as it is used instead of the default + * "path =" string in [homes] and so needs the + * service name, not the username. */ + case 'p': + string_sub(p,"%p", + automount_path(lp_servicename(SNUM(conn)))); + break; + case '\0': + p++; + break; /* don't run off the end of the string + */ + + default: p+=2; + break; + } + } + + standard_sub_basic(str); +} + + + +/******************************************************************* +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; + + nmask = ntohl(mask.s_addr); + net1 = ntohl(ip1.s_addr); + net2 = ntohl(ip2.s_addr); + + return((net1 & nmask) == (net2 & nmask)); } @@ -4022,34 +3969,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 @@ -4065,13 +3984,22 @@ struct hostent *Get_Hostbyname(char *name) exit(0); } + + /* + * This next test is redundent and causes some systems (with + * broken isalnum() calls) problems. + * JRA. + */ + +#if 0 if (!isalnum(*name2)) { free(name2); return(NULL); } +#endif /* 0 */ - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -4080,7 +4008,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 +4017,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); @@ -4107,32 +4035,7 @@ check if a process exists. Does this work on all unixes? ****************************************************************************/ BOOL process_exists(int pid) { -#ifdef LINUX - fstring s; - sprintf(s,"/proc/%d",pid); - return(directory_exist(s,NULL)); -#else - { - static BOOL tested=False; - static BOOL ok=False; - fstring s; - if (!tested) { - tested = True; - sprintf(s,"/proc/%05d",getpid()); - ok = file_exist(s,NULL); - } - if (ok) { - sprintf(s,"/proc/%05d",pid); - return(file_exist(s,NULL)); - } - } - - /* a best guess for non root access */ - if (geteuid() != 0) return(True); - - /* otherwise use kill */ - return(pid == getpid() || kill(pid,0) == 0); -#endif + return(kill(pid,0) == 0 || errno != ESRCH); } @@ -4144,7 +4047,7 @@ char *uidtoname(int uid) static char name[40]; struct passwd *pass = getpwuid(uid); if (pass) return(pass->pw_name); - sprintf(name,"%d",uid); + slprintf(name, sizeof(name) - 1, "%d",uid); return(name); } @@ -4153,358 +4056,777 @@ turn a gid into a group name ********************************************************************/ char *gidtoname(int gid) { - static char name[40]; - struct group *grp = getgrgid(gid); - if (grp) return(grp->gr_name); - sprintf(name,"%d",gid); - return(name); + static char name[40]; + struct group *grp = getgrgid(gid); + if (grp) return(grp->gr_name); + slprintf(name,sizeof(name) - 1, "%d",gid); + return(name); } /******************************************************************* -block sigs +something really nasty happened - panic! ********************************************************************/ -void BlockSignals(BOOL block) -{ -#ifdef USE_SIGBLOCK - int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV) - |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)| - sigmask(SIGINT)); - if (block) - sigblock(block_mask); - else - sigunblock(block_mask); -#endif +void smb_panic(char *why) +{ + char *cmd = lp_panic_action(); + if (cmd && *cmd) { + system(cmd); + } + DEBUG(0,("PANIC: %s\n", why)); + exit(1); } -#if AJT + /******************************************************************* -my own panic function - not suitable for general use +a readdir wrapper which just returns the file name ********************************************************************/ -void ajt_panic(void) +char *readdirname(void *p) { - pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &"; - smbrun(cmd,NULL); -} + struct dirent *ptr; + char *dname; + + if (!p) return(NULL); + + ptr = (struct dirent *)readdir(p); + if (!ptr) return(NULL); + + dname = ptr->d_name; + +#ifdef NEXT2 + if (telldir(p) < 0) return(NULL); #endif -#ifdef USE_DIRECT -#define DIRECT direct -#else -#define DIRECT dirent +#ifdef HAVE_BROKEN_READDIR + /* using /usr/ucb/cc is BAD */ + dname = dname - 2; #endif + { + static pstring buf; + memcpy(buf, dname, NAMLEN(ptr)+1); + unix_to_dos(buf, True); + dname = buf; + } + + return(dname); +} + /******************************************************************* -a readdir wrapper which just returns the file name -also return the inode number if requested + Utility function used to decide if the last component + of a path matches a (possibly wildcarded) entry in a namelist. ********************************************************************/ -char *readdirname(void *p) -{ - struct DIRECT *ptr; - char *dname; - if (!p) return(NULL); - - ptr = (struct DIRECT *)readdir(p); - if (!ptr) return(NULL); +BOOL is_in_path(char *name, name_compare_entry *namelist) +{ + pstring last_component; + char *p; - dname = ptr->d_name; + DEBUG(8, ("is_in_path: %s\n", name)); -#ifdef KANJI + /* if we have no list it's obviously not in the path */ + if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) { - static pstring buf; - strcpy(buf, dname); - unix_to_dos(buf, True); - dname = buf; + DEBUG(8,("is_in_path: no name list.\n")); + return False; } -#endif -#ifdef NEXT2 - if (telldir(p) < 0) return(NULL); -#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'; -#ifdef SUNOS5 - /* this handles a broken compiler setup, causing a mixture - of BSD and SYSV headers and libraries */ + for(; namelist->name != NULL; namelist++) { - static BOOL broken_readdir = False; - if (!broken_readdir && !(*(dname)) && strequal("..",dname-2)) + if(namelist->is_wild) + { + /* + * Look for a wildcard match. Use the old + * 'unix style' mask match, rather than the + * new NT one. + */ + if (unix_mask_match(last_component, namelist->name, case_sensitive, False)) { - DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n")); - broken_readdir = True; + DEBUG(8,("is_in_path: mask match succeeded\n")); + return True; } - if (broken_readdir) - return(dname-2); + } + 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; + } + } } -#endif - - return(dname); + DEBUG(8,("is_in_path: match not found\n")); + + return False; } +/******************************************************************* + 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; + } + /* next segment please */ + nameptr = name_end + 1; + i++; + } + + (*ppname_array)[i].name = NULL; -#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); + return; } -#endif -#ifdef NO_INITGROUPS -#include <sys/types.h> -#include <limits.h> -#include <grp.h> +/**************************************************************************** +routine to free a namearray. +****************************************************************************/ -#ifndef NULL -#define NULL (void *)0 -#endif +void free_namearray(name_compare_entry *name_array) +{ + if(name_array == 0) + return; + + if(name_array->name != NULL) + free(name_array->name); + + free((char *)name_array); +} /**************************************************************************** - some systems don't have an initgroups call +routine to do file locking ****************************************************************************/ -int initgroups(char *name,gid_t id) +BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) { -#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)) +#if HAVE_FCNTL_LOCK + SMB_STRUCT_FLOCK lock; + int ret; + + if(lp_ole_locking_compat()) { + SMB_OFF_T mask = ((SMB_OFF_T)0xC) << (SMB_OFF_T_BITS-4); + SMB_OFF_T mask2= ((SMB_OFF_T)0x3) << (SMB_OFF_T_BITS-4); + + /* 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) & mask2); + } else { + SMB_OFF_T mask = ((SMB_OFF_T)0x8) << (SMB_OFF_T_BITS-4); + SMB_OFF_T neg_mask = ~mask; + + /* interpret negative counts as large numbers */ + if (count < 0) + count &= ~mask; + + /* no negative offsets */ + if(offset < 0) + offset &= ~mask; + + /* count + offset must be in range */ + while ((offset < 0 || (offset + count < 0)) && mask) { - 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]; - } + offset &= ~mask; + mask = ((mask >> 1) & neg_mask); + } + } + + DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type)); + + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = offset; + lock.l_len = count; + lock.l_pid = 0; + + errno = 0; + + ret = fcntl(fd,op,&lock); + if (errno == EFBIG) + { + if( DEBUGLVL( 0 )) + { + dbgtext("fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n", (double)offset,(double)count); + dbgtext("a 'file too large' error. This can happen when using 64 bit lock offsets\n"); + dbgtext("on 32 bit NFS mounted file systems. Retrying with 32 bit truncated length.\n"); } - endgrent(); - return(setgroups(i,grouplst)); + /* 32 bit NFS file system, retry with smaller offset */ + errno = 0; + lock.l_len = count & 0xffffffff; + 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 == SMB_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,(int)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 %.0f count %.0f op %d type %d (%s)\n", + (double)offset,(double)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 + return(False); #endif } -#endif +/******************************************************************* +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; -#if WRAP_MALLOC + 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); +} -/* undo the wrapping temporarily */ -#undef malloc -#undef realloc -#undef free +/******************************************************************* +set the horrid remote_arch string based on an enum. +********************************************************************/ +void set_remote_arch(enum remote_arch_types type) +{ + ra_type = type; + switch( type ) + { + case RA_WFWG: + fstrcpy(remote_arch, "WfWg"); + return; + case RA_OS2: + fstrcpy(remote_arch, "OS2"); + return; + case RA_WIN95: + fstrcpy(remote_arch, "Win95"); + return; + case RA_WINNT: + fstrcpy(remote_arch, "WinNT"); + return; + case RA_SAMBA: + fstrcpy(remote_arch,"Samba"); + return; + default: + ra_type = RA_UNKNOWN; + fstrcpy(remote_arch, "UNKNOWN"); + break; + } +} -/**************************************************************************** -wrapper for malloc() to catch memory errors -****************************************************************************/ -void *malloc_wrapped(int size,char *file,int line) +/******************************************************************* + Get the remote_arch type. +********************************************************************/ +enum remote_arch_types get_remote_arch(void) { -#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); + return ra_type; } -/**************************************************************************** -wrapper for realloc() to catch memory errors -****************************************************************************/ -void *realloc_wrapped(void *ptr,int size,char *file,int line) + +/******************************************************************* +skip past some unicode strings in a buffer +********************************************************************/ +char *skip_unicode_string(char *buf,int n) { -#ifdef xx_old_realloc - void *res = xx_old_realloc(ptr,size); -#else - void *res = realloc(ptr,size); -#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); + while (n--) + { + while (*buf) + buf += 2; + buf += 2; + } + return(buf); } -/**************************************************************************** -wrapper for free() to catch memory errors -****************************************************************************/ -void free_wrapped(void *ptr,char *file,int line) +/******************************************************************* +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) { -#ifdef xx_old_free - xx_old_free(ptr); -#else - free(ptr); -#endif - DEBUG(3,("free called from %s(%d) with ptr=0x%X\n", - file,line,(unsigned int)ptr)); - return; + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + + nexti = (nexti+1)%8; + + DEBUG(10, ("unistrn2: ")); + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++) + { + DEBUG(10, ("%4x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); + + *p = 0; + return lbuf; } -/* 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__) +/******************************************************************* +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; -#endif + nexti = (nexti+1)%8; -#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) + DEBUG(10, ("unistr2: ")); + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++) + { + DEBUG(10, ("%4x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); + + *p = 0; + return lbuf; +} + +/******************************************************************* +create a null-terminated unicode string from a null-terminated ascii string. +return number of unicode chars copied, excluding the null character. + +only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +int struni2(uint16 *p, char *buf) { - int len = strlen(p); + int len = 0; - while ( *s != '\0' ) { - if ( strncmp(s, p, len) == 0 ) - return s; - s++; + if (p == NULL) return 0; + + DEBUG(10, ("struni2: ")); + + if (buf != NULL) + { + for (; *buf && len < MAXUNI-2; len++, p++, buf++) + { + DEBUG(10, ("%2x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); } - return NULL; + *p = 0; + + return len; +} + +/******************************************************************* +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; + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf += 2) + { + *p = *buf; + } + *p = 0; + return lbuf; } -#endif /* REPLACE_STRSTR */ -#ifdef REPLACE_MKTIME /******************************************************************* -a mktime() replacement for those who don't have it - contributed by -C.A. Lademann <cal@zls.com> +strcpy for unicode strings. returns length (in num of wide chars) ********************************************************************/ -#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++; - } - } +int unistrcpy(char *dst, char *src) +{ + int num_wchars = 0; - 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 - } + while (*src) + { + *dst++ = *src++; + *dst++ = *src++; + num_wchars++; + } + *dst++ = 0; + *dst++ = 0; - return(epoch); + return num_wchars; } -#endif /* REPLACE_MKTIME */ +/******************************************************************* +safe string copy into a known length string. maxlength does not +include the terminating zero. +********************************************************************/ +char *safe_strcpy(char *dest, char *src, int maxlength) +{ + int len; + + if (!dest) { + DEBUG(0,("ERROR: NULL dest in safe_strcpy\n")); + return NULL; + } + + if (!src) { + *dest = 0; + return dest; + } + len = strlen(src); -#ifdef REPLACE_RENAME -/* Rename a file. (from libiberty in GNU binutils) */ -int -rename (zfrom, zto) - const char *zfrom; - const char *zto; + if (len > maxlength) { + DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n", + len-maxlength, src)); + len = maxlength; + } + + memcpy(dest, src, len); + dest[len] = 0; + return dest; +} + +/******************************************************************* +safe string cat into a string. maxlength does not +include the terminating zero. +********************************************************************/ +char *safe_strcat(char *dest, char *src, int maxlength) { - if (link (zfrom, zto) < 0) - { - if (errno != EEXIST) - return -1; - if (unlink (zto) < 0 - || link (zfrom, zto) < 0) - return -1; + int src_len, dest_len; + + if (!dest) { + DEBUG(0,("ERROR: NULL dest in safe_strcat\n")); + return NULL; + } + + if (!src) { + return dest; + } + + src_len = strlen(src); + dest_len = strlen(dest); + + if (src_len + dest_len > maxlength) { + DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n", + src_len + dest_len - maxlength, src)); + src_len = maxlength - dest_len; } - return unlink (zfrom); + + memcpy(&dest[dest_len], src, src_len); + dest[dest_len + src_len] = 0; + return dest; } -#endif +/******************************************************************* +align a pointer to a multiple of 2 bytes +********************************************************************/ +char *align2(char *q, char *base) +{ + if ((q - base) & 1) + { + q++; + } + return q; +} -#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; +void print_asc(int level, unsigned char *buf,int len) { - 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 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)); } - endnetgrent(); - return (0); + } + 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")); + } } -#endif +char *tab_depth(int depth) +{ + static pstring spaces; + memset(spaces, ' ', depth * 4); + spaces[depth * 4] = 0; + return spaces; +} -#if WRAP_MEMCPY -#undef memcpy -/******************************************************************* -a wrapper around memcpy for diagnostic purposes -********************************************************************/ -void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line) +/***************************************************************** + Convert a SID to an ascii string. +*****************************************************************/ + +char *sid_to_string(pstring sidstr_out, DOM_SID *sid) { - 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 + char subauth[16]; + int i; + /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ + uint32 ia = (sid->id_auth[5]) + + (sid->id_auth[4] << 8 ) + + (sid->id_auth[3] << 16) + + (sid->id_auth[2] << 24); + + slprintf(sidstr_out, sizeof(pstring) - 1, "S-%d-%d", sid->sid_rev_num, ia); + + for (i = 0; i < sid->num_auths; i++) + { + slprintf(subauth, sizeof(subauth)-1, "-%d", sid->sub_auths[i]); + pstrcat(sidstr_out, subauth); + } + + DEBUG(7,("sid_to_string returning %s\n", sidstr_out)); + return sidstr_out; } -#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__) -#endif +/***************************************************************** + Convert a string to a SID. Returns True on success, False on fail. +*****************************************************************/ + +BOOL string_to_sid(DOM_SID *sidout, char *sidstr) +{ + pstring tok; + char *p = sidstr; + /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ + uint32 ia; + + memset((char *)sidout, '\0', sizeof(DOM_SID)); + + if(StrnCaseCmp( sidstr, "S-", 2)) { + DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr)); + return False; + } + + p += 2; + if(!next_token(&p, tok, "-", sizeof(tok))) { + DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr)); + return False; + } + + /* Get the revision number. */ + sidout->sid_rev_num = atoi(tok); + + if(!next_token(&p, tok, "-", sizeof(tok))) { + DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr)); + return False; + } + + /* identauth in decimal should be < 2^32 */ + ia = atoi(tok); + + /* NOTE - the ia value is in big-endian format. */ + sidout->id_auth[0] = 0; + sidout->id_auth[1] = 0; + sidout->id_auth[2] = (ia & 0xff000000) >> 24; + sidout->id_auth[3] = (ia & 0x00ff0000) >> 16; + sidout->id_auth[4] = (ia & 0x0000ff00) >> 8; + sidout->id_auth[5] = (ia & 0x000000ff); + + sidout->num_auths = 0; + + while(next_token(&p, tok, "-", sizeof(tok)) && + sidout->num_auths < MAXSUBAUTHS) { + /* + * NOTE - the subauths are in native machine-endian format. They + * are converted to little-endian when linearized onto the wire. + */ + sidout->sub_auths[sidout->num_auths++] = atoi(tok); + } + + DEBUG(7,("string_to_sid: converted SID %s ok\n", sidstr)); + + return True; +} + +/***************************************************************************** + * Provide a checksum on a string + * + * Input: s - the nul-terminated character string for which the checksum + * will be calculated. + * + * Output: The checksum value calculated for s. + * + * **************************************************************************** + */ +int str_checksum(char *s) +{ + int res = 0; + int c; + int i=0; + + while(*s) { + c = *s; + res ^= (c << (i % 15)) ^ (c >> (15-(i%15))); + s++; + i++; + } + return(res); +} /* str_checksum */ + +/***************************************************************** +zero a memory area then free it. Used to catch bugs faster +*****************************************************************/ +void zero_free(void *p, size_t size) +{ + memset(p, 0, size); + free(p); +} |