diff options
Diffstat (limited to 'source3/lib/util.c')
-rw-r--r-- | source3/lib/util.c | 5381 |
1 files changed, 1544 insertions, 3837 deletions
diff --git a/source3/lib/util.c b/source3/lib/util.c index 7bd6298c4c..7e2ad49639 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -1,8 +1,9 @@ /* - Unix SMB/Netbios implementation. - Version 1.9. + Unix SMB/CIFS implementation. Samba utility functions - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 2001 + Copyright (C) Simo Sorce 2001 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 +21,51 @@ */ #include "includes.h" -#include "loadparm.h" -pstring scope = ""; +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) +#ifdef WITH_NISPLUS_HOME +#ifdef BROKEN_NISPLUS_INCLUDE_FILES +/* + * The following lines are needed due to buggy include files + * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and + * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA. + * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as + * an enum in /usr/include/rpcsvc/nis.h. + */ -int DEBUGLEVEL = 1; +#if defined(GROUP) +#undef GROUP +#endif -BOOL passive = False; +#if defined(GROUP_OBJ) +#undef GROUP_OBJ +#endif -int Protocol = PROTOCOL_COREPLUS; +#endif /* BROKEN_NISPLUS_INCLUDE_FILES */ -int serverzone=0; +#include <rpcsvc/nis.h> -/* a default finfo structure to ensure all fields are sensible */ -file_info def_finfo = {-1,0,0,0,0,0,0,""}; +#else /* !WITH_NISPLUS_HOME */ -/* these are some file handles where debug info will be stored */ -FILE *dbf = NULL; +#include "rpcsvc/ypclnt.h" -/* the client file descriptor */ -int Client = -1; +#endif /* WITH_NISPLUS_HOME */ +#endif /* HAVE_NETGROUP && WITH_AUTOMOUNT */ -/* info on the client */ -struct from_host Client_info= -{"UNKNOWN","0.0.0.0",NULL}; +#ifdef WITH_SSL +#include <openssl/ssl.h> +#undef Realloc /* SSLeay defines this and samba has a function of this name */ +extern SSL *ssl; +extern int sslFd; +#endif /* WITH_SSL */ -/* the last IP received from */ -struct in_addr lastip; +int Protocol = PROTOCOL_COREPLUS; -/* the last port received from */ -int lastport=0; +/* a default finfo structure to ensure all fields are sensible */ +file_info def_finfo = {-1,0,0,0,0,0,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 +74,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; @@ -78,916 +82,110 @@ BOOL use_mangled_map = False; BOOL short_case_preserve; BOOL case_mangle; -fstring remote_machine=""; -fstring local_machine=""; -fstring remote_arch="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; - } -} - - -BOOL append_log=False; - - -/**************************************************************************** -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()); - - 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 - - if (stdout_logging) { - vfprintf(dbf,format_str,ap); - va_end(ap); - return(0); - } +static enum remote_arch_types ra_type = RA_UNKNOWN; +pstring user_socket_options=DEFAULT_SOCKET_OPTIONS; - { - static int debug_count=0; +pstring global_myname = ""; +fstring global_myworkgroup = ""; +char **my_netbios_names; - 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)); -*/ - } -#endif - - return((is_dst?60*60:0) - (extra_time_offset*60)); -} - -/**************************************************************************** -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)); -} - - -/**************************************************************************** -determine if a file descriptor is in fact a socket -****************************************************************************/ -BOOL is_a_socket(int fd) -{ - int v,l; - l = sizeof(int); - return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0); -} - - -static char *last_ptr=NULL; - -/**************************************************************************** - Get the next token from a string, return False if none found - handles double-quotes. -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) -{ - char *s; - BOOL quoted; - - if (!ptr) ptr = &last_ptr; - if (!ptr) return(False); - - s = *ptr; - - /* default to simple separators */ - if (!sep) sep = " \t\n\r"; - - /* find the first non sep char */ - while(*s && strchr(sep,*s)) s++; - - /* nothing left? */ - if (! *s) return(False); - - /* copy over the token */ - for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++) - { - if (*s == '\"') - quoted = !quoted; - else - *buff++ = *s; - } - - *ptr = (*s) ? s+1 : s; - *buff = 0; - last_ptr = *ptr; - - return(True); + char *p; + if ((p = getenv("TMPDIR"))) + return p; + return "/tmp"; } /**************************************************************************** -Convert list of tokens to array; dependent on above routine. -Uses last_ptr from above - bit of a hack. + Determine whether we are in the specified group. ****************************************************************************/ -char **toktocliplist(int *ctok, char *sep) -{ - char *s=last_ptr; - int ictok=0; - char **ret, **iret; - - if (!sep) sep = " \t\n\r"; - while(*s && strchr(sep,*s)) s++; - - /* nothing left? */ - if (!*s) return(NULL); - - do { - ictok++; - while(*s && (!strchr(sep,*s))) s++; - while(*s && strchr(sep,*s)) *s++=0; - } while(*s); - - *ctok=ictok; - s=last_ptr; - - if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL; - - while(ictok--) { - *iret++=s; - while(*s++); - while(!*s) s++; - } - - 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) +BOOL in_group(gid_t group, gid_t current_gid, int ngroups, gid_t *groups) { - unsigned long d,s; - int i; - if (dest==src || !size) return(dest); + int i; - d = (unsigned long)dest; - s = (unsigned long)src; + if (group == current_gid) + return(True); - if ((d >= (s+size)) || (s >= (d+size))) { - /* no overlap */ - memcpy(dest,src,size); - return(dest); - } + for (i=0;i<ngroups;i++) + if (group == groups[i]) + return(True); - 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); + return(False); } -#endif - /**************************************************************************** -prompte a dptr (to make it recently used) + Like atoi but gets the value up to the separator character. ****************************************************************************/ -void array_promote(char *array,int elsize,int element) -{ - char *p; - if (element == 0) - return; - p = (char *)malloc(elsize); - - if (!p) - { - DEBUG(5,("Ahh! Can't malloc\n")); - return; - } - memcpy(p,array + element * elsize, elsize); - memmove(array + elsize,array,elsize*element); - memcpy(array,p,elsize); - free(p); -} - -enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON}; - -struct +char *Atoic(char *p, int *n, char *c) { - char *name; - int level; - int option; - int value; - int opttype; -} socket_options[] = { - {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL}, - {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL}, - {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL}, -#ifdef TCP_NODELAY - {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL}, -#endif -#ifdef IPTOS_LOWDELAY - {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON}, -#endif -#ifdef IPTOS_THROUGHPUT - {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON}, -#endif -#ifdef SO_SNDBUF - {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT}, -#endif -#ifdef SO_RCVBUF - {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT}, -#endif -#ifdef SO_SNDLOWAT - {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT}, -#endif -#ifdef SO_RCVLOWAT - {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT}, -#endif - {NULL,0,0,0,0}}; - - - -/**************************************************************************** -set user socket options -****************************************************************************/ -void set_socket_options(int fd, char *options) -{ - string tok; - - while (next_token(&options,tok," \t,")) - { - int ret=0,i; - int value = 1; - char *p; - BOOL got_value = False; - - if ((p = strchr(tok,'='))) - { - *p = 0; - value = atoi(p+1); - got_value = True; + if (!isdigit((int)*p)) { + DEBUG(5, ("Atoic: malformed number\n")); + return NULL; } - for (i=0;socket_options[i].name;i++) - if (strequal(socket_options[i].name,tok)) - break; + (*n) = atoi(p); - if (!socket_options[i].name) - { - DEBUG(0,("Unknown socket option %s\n",tok)); - continue; - } + while ((*p) && isdigit((int)*p)) + p++; - switch (socket_options[i].opttype) + if (strchr_m(c, *p) == NULL) { - case OPT_BOOL: - case OPT_INT: - ret = setsockopt(fd,socket_options[i].level, - socket_options[i].option,(char *)&value,sizeof(int)); - break; - - case OPT_ON: - if (got_value) - DEBUG(0,("syntax error - %s does not take a value\n",tok)); - - { - int on = socket_options[i].value; - ret = setsockopt(fd,socket_options[i].level, - socket_options[i].option,(char *)&on,sizeof(int)); - } - break; + DEBUG(5, ("Atoic: no separator characters (%s) not found\n", c)); + return NULL; } - - if (ret != 0) - DEBUG(0,("Failed to set socket option %s\n",tok)); - } -} - - -/**************************************************************************** - close the socket communication -****************************************************************************/ -void close_sockets(void ) -{ - close(Client); - Client = 0; + return p; } -/**************************************************************************** - 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); -} +/************************************************************************* + Reads a list of numbers. + *************************************************************************/ -/**************************************************************************** -determine whether we are in the specified group -****************************************************************************/ -BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups) +char *get_numlist(char *p, uint32 **num, int *count) { - int i; - - if (group == current_gid) return(True); + int val; - for (i=0;i<ngroups;i++) - if (group == groups[i]) - return(True); - - return(False); -} - -/**************************************************************************** -this is a safer strcpy(), meant to prevent core dumps when nasty things happen -****************************************************************************/ -char *StrCpy(char *dest,char *src) -{ - char *d = dest; + if (num == NULL || count == NULL) + return NULL; -#if AJT - /* I don't want to get lazy with these ... */ - if (!dest || !src) { - DEBUG(0,("ERROR: NULL StrCpy() called!\n")); - ajt_panic(); - } -#endif + (*count) = 0; + (*num ) = NULL; - if (!dest) return(NULL); - if (!src) { - *dest = 0; - return(dest); - } - while ((*d++ = *src++)) ; - return(dest); -} + while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':') { + uint32 *tn; + + tn = Realloc((*num), ((*count)+1) * sizeof(uint32)); + if (tn == NULL) + { + SAFE_FREE(*num); + return NULL; + } else + (*num) = tn; + (*num)[(*count)] = val; + (*count)++; + p++; + } -/**************************************************************************** -line strncpy but always null terminates. Make sure there is room! -****************************************************************************/ -char *StrnCpy(char *dest,const char *src,int n) -{ - char *d = dest; - if (!dest) return(NULL); - if (!src) { - *dest = 0; - return(dest); - } - while (n-- && (*d++ = *src++)) ; - *d = 0; - return(dest); + return p; } - /******************************************************************* -copy an IP address from one buffer to another + Check if a file exists - call vfs_file_exist for samba files. ********************************************************************/ -void putip(void *dest,void *src) -{ - memcpy(dest,src,4); -} - -/**************************************************************************** -interpret the weird netbios "name". Return the name type -****************************************************************************/ -static int name_interpret(char *in,char *out) +BOOL file_exist(const char *fname,SMB_STRUCT_STAT *sbuf) { - int ret; - int len = (*in++) / 2; - - *out=0; - - if (len > 30 || len<1) return(0); - - while (len--) - { - if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { - *out = 0; - return(0); - } - *out = ((in[0]-'A')<<4) + (in[1]-'A'); - in += 2; - out++; - } - *out = 0; - ret = out[-1]; - -#ifdef NETBIOS_SCOPE - /* Handle any scope names */ - while(*in) - { - *out++ = '.'; /* Scope names are separated by periods */ - len = *(unsigned char *)in++; - StrnCpy(out, in, len); - out += len; - *out=0; - in += len; - } -#endif - return(ret); -} - -/**************************************************************************** -mangle a name into netbios format -****************************************************************************/ -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; - - 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); - } - - *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) - { - 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 == '.'); - } - *out = 0; - return(name_len(Out)); -} - - -/******************************************************************* - check if a file exists -********************************************************************/ -BOOL file_exist(char *fname,struct stat *sbuf) -{ - struct stat st; - if (!sbuf) sbuf = &st; + SMB_STRUCT_STAT st; + if (!sbuf) + sbuf = &st; if (sys_stat(fname,sbuf) != 0) return(False); @@ -996,11 +194,12 @@ BOOL file_exist(char *fname,struct stat *sbuf) } /******************************************************************* -check a files mod time + Check a files mod time. ********************************************************************/ -time_t file_modtime(char *fname) + +time_t file_modtime(const char *fname) { - struct stat st; + SMB_STRUCT_STAT st; if (sys_stat(fname,&st) != 0) return(0); @@ -1009,444 +208,99 @@ time_t file_modtime(char *fname) } /******************************************************************* - check if a directory exists + 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) 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 get_file_size(char *file_name) { - struct stat buf; + SMB_STRUCT_STAT buf; buf.st_size = 0; - sys_stat(file_name,&buf); + if(sys_stat(file_name,&buf) != 0) + return (SMB_OFF_T)-1; 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) +char *attrib_string(uint16 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); } - /******************************************************************* - case insensitive string compararison -********************************************************************/ -int StrCaseCmp(char *s, char *t) -{ - for (; tolower(*s) == tolower(*t); ++s, ++t) - if (!*s) return 0; - - return tolower(*s) - tolower(*t); -} - -/******************************************************************* - case insensitive string compararison, length limited -********************************************************************/ -int StrnCaseCmp(char *s, char *t, int n) -{ - while (n-- && *s && *t) { - if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t)); - s++; t++; - } - if (n) return(tolower(*s) - tolower(*t)); - - return(0); -} - -/******************************************************************* - compare 2 strings -********************************************************************/ -BOOL strequal(char *s1,char *s2) -{ - if (s1 == s2) return(True); - if (!s1 || !s2) return(False); - - return(StrCaseCmp(s1,s2)==0); -} - -/******************************************************************* - compare 2 strings up to and including the nth char. - ******************************************************************/ -BOOL strnequal(char *s1,char *s2,int n) -{ - if (s1 == s2) return(True); - if (!s1 || !s2 || !n) return(False); - - return(StrnCaseCmp(s1,s2,n)==0); -} - -/******************************************************************* - compare 2 strings (case sensitive) -********************************************************************/ -BOOL strcsequal(char *s1,char *s2) -{ - if (s1 == s2) return(True); - if (!s1 || !s2) return(False); - - return(strcmp(s1,s2)==0); -} - - -/******************************************************************* - convert a string to lower case -********************************************************************/ -void strlower(char *s) -{ - while (*s) - { -#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 */ - } -} - -/******************************************************************* - convert a string to upper case + show a smb message structure ********************************************************************/ -void strupper(char *s) +void show_msg(char *buf) { - while (*s) - { -#ifdef KANJI - if (is_shift_jis (*s)) { - s += 2; - } else if (is_kana (*s)) { - s++; - } else { - if (islower(*s)) - *s = toupper(*s); - s++; + 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))); } -#else - if (islower(*s)) - *s = toupper(*s); - s++; -#endif - } -} -/******************************************************************* - convert a string to "normal" form -********************************************************************/ -void strnorm(char *s) -{ - if (case_default == CASE_UPPER) - strupper(s); - else - strlower(s); -} + bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); -/******************************************************************* -check if a string is in "normal" case -********************************************************************/ -BOOL strisnormal(char *s) -{ - if (case_default == CASE_UPPER) - return(!strhaslower(s)); - - return(!strhasupper(s)); -} + DEBUG(5,("smb_bcc=%d\n",bcc)); + if (DEBUGLEVEL < 10) return; -/**************************************************************************** - string replace -****************************************************************************/ -void string_replace(char *s,char oldc,char newc) -{ - while (*s) - { -#ifdef KANJI - if (is_shift_jis (*s)) { - s += 2; - } else if (is_kana (*s)) { - s++; - } else { - if (oldc == *s) - *s = newc; - s++; + if (DEBUGLEVEL < 50) + { + bcc = MIN(bcc, 512); } -#else - if (oldc == *s) - *s = newc; - s++; -#endif /* KANJI */ - } -} -/**************************************************************************** - make a file into unix format -****************************************************************************/ -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); - } -} - -/**************************************************************************** - make a file into dos format -****************************************************************************/ -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; - - 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")); -} - -/******************************************************************* - return the length of an smb packet -********************************************************************/ -int smb_len(char *buf) -{ - return( PVAL(buf,3) | (PVAL(buf,2)<<8) | ((PVAL(buf,1)&1)<<16) ); -} - -/******************************************************************* - set the length of an smb packet -********************************************************************/ -void _smb_setlen(char *buf,int len) -{ - buf[0] = 0; - buf[1] = (len&0x10000)>>16; - buf[2] = (len&0xFF00)>>8; - buf[3] = len&0xFF; + dump_data(10, smb_buf(buf), bcc); } /******************************************************************* @@ -1456,10 +310,10 @@ void smb_setlen(char *buf,int len) { _smb_setlen(buf,len); - CVAL(buf,4) = 0xFF; - CVAL(buf,5) = 'S'; - CVAL(buf,6) = 'M'; - CVAL(buf,7) = 'B'; + SCVAL(buf,4,0xFF); + SCVAL(buf,5,'S'); + SCVAL(buf,6,'M'); + SCVAL(buf,7,'B'); } /******************************************************************* @@ -1467,93 +321,35 @@ void smb_setlen(char *buf,int len) ********************************************************************/ int set_message(char *buf,int num_words,int num_bytes,BOOL zero) { - if (zero) - bzero(buf + smb_size,num_words*2 + num_bytes); - CVAL(buf,smb_wct) = num_words; - SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); - smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); - return (smb_size + num_words*2 + num_bytes); + if (zero) + memset(buf + smb_size,'\0',num_words*2 + num_bytes); + SCVAL(buf,smb_wct,num_words); + SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); + smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); + return (smb_size + num_words*2 + num_bytes); } /******************************************************************* -return the number of smb words + setup only the byte count for a smb message ********************************************************************/ -int smb_numwords(char *buf) +int set_message_bcc(char *buf,int num_bytes) { - return (CVAL(buf,smb_wct)); + int num_words = CVAL(buf,smb_wct); + SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); + smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); + return (smb_size + num_words*2 + num_bytes); } /******************************************************************* -return the size of the smb_buf region of a message + setup only the byte count for a smb message, using the end of the + message as a marker ********************************************************************/ -int smb_buflen(char *buf) +int set_message_end(void *outbuf,void *end_ptr) { - return(SVAL(buf,smb_vwv0 + smb_numwords(buf)*2)); + return set_message_bcc((char *)outbuf,PTR_DIFF(end_ptr,smb_buf((char *)outbuf))); } /******************************************************************* - return a pointer to the smb_buf data area -********************************************************************/ -int smb_buf_ofs(char *buf) -{ - return (smb_size + CVAL(buf,smb_wct)*2); -} - -/******************************************************************* - return a pointer to the smb_buf data area -********************************************************************/ -char *smb_buf(char *buf) -{ - return (buf + smb_buf_ofs(buf)); -} - -/******************************************************************* -return the SMB offset into an SMB buffer -********************************************************************/ -int smb_offset(char *p,char *buf) -{ - return(PTR_DIFF(p,buf+4)); -} - - -/******************************************************************* -skip past some strings in a buffer -********************************************************************/ -char *skip_string(char *buf,int n) -{ - while (n--) - buf += strlen(buf) + 1; - return(buf); -} - -/******************************************************************* -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)) - { - ret = True; - s[strlen(s)-strlen(back)] = 0; - } - return(ret); -} - - -/******************************************************************* reduce a file name, removing .. elements. ********************************************************************/ void dos_clean_name(char *s) @@ -1563,25 +359,25 @@ void dos_clean_name(char *s) DEBUG(3,("dos_clean_name [%s]\n",s)); /* remove any double slashes */ - string_sub(s, "\\\\", "\\"); + all_string_sub(s, "\\\\", "\\", 0); while ((p = strstr(s,"\\..\\")) != NULL) { pstring s1; *p = 0; - strcpy(s1,p+3); + pstrcpy(s1,p+3); - if ((p=strrchr(s,'\\')) != NULL) + if ((p=strrchr_m(s,'\\')) != NULL) *p = 0; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"\\.."); - string_sub(s, "\\.\\", "\\"); + all_string_sub(s, "\\.\\", "\\", 0); } /******************************************************************* @@ -1594,474 +390,119 @@ void unix_clean_name(char *s) DEBUG(3,("unix_clean_name [%s]\n",s)); /* remove any double slashes */ - string_sub(s, "//","/"); + all_string_sub(s, "//","/", 0); + + /* 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) + if ((p=strrchr_m(s,'/')) != NULL) *p = 0; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"/.."); } - /******************************************************************* -a wrapper for the normal chdir() function +convert '\' to '/' +reduce a file name, removing or reducing /../ , /./ , // elements. +remove also any trailing . and / +return a new allocated string. ********************************************************************/ -int ChDir(char *path) -{ - int res; - static pstring LastDir=""; - - if (strcsequal(path,".")) return(0); - - if (*path == '/' && strcsequal(LastDir,path)) return(0); - DEBUG(3,("chdir to %s\n",path)); - res = sys_chdir(path); - if (!res) - strcpy(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; - BOOL valid; -} ino_list[MAX_GETWDCACHE]; - -BOOL use_getwd_cache=True; - -/******************************************************************* - return the absolute current directory path -********************************************************************/ -char *GetWd(char *str) -{ - pstring s; - static BOOL getwd_cache_init = False; - struct stat st, st2; - int i; - - *s = 0; - - if (!use_getwd_cache) - return(Dumb_GetWd(str)); - - /* init the cache */ - if (!getwd_cache_init) - { - getwd_cache_init = True; - for (i=0;i<MAX_GETWDCACHE;i++) - { - string_init(&ino_list[i].text,""); - ino_list[i].valid = False; +smb_ucs2_t *unix_clean_path(const smb_ucs2_t *s) +{ + smb_ucs2_t *ns; + smb_ucs2_t *p, *r, *t; + + DEBUG(3, ("unix_clean_path\n")); /* [%unicode]\n")); */ + if(!s) return NULL; + + /* convert '\' to '/' */ + ns = strdup_w(s); + if (!ns) return NULL; + unix_format_w(ns); + + /* remove all double slashes */ + p = ns; + ns = all_string_sub_wa(p, "//", "/"); + SAFE_FREE(p); + if (!ns) return NULL; + + /* remove any /./ */ + p = ns; + ns = all_string_sub_wa(p, "/./", "/"); + SAFE_FREE(p); + if (!ns) return NULL; + + /* reduce any /../ */ + t = ns; + while (*t && (r = strstr_wa(t, "/.."))) { + t = &(r[3]); + if (*t == UCS2_CHAR('/') || *t == 0) { + *r = 0; + p = strrchr_w(ns, UCS2_CHAR('/')); + if (!p) p = ns; + if (*t == 0) *p = 0; + else memmove(p, t, (strlen_w(t) + 1) * sizeof(smb_ucs2_t)); + t = p; + } } - } - - /* 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)); - } - - - 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 (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; - } - } - } - } + /* remove any leading ./ trailing /. */ + trim_string_wa(ns, "./", "/."); - /* 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); - } + /* remove any leading and trailing / */ + trim_string_wa(ns, "/", "/"); - strcpy(str,s); - - DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev)); - - /* add it to the cache */ - i = MAX_GETWDCACHE - 1; - string_set(&ino_list[i].text,s); - ino_list[i].dev = st.st_dev; - ino_list[i].inode = st.st_ino; - ino_list[i].valid = True; - - /* put it at the top of the list */ - array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); - - return (str); + return ns; } - - -/******************************************************************* -reduce a file name, removing .. elements and checking that -it is below dir in the heirachy. This uses GetWd() and so must be run -on the system that has the referenced file system. - -widelinks are allowed if widelinks is true -********************************************************************/ -BOOL reduce_name(char *s,char *dir,BOOL widelinks) -{ -#ifndef REDUCE_PATHS - return True; -#else - pstring dir2; - pstring wd; - pstring basename; - pstring newname; - char *p=NULL; - BOOL relative = (*s != '/'); - - *dir2 = *wd = *basename = *newname = 0; - - if (widelinks) - { - unix_clean_name(s); - /* can't have a leading .. */ - if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) - { - DEBUG(3,("Illegal file name? (%s)\n",s)); - return(False); - } - return(True); - } - - DEBUG(3,("reduce_name [%s] [%s]\n",s,dir)); - - /* remove any double slashes */ - string_sub(s,"//","/"); - - strcpy(basename,s); - p = strrchr(basename,'/'); - - if (!p) - return(True); - - if (!GetWd(wd)) - { - DEBUG(0,("couldn't getwd for %s %s\n",s,dir)); - return(False); - } - - if (ChDir(dir) != 0) - { - DEBUG(0,("couldn't chdir to %s\n",dir)); - return(False); - } - - if (!GetWd(dir2)) - { - DEBUG(0,("couldn't getwd for %s\n",dir)); - ChDir(wd); - return(False); - } - - - if (p && (p != basename)) - { - *p = 0; - if (strcmp(p+1,".")==0) - p[1]=0; - if (strcmp(p+1,"..")==0) - *p = '/'; - } - - if (ChDir(basename) != 0) - { - ChDir(wd); - DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename)); - return(False); - } - - if (!GetWd(newname)) - { - ChDir(wd); - DEBUG(2,("couldn't get wd for %s %s\n",s,dir2)); - return(False); - } - - if (p && (p != basename)) - { - strcat(newname,"/"); - strcat(newname,p+1); - } - - { - int l = strlen(dir2); - if (dir2[l-1] == '/') - l--; - - if (strncmp(newname,dir2,l) != 0) - { - ChDir(wd); - DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,l)); - return(False); - } - - if (relative) - { - if (newname[l] == '/') - strcpy(s,newname + l + 1); - else - strcpy(s,newname+l); - } - else - strcpy(s,newname); - } - - ChDir(wd); - - if (strlen(s) == 0) - strcpy(s,"./"); - - DEBUG(3,("reduced to %s\n",s)); - return(True); -#endif -} - -/**************************************************************************** -expand some *s -****************************************************************************/ -static void expand_one(char *Mask,int len) -{ - char *p1; - while ((p1 = strchr(Mask,'*')) != NULL) - { - int lfill = (len+1) - strlen(Mask); - int l1= (p1 - Mask); - pstring tmp; - strcpy(tmp,Mask); - memset(tmp+l1,'?',lfill); - strcpy(tmp + l1 + lfill,Mask + l1 + 1); - strcpy(Mask,tmp); - } -} - -/**************************************************************************** -expand a wildcard expression, replacing *s with ?s -****************************************************************************/ -void expand_mask(char *Mask,BOOL doext) -{ - pstring mbeg,mext; - pstring dirpart; - pstring filepart; - BOOL hasdot = False; - char *p1; - BOOL absolute = (*Mask == '\\'); - - *mbeg = *mext = *dirpart = *filepart = 0; - - /* parse the directory and filename */ - if (strchr(Mask,'\\')) - dirname_dos(Mask,dirpart); - - filename_dos(Mask,filepart); - - strcpy(mbeg,filepart); - if ((p1 = strchr(mbeg,'.')) != NULL) - { - hasdot = True; - *p1 = 0; - p1++; - strcpy(mext,p1); - } - else - { - strcpy(mext,""); - if (strlen(mbeg) > 8) - { - strcpy(mext,mbeg + 8); - mbeg[8] = 0; - } - } - - if (*mbeg == 0) - strcpy(mbeg,"????????"); - if ((*mext == 0) && doext && !hasdot) - strcpy(mext,"???"); - - if (strequal(mbeg,"*") && *mext==0) - strcpy(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); - - DEBUG(6,("Mask expanded to [%s]\n",Mask)); -} - - -/**************************************************************************** -does a string have any uppercase chars in it? -****************************************************************************/ -BOOL strhasupper(char *s) -{ - while (*s) - { -#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 */ - } - return(False); -} - -/**************************************************************************** -does a string have any lowercase chars in it? -****************************************************************************/ -BOOL strhaslower(char *s) -{ - while (*s) - { -#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 */ - } - return(False); -} - -/**************************************************************************** -find the number of chars in a string -****************************************************************************/ -int count_chars(char *s,char c) -{ - int count=0; - while (*s) - { - if (*s == c) - count++; - s++; - } - return(count); -} - - /**************************************************************************** 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; memset(buf+1,' ',11); - if ((p = strchr(mask2,'.')) != NULL) + if ((p = strchr_m(mask2,'.')) != NULL) { *p = 0; - memcpy(buf+1,mask2,MIN(strlen(mask2),8)); - memcpy(buf+9,p+1,MIN(strlen(p+1),3)); + push_ascii(buf+1,mask2,8, 0); + push_ascii(buf+9,p+1,3, 0); *p = '.'; } else - memcpy(buf+1,mask2,MIN(strlen(mask2),11)); + push_ascii(buf+1,mask2,11, 0); - bzero(buf+21,DIR_STRUCT_SIZE-21); - CVAL(buf,21) = mode; + memset(buf+21,'\0',DIR_STRUCT_SIZE-21); + SCVAL(buf,21,mode); put_dos_date(buf,22,date); SSVAL(buf,26,size & 0xFFFF); - SSVAL(buf,28,size >> 16); - StrnCpy(buf+30,fname,12); + SSVAL(buf,28,(size >> 16)&0xFFFF); + push_ascii(buf+30,fname,12, 0); if (!case_sensitive) strupper(buf+30); - DEBUG(8,("put name [%s] into dir struct\n",buf+30)); + DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname)); } @@ -2072,12 +513,15 @@ void close_low_fds(void) { int fd; int i; - close(0); close(1); close(2); + close(0); close(1); +#ifndef __INSURE__ + close(2); +#endif /* try and use up these file descriptors, so silly library routines writing to stdout etc won't cause havoc */ for (i=0;i<3;i++) { - fd = open("/dev/null",O_RDWR,0); - if (fd < 0) fd = open("/dev/null",O_WRONLY,0); + fd = sys_open("/dev/null",O_RDWR,0); + if (fd < 0) fd = sys_open("/dev/null",O_WRONLY,0); if (fd < 0) { DEBUG(0,("Can't open /dev/null\n")); return; @@ -2089,48 +533,6 @@ 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 @@ -2139,7 +541,7 @@ if BSD use FNDELAY ****************************************************************************/ int set_blocking(int fd, BOOL set) { -int val; + int val; #ifdef O_NONBLOCK #define FLAG_TO_SET O_NONBLOCK #else @@ -2150,7 +552,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; @@ -2160,2351 +562,1656 @@ int val; #undef FLAG_TO_SET } - /**************************************************************************** -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 + Transfer some data between two fd's. ****************************************************************************/ -static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2) -{ - int usecdiff = val1->tv_usec - val2->tv_usec; - int secdiff = val1->tv_sec - val2->tv_sec; - if(usecdiff < 0) { - usecdiff = 1000000 + usecdiff; - secdiff--; - } - retval->tv_sec = secdiff; - retval->tv_usec = usecdiff; - if(secdiff < 0) - return -1; - if(secdiff > 0) - return 1; - return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0); -} -/**************************************************************************** -read data from a device with a timout in msec. -mincount = if timeout, minimum to read before returning -maxcount = number to be read. -****************************************************************************/ -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact) -{ - fd_set fds; - int selrtn; - int readret; - int nread = 0; - struct timeval timeout, tval1, tval2, tvaldiff; - int error_limit = 5; +#ifndef TRANSFER_BUF_SIZE +#define TRANSFER_BUF_SIZE 65536 +#endif - /* just checking .... */ - if (maxcnt <= 0) return(0); +ssize_t transfer_file_internal(int infd, int outfd, size_t n, ssize_t (*read_fn)(int, void *, size_t), + ssize_t (*write_fn)(int, const void *, size_t)) +{ + char *buf; + size_t total = 0; + ssize_t read_ret; + ssize_t write_ret; + size_t num_to_read_thistime; + size_t num_written = 0; - if(time_out == -2) - time_out = DEFAULT_PIPE_TIMEOUT; + if ((buf = malloc(TRANSFER_BUF_SIZE)) == NULL) + return -1; - /* Blocking read */ - if(time_out < 0) { - if (mincnt == 0) mincnt = maxcnt; + while (total < n) { + num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE); - while (nread < mincnt) - { - readret = read(fd, buf + nread, maxcnt - nread); - if (readret <= 0) return(nread); - nread += readret; - } - return(nread); - } - - /* Non blocking read */ - if(time_out == 0) { - set_blocking(fd, False); - nread = read_data(fd, buf, mincnt); - if (nread < maxcnt) - nread += read(fd,buf+nread,maxcnt-nread); - if(nread == -1 && errno == EWOULDBLOCK) - nread = 0; - set_blocking(fd,True); - return nread; - } + read_ret = (*read_fn)(infd, buf, num_to_read_thistime); + if (read_ret == -1) { + DEBUG(0,("transfer_file_internal: read failure. Error = %s\n", strerror(errno) )); + SAFE_FREE(buf); + return -1; + } + if (read_ret == 0) + break; - /* 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 */ - - /* 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); - } + num_written = 0; + + while (num_written < read_ret) { + write_ret = (*write_fn)(outfd,buf + num_written, read_ret - num_written); + + if (write_ret == -1) { + DEBUG(0,("transfer_file_internal: write failure. Error = %s\n", strerror(errno) )); + SAFE_FREE(buf); + return -1; + } + if (write_ret == 0) + return (ssize_t)total; + + num_written += (size_t)write_ret; + } - 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; - - /* If we have read more than mincnt then return */ - if (nread >= mincnt) - break; - - /* We need to do another select - but first reduce the - time_out by the amount of time already elapsed - if - this is less than zero then return */ - if (exact) { - GetTimeOfDay(&tval2); - (void)tval_sub( &tvaldiff, &tval2, &tval1); - - if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) - break; /* We timed out */ - } - - /* Save the time of day as we need to do the select - again (saves a system call) */ - tval1 = tval2; - } + total += (size_t)read_ret; + } - /* Return the number we got */ - return(nread); + SAFE_FREE(buf); + return (ssize_t)total; } -/**************************************************************************** -read data from the client. Maxtime is in milliseconds -****************************************************************************/ -int read_max_udp(int fd,char *buffer,int bufsize,int maxtime) +SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n) { - 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; - - nread = read_udp_socket(fd, buffer, bufsize); - - /* return the number got */ - return(nread); + return (SMB_OFF_T)transfer_file_internal(infd, outfd, (size_t)n, read, write); } /******************************************************************* -find the difference in milliseconds between two struct timeval -values + Sleep for a specified number of milliseconds. ********************************************************************/ -int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew) -{ - return((tvalnew->tv_sec - tvalold->tv_sec)*1000 + - ((int)tvalnew->tv_usec - (int)tvalold->tv_usec)/1000); -} -/**************************************************************************** -send a keepalive packet (rfc1002) -****************************************************************************/ -BOOL send_keepalive(int client) +void msleep(unsigned int t) { - unsigned char buf[4]; - - buf[0] = 0x85; - buf[1] = buf[2] = buf[3] = 0; + unsigned int tdiff=0; + struct timeval tval,t1,t2; + fd_set fds; - return(write_data(client,(char *)buf,4) == 4); + GetTimeOfDay(&t1); + GetTimeOfDay(&t2); + + while (tdiff < t) { + tval.tv_sec = (t-tdiff)/1000; + tval.tv_usec = 1000*((t-tdiff)%1000); + + /* Never wait for more than 1 sec. */ + if (tval.tv_sec > 1) { + tval.tv_sec = 1; + tval.tv_usec = 0; + } + + FD_ZERO(&fds); + errno = 0; + sys_select_intr(0,&fds,NULL,NULL,&tval); + + GetTimeOfDay(&t2); + if (t2.tv_sec < t1.tv_sec) { + /* Someone adjusted time... */ + t1 = t2; + } + + tdiff = TvalDiff(&t1,&t2); + } } - - /**************************************************************************** - read data from the client, reading exactly N bytes. + Become a daemon, discarding the controlling terminal. ****************************************************************************/ -int read_data(int fd,char *buffer,int N) + +void become_daemon(void) { - int ret; - int total=0; - - while (total < N) - { - ret = read(fd,buffer + total,N - total); + if (sys_fork()) { + _exit(0); + } - /* this is for portability */ - if (ret < 0) - errno = EBADF; + /* detach from the terminal */ +#ifdef HAVE_SETSID + setsid(); +#elif defined(TIOCNOTTY) + { + int i = sys_open("/dev/tty", O_RDWR, 0); + if (i != -1) { + ioctl(i, (int) TIOCNOTTY, (char *)0); + close(i); + } + } +#endif /* HAVE_SETSID */ - if (ret <= 0) - return total; - total += ret; - } - return total; + /* Close fd's 0,1,2. Needed if started by rsh */ + close_low_fds(); } /**************************************************************************** - write data to a fd +put up a yes/no prompt ****************************************************************************/ -int write_data(int fd,char *buffer,int N) +BOOL yesno(char *p) { - int total=0; - int ret; + pstring ans; + printf("%s",p); - while (total < N) - { - ret = write(fd,buffer + total,N - total); + if (!fgets(ans,sizeof(ans)-1,stdin)) + return(False); - if (ret <= 0) - return total; + if (*ans == 'y' || *ans == 'Y') + return(True); - total += ret; - } - return total; + return(False); } - -/* 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 + Expand a pointer to be a particular size. ****************************************************************************/ -int read_predict(int fd,int offset,char *buf,char **ptr,int num) -{ - int ret = 0; - int possible = rp_length - (offset - rp_offset); - - possible = MIN(possible,num); - - /* give data if possible */ - if (fd == rp_fd && - offset >= rp_offset && - possible>0 && - smb_last_time-rp_time < rp_timeout) - { - ret = possible; - if (buf) - memcpy(buf,rp_buffer + (offset-rp_offset),possible); - else - *ptr = rp_buffer + (offset-rp_offset); - DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num)); - } - if (ret == num) { - predict_skip = True; - } else { - predict_skip = False; +void *Realloc(void *p,size_t size) +{ + void *ret=NULL; - /* prepare the next prediction */ - rp_predict_fd = fd; - rp_predict_offset = offset + num; - rp_predict_length = num; + if (size == 0) { + SAFE_FREE(p); + DEBUG(5,("Realloc asked for 0 bytes\n")); + return NULL; } - if (ret < 0) ret = 0; + if (!p) + ret = (void *)malloc(size); + else + ret = (void *)realloc(p,size); + + if (!ret) + DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",(int)size)); return(ret); } /**************************************************************************** -pre-read some data + Free memory, checks for NULL. +use directly SAFE_FREE() +exist only because we need to pass a function pointer somewhere --SSS ****************************************************************************/ -void do_read_prediction() + +void safe_free(void *p) { - if (predict_skip) return; + SAFE_FREE(p); +} - if (rp_predict_fd == -1) - return; +/**************************************************************************** + Get my own name and IP. +****************************************************************************/ - rp_fd = rp_predict_fd; - rp_offset = rp_predict_offset; - rp_length = 0; +BOOL get_myname(char *my_name) +{ + pstring hostname; - rp_predict_fd = -1; + *hostname = 0; - 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; + /* get my host name */ + if (gethostname(hostname, sizeof(hostname)) == -1) { + DEBUG(0,("gethostname failed\n")); + return False; + } - 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; - } - } + /* Ensure null termination. */ + hostname[sizeof(hostname)-1] = '\0'; - if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) { - rp_fd = -1; - rp_predict_fd = -1; - return; - } + if (my_name) { + /* split off any parts after an initial . */ + char *p = strchr_m(hostname,'.'); - rp_length = read(rp_fd,rp_buffer,rp_predict_length); - rp_time = time(NULL); - if (rp_length < 0) - rp_length = 0; + if (p) + *p = 0; + + fstrcpy(my_name,hostname); + } + + return(True); } /**************************************************************************** -invalidate read-prediction on a fd + Interpret a protocol description string, with a default. ****************************************************************************/ -void invalidate_read_prediction(int fd) + +int interpret_protocol(char *str,int def) { - if (rp_fd == fd) - rp_fd = -1; - if (rp_predict_fd == fd) - rp_predict_fd = -1; + if (strequal(str,"NT1")) + return(PROTOCOL_NT1); + if (strequal(str,"LANMAN2")) + return(PROTOCOL_LANMAN2); + if (strequal(str,"LANMAN1")) + return(PROTOCOL_LANMAN1); + if (strequal(str,"CORE")) + return(PROTOCOL_CORE); + if (strequal(str,"COREPLUS")) + return(PROTOCOL_COREPLUS); + if (strequal(str,"CORE+")) + return(PROTOCOL_COREPLUS); + + DEBUG(0,("Unrecognised protocol level %s\n",str)); + + return(def); } - /**************************************************************************** -transfer some data between two fd's + Return true if a string could be a pure IP address. ****************************************************************************/ -int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) + +BOOL is_ipaddress(const char *str) { - static char *buf=NULL; - char *buf1,*abuf; - static int size = 0; - int total = 0; + BOOL pure_address = True; + int i; + + for (i=0; pure_address && str[i]; i++) + if (!(isdigit((int)str[i]) || str[i] == '.')) + pure_address = False; - DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen)); + /* Check that a pure number is not misinterpreted as an IP */ + pure_address = pure_address && (strchr_m(str, '.') != NULL); - if ((size < ReadSize) && buf) { - free(buf); - buf = NULL; - } + return pure_address; +} - size = MAX(ReadSize,1024); +/**************************************************************************** +interpret an internet address or name into an IP address in 4 byte form +****************************************************************************/ - 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); - } +uint32 interpret_addr(const char *str) +{ + struct hostent *hp; + uint32 res; - abuf = buf + (align%8); + if (strcmp(str,"0.0.0.0") == 0) return(0); + if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF); - if (header) - n += headlen; + /* if it's in the form of an IP address then get the lib to interpret it */ + if (is_ipaddress(str)) { + res = inet_addr(str); + } else { + /* otherwise assume it's a network name of some sort and use + sys_gethostbyname */ + if ((hp = sys_gethostbyname(str)) == 0) { + DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str)); + return 0; + } + if(hp->h_addr == NULL) { + DEBUG(3,("sys_gethostbyname: host address is invalid for host %s\n",str)); + return 0; + } + putip((char *)&res,(char *)hp->h_addr); + } - while (n > 0) - { - int s = MIN(n,size); - int ret,ret2=0; - - ret = 0; - - if (header && (headlen >= MIN(s,1024))) { - buf1 = header; - s = headlen; - ret = headlen; - headlen = 0; - header = NULL; - } else { - buf1 = abuf; - } + if (res == (uint32)-1) return(0); - if (header && headlen > 0) - { - ret = MIN(headlen,size); - memcpy(buf1,header,ret); - headlen -= ret; - header += ret; - if (headlen <= 0) header = NULL; - } + return(res); +} - if (s > ret) - ret += read(infd,buf1+ret,s-ret); +/******************************************************************* + a convenient addition to interpret_addr() + ******************************************************************/ +struct in_addr *interpret_addr2(const char *str) +{ + static struct in_addr ret; + uint32 a = interpret_addr(str); + ret.s_addr = a; + return(&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); +/******************************************************************* + check if an IP is the 0.0.0.0 + ******************************************************************/ +BOOL is_zero_ip(struct in_addr ip) +{ + uint32 a; + putip((char *)&a,(char *)&ip); + return(a == 0); } +/* Set an IP to 0.0.0.0 */ -/**************************************************************************** -read 4 bytes of a smb packet and return the smb length of the packet -possibly store the result in the buffer -****************************************************************************/ -int read_smb_length(int fd,char *inbuf,int timeout) +void zero_ip(struct in_addr *ip) { - char *buffer; - char buf[4]; - int len=0, msg_type; - BOOL ok=False; + static BOOL init; + static struct in_addr ipzero; - if (inbuf) - buffer = inbuf; - else - buffer = buf; + if (!init) { + ipzero = *interpret_addr2("0.0.0.0"); + init = True; + } - while (!ok) - { - if (timeout > 0) - ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4); - else - ok = (read_data(fd,buffer,4) == 4); + *ip = ipzero; +} - 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 (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>. +*******************************************************************/ - len = smb_len(buffer); - msg_type = CVAL(buffer,0); +static void strip_mount_options( pstring *str) +{ + if (**str == '-') + { + char *p = *str; + while(*p && !isspace(*p)) + p++; + while(*p && isspace(*p)) + p++; + if(*p) { + pstring tmp_str; - if (msg_type == 0x85) - { - DEBUG(5,( "Got keepalive packet\n")); - ok = False; - } + pstrcpy(tmp_str, p); + pstrcpy(*str, tmp_str); } - - DEBUG(10,("got smb length of %d\n",len)); - - return(len); + } } +/******************************************************************* + 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. +*******************************************************************/ - -/**************************************************************************** - read an smb from a fd and return it's length -The timeout is in milli seconds -****************************************************************************/ -BOOL receive_smb(int fd,char *buffer,int timeout) +#ifdef WITH_NISPLUS_HOME +char *automount_lookup(const char *user_name) { - int len; - BOOL ok; - - bzero(buffer,smb_size + 100); - - len = read_smb_length(fd,buffer,timeout); - if (len == -1) - return(False); - - if (len > BUFFER_SIZE) + static fstring last_key = ""; + static pstring last_value = ""; + + char *nis_map = (char *)lp_nis_home_map_name(); + + char buffer[NIS_MAXATTRVAL + 1]; + nis_result *result; + nis_object *object; + entry_obj *entry; + + if (strcmp(user_name, last_key)) + { + slprintf(buffer, sizeof(buffer)-1, "[key=%s],%s", user_name, nis_map); + DEBUG(5, ("NIS+ querystring: %s\n", buffer)); + + if (result = nis_list(buffer, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP, NULL, NULL)) { - DEBUG(0,("Invalid packet length! (%d bytes)\n",len)); - if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) - exit(1); + 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); + pstring_sub(last_value, "&", user_name); + fstrcpy(last_key, user_name); + } + } } + nis_freeresult(result); + } - ok = (read_data(fd,buffer+4,len) == len); + strip_mount_options(&last_value); - if (!ok) - { - close_sockets(); - exit(1); - } - - return(True); + DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; } +#else /* WITH_NISPLUS_HOME */ +char *automount_lookup(const 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(); -/**************************************************************************** - send an smb to a fd -****************************************************************************/ -BOOL send_smb(int fd,char *buffer) -{ - int len; - int ret,nwritten=0; - len = smb_len(buffer) + 4; + if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) { + DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); + return last_value; + } - while (nwritten < len) - { - 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(5, ("NIS Domain: %s\n", nis_domain)); + + 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) { + 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); + + } else if(nis_error == YPERR_KEY) { + + /* If Key lookup fails user home server is not in nis_map + use default information for server, and home directory */ + last_value[0] = 0; + DEBUG(3, ("YP Key not found: while looking up \"%s\" in map \"%s\"\n", + user_name, nis_map)); + DEBUG(3, ("using defaults for server and home directory\n")); + } else { + DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n", + yperr_string(nis_error), user_name, nis_map)); } + } - return True; + DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; } +#endif /* WITH_NISPLUS_HOME */ +#endif -/**************************************************************************** -find a pointer to a netbios name -****************************************************************************/ -char *name_ptr(char *buf,int ofs) +/******************************************************************* +are two IPs on the same subnet? +********************************************************************/ +BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) { - unsigned char c = *(unsigned char *)(buf+ofs); + uint32 net1,net2,nmask; - if ((c & 0xC0) == 0xC0) - { - uint16 l; - char p[2]; - memcpy(p,buf+ofs,2); - p[0] &= ~0xC0; - l = RSVAL(p,0); - DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l)); - return(buf + l); - } - else - return(buf+ofs); -} + nmask = ntohl(mask.s_addr); + net1 = ntohl(ip1.s_addr); + net2 = ntohl(ip2.s_addr); + + return((net1 & nmask) == (net2 & nmask)); +} -/**************************************************************************** -extract a netbios name from a buf -****************************************************************************/ -int name_extract(char *buf,int ofs,char *name) -{ - char *p = name_ptr(buf,ofs); - int d = PTR_DIFF(p,buf+ofs); - strcpy(name,""); - if (d < -50 || d > 50) return(0); - return(name_interpret(p,name)); -} - /**************************************************************************** -return the total storage length of a mangled name +check if a process exists. Does this work on all unixes? ****************************************************************************/ -int name_len(char *s) -{ - char *s0=s; - unsigned char c = *(unsigned char *)s; - if ((c & 0xC0) == 0xC0) - return(2); - while (*s) s += (*s)+1; - return(PTR_DIFF(s,s0)+1); -} -/**************************************************************************** -send a single packet to a port on another machine -****************************************************************************/ -BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type) +BOOL process_exists(pid_t pid) { - BOOL ret; - int out_fd; - struct sockaddr_in sock_out; + /* Doing kill with a non-positive pid causes messages to be + * sent to places we don't want. */ + SMB_ASSERT(pid > 0); + return(kill(pid,0) == 0 || errno != ESRCH); +} - if (passive) - return(True); - /* create a socket to write to */ - out_fd = socket(AF_INET, type, 0); - if (out_fd == -1) - { - DEBUG(0,("socket failed")); - return False; - } - - /* set the address and port */ - bzero((char *)&sock_out,sizeof(sock_out)); - putip((char *)&sock_out.sin_addr,(char *)&ip); - sock_out.sin_port = htons( port ); - sock_out.sin_family = AF_INET; - - if (DEBUGLEVEL > 0) - DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n", - len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM")); - - /* send it */ - ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0); +/******************************************************************* + Convert a uid into a user name. +********************************************************************/ - if (!ret) - DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n", - inet_ntoa(ip),port,errno)); +char *uidtoname(uid_t uid) +{ + static fstring name; + struct passwd *pass; - close(out_fd); - return(ret); + pass = sys_getpwuid(uid); + if (pass) return(pass->pw_name); + slprintf(name, sizeof(name) - 1, "%d",(int)uid); + return(name); } + /******************************************************************* -sleep for a specified number of milliseconds + Convert a gid into a group name. ********************************************************************/ -void msleep(int t) -{ - int tdiff=0; - struct timeval tval,t1,t2; - fd_set fds; - GetTimeOfDay(&t1); - GetTimeOfDay(&t2); - - while (tdiff < t) { - tval.tv_sec = (t-tdiff)/1000; - tval.tv_usec = 1000*((t-tdiff)%1000); - - FD_ZERO(&fds); - errno = 0; - sys_select(&fds,&tval); +char *gidtoname(gid_t gid) +{ + static fstring name; + struct group *grp; - GetTimeOfDay(&t2); - tdiff = TvalDiff(&t1,&t2); - } + grp = getgrgid(gid); + if (grp) return(grp->gr_name); + slprintf(name,sizeof(name) - 1, "%d",(int)gid); + return(name); } -/**************************************************************************** -check if a string is part of a list -****************************************************************************/ -BOOL in_list(char *s,char *list,BOOL casesensitive) +/******************************************************************* + Convert a user name into a uid. If winbindd is present uses this. +********************************************************************/ + +uid_t nametouid(char *name) { - pstring tok; - char *p=list; + struct passwd *pass; + char *p; + uid_t u; - if (!list) return(False); + u = (uid_t)strtol(name, &p, 0); + if ((p != name) && (*p == '\0')) + return u; - while (next_token(&p,tok,LIST_SEP)) - { - if (casesensitive) { - if (strcmp(tok,s) == 0) - return(True); - } else { - if (StrCaseCmp(tok,s) == 0) - return(True); - } - } - return(False); + pass = getpwnam_alloc(name); + if (pass) { + return(pass->pw_uid); + passwd_free(&pass); + } + return (uid_t)-1; } -/* this is used to prevent lots of mallocs of size 1 */ -static char *null_string = NULL; +/******************************************************************* + Convert a name to a gid_t if possible. Return -1 if not a group. If winbindd + is present does a shortcut lookup... +********************************************************************/ -/**************************************************************************** -set a string value, allocing the space for the string -****************************************************************************/ -BOOL string_init(char **dest,char *src) +gid_t nametogid(const char *name) { - int l; - if (!src) - src = ""; + struct group *grp; + char *p; + gid_t g; - l = strlen(src); + g = (gid_t)strtol(name, &p, 0); + if ((p != name) && (*p == '\0')) + return g; - if (l == 0) - { - if (!null_string) - null_string = (char *)malloc(1); - - *null_string = 0; - *dest = null_string; - } - else - { - *dest = (char *)malloc(l+1); - strcpy(*dest,src); - } - return(True); + grp = getgrnam(name); + if (grp) + return(grp->gr_gid); + return (gid_t)-1; } -/**************************************************************************** -free a string value -****************************************************************************/ -void string_free(char **s) +/******************************************************************* +something really nasty happened - panic! +********************************************************************/ +void smb_panic(char *why) { - if (!s || !(*s)) return; - if (*s == null_string) - *s = NULL; - if (*s) free(*s); - *s = NULL; + char *cmd = lp_panic_action(); + if (cmd && *cmd) { + system(cmd); + } + DEBUG(0,("PANIC: %s\n", why)); + dbgflush(); + abort(); } -/**************************************************************************** -set a string value, allocing the space for the string, and deallocating any -existing space -****************************************************************************/ -BOOL string_set(char **dest,char *src) -{ - string_free(dest); - - return(string_init(dest,src)); -} -/**************************************************************************** -substitute a string for a pattern in another string. Make sure there is -enough room! +/******************************************************************* +a readdir wrapper which just returns the file name +********************************************************************/ +char *readdirname(DIR *p) +{ + SMB_STRUCT_DIRENT *ptr; + char *dname; -This routine looks for pattern in s and replaces it with -insert. It may do multiple replacements. + if (!p) return(NULL); + + ptr = (SMB_STRUCT_DIRENT *)sys_readdir(p); + if (!ptr) return(NULL); -return True if a substitution was done. -****************************************************************************/ -BOOL string_sub(char *s,char *pattern,char *insert) -{ - BOOL ret = False; - char *p; - int ls,lp,li; + dname = ptr->d_name; - if (!insert || !pattern || !s) return(False); +#ifdef NEXT2 + if (telldir(p) < 0) return(NULL); +#endif - ls = strlen(s); - lp = strlen(pattern); - li = strlen(insert); +#ifdef HAVE_BROKEN_READDIR + /* using /usr/ucb/cc is BAD */ + dname = dname - 2; +#endif - if (!*pattern) return(False); + { + static pstring buf; + int len = NAMLEN(ptr); + memcpy(buf, dname, len); + buf[len] = 0; + dname = buf; + } - while (lp <= ls && (p = strstr(s,pattern))) - { - ret = True; - memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp)); - memcpy(p,insert,li); - s = p + li; - ls = strlen(s); - } - return(ret); + return(dname); } +/******************************************************************* + Utility function used to decide if the last component + of a path matches a (possibly wildcarded) entry in a namelist. +********************************************************************/ - -/********************************************************* -* Recursive routine that is called by mask_match. -* Does the actual matching. -*********************************************************/ -BOOL do_match(char *str, char *regexp, int case_sig) +BOOL is_in_path(char *name, name_compare_entry *namelist) { + pstring last_component; char *p; - for( p = regexp; *p && *str; ) { - switch(*p) { - case '?': - str++; p++; - break; + DEBUG(8, ("is_in_path: %s\n", name)); - 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++; - 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; - } + /* if we have no list it's obviously not in the path */ + if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) + { + DEBUG(8,("is_in_path: no name list.\n")); + return False; } - if(!*p && !*str) - return True; - if (!*p && str[0] == '.' && str[1] == 0) - return(True); - - if (!*str && *p == '?') + /* Get the last component of the unix name. */ + p = strrchr_m(name, '/'); + strncpy(last_component, p ? ++p : name, sizeof(last_component)-1); + last_component[sizeof(last_component)-1] = '\0'; + + for(; namelist->name != NULL; namelist++) + { + if(namelist->is_wild) { - while (*p == '?') p++; - return(!*p); + if (mask_match(last_component, namelist->name, case_sensitive)) + { + DEBUG(8,("is_in_path: mask match succeeded\n")); + return True; + } } - - if(!*str && (*p == '*' && p[1] == '\0')) - return True; + else + { + if((case_sensitive && (strcmp(last_component, namelist->name) == 0))|| + (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0))) + { + DEBUG(8,("is_in_path: match succeeded\n")); + return True; + } + } + } + DEBUG(8,("is_in_path: match not found\n")); + return False; } - -/********************************************************* -* Routine to match a given string with a regexp - uses -* simplified regexp that takes * and ? only. Case can be -* significant or not. -*********************************************************/ -BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) +/******************************************************************* + 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 *p; - pstring p1, p2; - fstring ebase,eext,sbase,sext; - - BOOL matched; - - /* Make local copies of str and regexp */ - StrnCpy(p1,regexp,sizeof(pstring)-1); - StrnCpy(p2,str,sizeof(pstring)-1); + char *name_end; + char *nameptr = namelist; + int num_entries = 0; + int i; - if (!strchr(p2,'.')) { - strcat(p2,"."); - } + (*ppname_array) = NULL; -/* - if (!strchr(p1,'.')) { - strcat(p1,"."); - } -*/ + if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) + return; -#if 0 - if (strchr(p1,'.')) + /* We need to make two passes over the string. The + first to count the number of elements, the second + to split it. + */ + while(*nameptr) { - 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]); - - if (strequal(p1,"*")) return(True); + if ( *nameptr == '/' ) + { + /* cope with multiple (useless) /s) */ + nameptr++; + continue; + } + /* find the next / */ + name_end = strchr_m(nameptr, '/'); - DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); + /* oops - the last check for a / didn't find one. */ + if (name_end == NULL) + break; - if (trans2) { - strcpy(ebase,p1); - strcpy(sbase,p2); - } else { - if ((p=strrchr(p1,'.'))) { - *p = 0; - strcpy(ebase,p1); - strcpy(eext,p+1); - } else { - strcpy(ebase,p1); - eext[0] = 0; + /* next segment please */ + nameptr = name_end + 1; + num_entries++; } - if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) { - *p = 0; - strcpy(sbase,p2); - strcpy(sext,p+1); - } else { - strcpy(sbase,p2); - strcpy(sext,""); - } - } + if(num_entries == 0) + return; - matched = do_match(sbase,ebase,case_sig) && - (trans2 || do_match(sext,eext,case_sig)); + 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_m(nameptr, '/')) != NULL) + { + *name_end = 0; + } - DEBUG(5,("mask_match returning %d\n", matched)); + /* oops - the last check for a / didn't find one. */ + if(name_end == NULL) + break; - return matched; -} + (*ppname_array)[i].is_wild = ms_has_wild(nameptr); + 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; + return; +} /**************************************************************************** -become a daemon, discarding the controlling terminal +routine to free a namearray. ****************************************************************************/ -void become_daemon(void) + +void free_namearray(name_compare_entry *name_array) { -#ifndef NO_FORK_DEBUG - if (fork()) - exit(0); + if(name_array == NULL) + return; - /* 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); - } - } -#endif -#endif -#endif + SAFE_FREE(name_array->name); + SAFE_FREE(name_array); } /**************************************************************************** -calculate the default netmask for an address + Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping + is dealt with in posix.c ****************************************************************************/ -static void default_netmask(struct in_addr *inm, struct in_addr *iad) -{ - unsigned long ad = ntohl(iad->s_addr); - unsigned long nm; - /* - ** Guess a netmask based on the class of the IP address given. - */ - if ( (ad & 0x80000000) == 0 ) { - /* class A address */ - nm = 0xFF000000; - } else if ( (ad & 0xC0000000) == 0x80000000 ) { - /* class B address */ - nm = 0xFFFF0000; - } else if ( (ad & 0xE0000000) == 0xC0000000 ) { - /* class C address */ - nm = 0xFFFFFF00; - } else { - /* class D or E; netmask doesn't make much sense - guess 4 bits */ - nm = 0xFFFFFFF0; - } - inm->s_addr = htonl(nm); -} -/**************************************************************************** - 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; +BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) +{ + SMB_STRUCT_FLOCK lock; + int ret; -#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 + DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type)); - /* get a default netmask and broadcast */ - default_netmask(if_nmask, if_ipaddr); + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = offset; + lock.l_len = count; + lock.l_pid = 0; -#ifndef NO_GET_BROADCAST - /* Create a socket to the INET kernel. */ -#if USE_SOCKRAW - if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0) -#else - if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0) -#endif - { - DEBUG(0,( "Unable to open socket to get broadcast address\n")); - return; - } - - /* Get a list of the configured interfaces */ -#ifdef EVEREST - /* This is part of SCO Openserver 5: The ioctls are no longer part - if the lower level STREAMS interface glue. They are now real - ioctl calls */ - - if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) { - DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno))); - } else { - DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces)); + errno = 0; - ifc.ifc_len = sizeof(struct ifreq) * n_interfaces; - ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len); + ret = fcntl(fd,op,&lock); - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) - DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno))); - else { - ifr = ifc.ifc_req; + if (errno != 0) + DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); - for (i = 0; i < n_interfaces; ++i) { - if (if_ipaddr->s_addr == - ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) { - found = True; - break; - } - } - } - } -#elif defined(USE_IFREQ) - ifc = (struct ifconf *)buff; - ifc->ifc_len = BUFSIZ - sizeof(struct ifconf); - strioctl.ic_cmd = SIOCGIFCONF; - strioctl.ic_dp = (char *)ifc; - strioctl.ic_len = sizeof(buff); - if (ioctl(sock, I_STR, &strioctl) < 0) { - DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno))); - } else { - ifr = (struct ifreq *)ifc->ifc_req; - - /* Loop through interfaces, looking for given IP address */ - for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { - if (if_ipaddr->s_addr == - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { - found = True; - break; - } - } - } -#elif defined(__FreeBSD__) || defined(NETBSD) - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { - DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); - } else { - ifr = ifc.ifc_req; - /* Loop through interfaces, looking for given IP address */ - i = ifc.ifc_len; - while (i > 0) { - if (if_ipaddr->s_addr == - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { - found = True; - break; - } - i -= ifr->ifr_addr.sa_len + IFNAMSIZ; - ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ); - } - } -#else - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { - DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); - } else { - ifr = ifc.ifc_req; - - /* Loop through interfaces, looking for given IP address */ - for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { -#ifdef BSDI - if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break; -#endif - if (if_ipaddr->s_addr == - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { - found = True; - break; - } + /* a lock query */ + if (op == SMB_F_GETLK) + { + if ((ret != -1) && + (lock.l_type != F_UNLCK) && + (lock.l_pid != 0) && + (lock.l_pid != sys_getpid())) + { + DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid)); + return(True); } - } -#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))); + /* it must be not locked or locked by me */ + return(False); } - /* Close up shop */ - (void) close(sock); - -#endif - - /* sanity check on the netmask */ + /* a lock set or unset */ + if (ret == -1) { - 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); - } + DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n", + (double)offset,(double)count,op,type,strerror(errno))); + return(False); } - /* 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 */ + /* everything went OK */ + DEBUG(8,("fcntl_lock: Lock call successful\n")); + return(True); +} -/**************************************************************************** -put up a yes/no prompt -****************************************************************************/ -BOOL yesno(char *p) +/******************************************************************* +is the name specified one of my netbios names +returns true is it is equal, false otherwise +********************************************************************/ +BOOL is_myname(char *s) { - pstring ans; - printf("%s",p); - - if (!fgets(ans,sizeof(ans)-1,stdin)) - return(False); - - if (*ans == 'y' || *ans == 'Y') - return(True); + int n; + BOOL ret = False; - return(False); + 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); } -/**************************************************************************** -read a line from a file with possible \ continuation chars. -Blanks at the start or end of a line are stripped. -The string will be allocated if s2 is NULL -****************************************************************************/ -char *fgets_slash(char *s2,int maxlen,FILE *f) +BOOL is_myname_or_ipaddr(char *s) { - char *s=s2; - int len = 0; - int c; - BOOL start_of_line = True; - - if (feof(f)) - return(NULL); - - if (!s2) - { - maxlen = MIN(maxlen,8); - s = (char *)Realloc(s,maxlen); - } - - if (!s || maxlen < 2) return(NULL); - - *s = 0; + char **ptr; + + /* optimize for the common case */ + if (strequal(s, global_myname)) + return True; - while (len < maxlen-1) - { - c = getc(f); - switch (c) + /* maybe its an IP address? */ + if (is_ipaddress(s)) { - case '\r': - break; - case '\n': - while (len > 0 && s[len-1] == ' ') - { - s[--len] = 0; - } - if (len > 0 && s[len-1] == '\\') - { - s[--len] = 0; - start_of_line = True; - break; - } - return(s); - case EOF: - if (len <= 0 && !s2) - free(s); - return(len>0?s:NULL); - case ' ': - if (start_of_line) - break; - default: - start_of_line = False; - s[len++] = c; - s[len] = 0; - } - if (!s2 && len > maxlen-3) + struct iface_struct nics[MAX_INTERFACES]; + int i, n; + uint32 ip; + + ip = interpret_addr(s); + if ((ip==0) || (ip==0xffffffff)) + return False; + + n = get_interfaces(nics, MAX_INTERFACES); + for (i=0; i<n; i++) { + if (ip == nics[i].ip.s_addr) + return True; + } + } + + /* check for an alias */ + ptr = lp_netbios_aliases(); + for ( ; *ptr; ptr++ ) { - maxlen *= 2; - s = (char *)Realloc(s,maxlen); - if (!s) return(NULL); + if (StrCaseCmp(s, *ptr) == 0) + return True; } - } - return(s); -} - - - -/**************************************************************************** -set the length of a file from a filedescriptor. -Returns 0 on success, -1 on failure. -****************************************************************************/ -int set_filelen(int fd, long 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); -#else - struct stat st; - char c = 0; - long currpos = lseek(fd, 0L, SEEK_CUR); - - if(currpos < 0) - return -1; - /* Do an fstat to see if the file is longer than - 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) - return -1; - -#ifdef S_ISFIFO - if (S_ISFIFO(st.st_mode)) return 0; -#endif + + + /* no match */ + return False; - if(st.st_size == len) - return 0; - if(st.st_size > len) - return ftruncate(fd, len); - - if(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); - return 0; -#endif } -/**************************************************************************** -return the byte checksum of some data -****************************************************************************/ -int byte_checksum(char *buf,int len) +/******************************************************************* +set the horrid remote_arch string based on an enum. +********************************************************************/ +void set_remote_arch(enum remote_arch_types type) { - unsigned char *p = (unsigned char *)buf; - int ret = 0; - while (len--) - ret += *p++; - return(ret); + extern fstring remote_arch; + 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_WIN2K: + fstrcpy(remote_arch, "Win2K"); + return; + case RA_SAMBA: + fstrcpy(remote_arch,"Samba"); + return; + default: + ra_type = RA_UNKNOWN; + fstrcpy(remote_arch, "UNKNOWN"); + break; + } } - - -#ifdef HPUX -/**************************************************************************** -this is a version of setbuffer() for those machines that only have setvbuf -****************************************************************************/ -void setbuffer(FILE *f,char *buf,int bufsize) +/******************************************************************* + Get the remote_arch type. +********************************************************************/ +enum remote_arch_types get_remote_arch(void) { - setvbuf(f,buf,_IOFBF,bufsize); + return ra_type; } -#endif -/**************************************************************************** -parse out a directory name from a path name. Assumes dos style filenames. -****************************************************************************/ -char *dirname_dos(char *path,char *buf) +void out_ascii(FILE *f, unsigned char *buf,int len) { - char *p = strrchr(path,'\\'); - - if (!p) - strcpy(buf,path); - else - { - *p = 0; - strcpy(buf,path); - *p = '\\'; - } - - return(buf); + int i; + for (i=0;i<len;i++) + { + fprintf(f, "%c", isprint(buf[i])?buf[i]:'.'); + } } - -/**************************************************************************** -parse out a filename from a path name. Assumes dos style filenames. -****************************************************************************/ -static char *filename_dos(char *path,char *buf) +void out_data(FILE *f,char *buf1,int len, int per_line) { - char *p = strrchr(path,'\\'); - - if (!p) - strcpy(buf,path); - else - strcpy(buf,p+1); + unsigned char *buf = (unsigned char *)buf1; + int i=0; + if (len<=0) + { + return; + } - return(buf); + fprintf(f, "[%03X] ",i); + for (i=0;i<len;) + { + fprintf(f, "%02X ",(int)buf[i]); + i++; + if (i%(per_line/2) == 0) fprintf(f, " "); + if (i%per_line == 0) + { + out_ascii(f,&buf[i-per_line ],per_line/2); fprintf(f, " "); + out_ascii(f,&buf[i-per_line/2],per_line/2); fprintf(f, "\n"); + if (i<len) fprintf(f, "[%03X] ",i); + } + } + if ((i%per_line) != 0) + { + int n; + + n = per_line - (i%per_line); + fprintf(f, " "); + if (n>(per_line/2)) fprintf(f, " "); + while (n--) + { + fprintf(f, " "); + } + n = MIN(per_line/2,i%per_line); + out_ascii(f,&buf[i-(i%per_line)],n); fprintf(f, " "); + n = (i%per_line) - n; + if (n>0) out_ascii(f,&buf[i-n],n); + fprintf(f, "\n"); + } } - - -/**************************************************************************** -expand a pointer to be a particular size -****************************************************************************/ -void *Realloc(void *p,int size) +void print_asc(int level, const unsigned char *buf,int len) { - void *ret=NULL; - if (!p) - ret = (void *)malloc(size); - else - ret = (void *)realloc(p,size); - - if (!ret) - DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",size)); - - return(ret); + int i; + for (i=0;i<len;i++) + DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.')); } -/**************************************************************************** -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; +void dump_data(int level, const char *buf1,int len) +{ + const unsigned char *buf = (const unsigned char *)buf1; + int i=0; + if (len<=0) return; - if (sys_utime(fname,×)) { - DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno))); + DEBUG(level,("[%03X] ",i)); + for (i=0;i<len;) { + DEBUG(level,("%02X ",(int)buf[i])); + i++; + if (i%8 == 0) DEBUG(level,(" ")); + if (i%16 == 0) { + print_asc(level,&buf[i-16],8); DEBUG(level,(" ")); + print_asc(level,&buf[i-8],8); DEBUG(level,("\n")); + if (i<len) DEBUG(level,("[%03X] ",i)); + } + } + if (i%16) { + int n; + + n = 16 - (i%16); + DEBUG(level,(" ")); + if (n>8) DEBUG(level,(" ")); + while (n--) DEBUG(level,(" ")); + + n = MIN(8,i%16); + print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" ")); + n = (i%16) - n; + if (n>0) print_asc(level,&buf[i-n],n); + DEBUG(level,("\n")); } - - return(True); } - -#ifdef NOSTRDUP -/**************************************************************************** -duplicate a string -****************************************************************************/ -char *strdup(char *s) +char *tab_depth(int depth) { - char *ret = NULL; - if (!s) return(NULL); - ret = (char *)malloc(strlen(s)+1); - if (!ret) return(NULL); - strcpy(ret,s); - return(ret); + static pstring spaces; + memset(spaces, ' ', depth * 4); + spaces[depth * 4] = 0; + return spaces; } -#endif - -/**************************************************************************** - Signal handler for SIGPIPE (write on a disconnected socket) -****************************************************************************/ -void Abort(void ) +/***************************************************************************** + * Provide a checksum on a string + * + * Input: s - the null-terminated character string for which the checksum + * will be calculated. + * + * Output: The checksum value calculated for s. + * + * **************************************************************************** + */ +int str_checksum(const char *s) { - DEBUG(0,("Probably got SIGPIPE\nExiting\n")); - exit(2); -} - + 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 */ -#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) +/***************************************************************** +zero a memory area then free it. Used to catch bugs faster +*****************************************************************/ +void zero_free(void *p, size_t size) { - 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)); + memset(p, 0, size); + SAFE_FREE(p); } -/******************************************************************* - check for a sane unix date -********************************************************************/ -BOOL sane_unix_date(time_t unixdate) +/***************************************************************** +set our open file limit to a requested max and return the limit +*****************************************************************/ +int set_maxfiles(int requested_max) { - 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); -} +#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)) + struct rlimit rlp; + int saved_current_limit; + if(getrlimit(RLIMIT_NOFILE, &rlp)) { + DEBUG(0,("set_maxfiles: getrlimit (1) for RLIMIT_NOFILE failed with error %s\n", + strerror(errno) )); + /* just guess... */ + return requested_max; + } + /* + * Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to + * account for the extra fd we need + * as well as the log files and standard + * handles etc. Save the limit we want to set in case + * we are running on an OS that doesn't support this limit (AIX) + * which always returns RLIM_INFINITY for rlp.rlim_max. + */ -#ifdef NO_FTRUNCATE - /******************************************************************* -ftruncate for operating systems that don't have it -********************************************************************/ -int ftruncate(int f,long l) -{ - struct flock fl; + /* Try raising the hard (max) limit to the requested amount. */ - fl.l_whence = 0; - fl.l_len = 0; - fl.l_start = l; - fl.l_type = F_WRLCK; - return fcntl(f, F_FREESP, &fl); -} -#endif +#if defined(RLIM_INFINITY) + if (rlp.rlim_max != RLIM_INFINITY) { + int orig_max = rlp.rlim_max; + if ( rlp.rlim_max < requested_max ) + rlp.rlim_max = requested_max; + /* This failing is not an error - many systems (Linux) don't + support our default request of 10,000 open files. JRA. */ -/**************************************************************************** -get my own name and IP -****************************************************************************/ -BOOL get_myname(char *myname,struct in_addr *ip) -{ - struct hostent *hp; - pstring hostname; + if(setrlimit(RLIMIT_NOFILE, &rlp)) { + DEBUG(3,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d max files failed with error %s\n", + (int)rlp.rlim_max, strerror(errno) )); - *hostname = 0; + /* Set failed - restore original value from get. */ + rlp.rlim_max = orig_max; + } + } +#endif - /* get my host name */ - if (gethostname(hostname, MAXHOSTNAMELEN) == -1) - { - DEBUG(0,("gethostname failed\n")); - return False; - } + /* Now try setting the soft (current) limit. */ - /* get host info */ - if ((hp = Get_Hostbyname(hostname)) == 0) - { - DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname)); - return False; - } + saved_current_limit = rlp.rlim_cur = MIN(requested_max,rlp.rlim_max); - if (myname) - { - /* split off any parts after an initial . */ - char *p = strchr(hostname,'.'); - if (p) *p = 0; + if(setrlimit(RLIMIT_NOFILE, &rlp)) { + DEBUG(0,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d files failed with error %s\n", + (int)rlp.rlim_cur, strerror(errno) )); + /* just guess... */ + return saved_current_limit; + } - strcpy(myname,hostname); + if(getrlimit(RLIMIT_NOFILE, &rlp)) { + DEBUG(0,("set_maxfiles: getrlimit (2) for RLIMIT_NOFILE failed with error %s\n", + strerror(errno) )); + /* just guess... */ + return saved_current_limit; } - if (ip) - putip((char *)ip,(char *)hp->h_addr); - - return(True); -} +#if defined(RLIM_INFINITY) + if(rlp.rlim_cur == RLIM_INFINITY) + return saved_current_limit; +#endif + if((int)rlp.rlim_cur > saved_current_limit) + return saved_current_limit; -/**************************************************************************** -true if two IP addresses are equal -****************************************************************************/ -BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) -{ - unsigned long a1,a2; - a1 = ntohl(ip1.s_addr); - a2 = ntohl(ip2.s_addr); - return(a1 == a2); + return rlp.rlim_cur; +#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */ + /* + * No way to know - just guess... + */ + return requested_max; +#endif } - -/**************************************************************************** -open a socket of the specified type, port and address for incoming data -****************************************************************************/ -int open_socket_in(int type, int port, int dlevel) +/***************************************************************** + splits out the start of the key (HKLM or HKU) and the rest of the key + *****************************************************************/ +BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name) { - struct hostent *hp; - struct sockaddr_in sock; - pstring host_name; - 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; } + pstring tmp; - /* get host info */ - if ((hp = Get_Hostbyname(host_name)) == 0) - { - 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 */ - sock.sin_len = sizeof(sock); -#endif - sock.sin_port = htons( port ); - sock.sin_family = hp->h_addrtype; - sock.sin_addr.s_addr = INADDR_ANY; - res = socket(hp->h_addrtype, type, 0); - if (res == -1) - { DEBUG(0,("socket failed\n")); return -1; } - - { - int one=1; - setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); - } + if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp))) + { + return False; + } - /* now we've got a socket - we need to bind it */ - 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))); - close(res); + (*reg_type) = 0; - if (dlevel > 0 && port < 1000) - port = 7999; + DEBUG(10, ("reg_split_key: hive %s\n", tmp)); - if (port >= 1000 && port < 9000) - return(open_socket_in(type,port+1,dlevel)); - } + if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE")) + { + (*reg_type) = HKEY_LOCAL_MACHINE; + } + else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS")) + { + (*reg_type) = HKEY_USERS; + } + else + { + DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp)); + return False; + } + + if (next_token(&full_keyname, tmp, "\n\r", sizeof(tmp))) + { + fstrcpy(key_name, tmp); + } + else + { + key_name[0] = 0; + } - return(-1); - } - DEBUG(3,("bind succeeded on port %d\n",port)); + DEBUG(10, ("reg_split_key: name %s\n", key_name)); - return res; + return True; } -/**************************************************************************** - create an outgoing socket - **************************************************************************/ -int open_socket_out(int type, struct in_addr *addr, int port ) +/***************************************************************** +possibly replace mkstemp if it is broken +*****************************************************************/ +int smb_mkstemp(char *template) { - struct sockaddr_in sock_out; - int res; - - /* create a socket to write to */ - res = socket(PF_INET, type, 0); - if (res == -1) - { DEBUG(0,("socket error\n")); return -1; } - - if (type != SOCK_STREAM) return(res); - - bzero((char *)&sock_out,sizeof(sock_out)); - putip((char *)&sock_out.sin_addr,(char *)addr); - - sock_out.sin_port = htons( port ); - sock_out.sin_family = PF_INET; - - 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); - } - - return res; +#if HAVE_SECURE_MKSTEMP + return mkstemp(template); +#else + /* have a reasonable go at emulating it. Hope that + the system mktemp() isn't completly hopeless */ + char *p = mktemp(template); + if (!p) return -1; + return open(p, O_CREAT|O_EXCL|O_RDWR, 0600); +#endif } -/**************************************************************************** -interpret a protocol description string, with a default -****************************************************************************/ -int interpret_protocol(char *str,int def) +/** + malloc that aborts with smb_panic on fail or zero size. +**/ +void *smb_xmalloc(size_t size) { - if (strequal(str,"NT1")) - return(PROTOCOL_NT1); - if (strequal(str,"LANMAN2")) - return(PROTOCOL_LANMAN2); - if (strequal(str,"LANMAN1")) - return(PROTOCOL_LANMAN1); - if (strequal(str,"CORE")) - return(PROTOCOL_CORE); - if (strequal(str,"COREPLUS")) - return(PROTOCOL_COREPLUS); - if (strequal(str,"CORE+")) - return(PROTOCOL_COREPLUS); - - DEBUG(0,("Unrecognised protocol level %s\n",str)); - - return(def); + void *p; + if (size == 0) + smb_panic("smb_xmalloc: called with zero size.\n"); + if ((p = malloc(size)) == NULL) + smb_panic("smb_xmalloc: malloc fail.\n"); + return p; } -/**************************************************************************** -interpret a security level -****************************************************************************/ -int interpret_security(char *str,int def) +/** + Memdup with smb_panic on fail. +**/ +void *smb_xmemdup(const void *p, size_t size) { - 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); + void *p2; + p2 = smb_xmalloc(size); + memcpy(p2, p, size); + return p2; } - -/**************************************************************************** -interpret an internet address or name into an IP address in 4 byte form -****************************************************************************/ -unsigned long interpret_addr(char *str) +/** + strdup that aborts on malloc fail. +**/ +char *smb_xstrdup(const char *s) { - struct hostent *hp; - unsigned long res; - - if (strcmp(str,"0.0.0.0") == 0) return(0); - if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF); - - /* if it's in the form of an IP address then get the lib to interpret it */ - if (isdigit(str[0])) { - res = inet_addr(str); - } else { - /* 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; - } - putip((char *)&res,(char *)hp->h_addr); - } - - if (res == (unsigned long)-1) return(0); - - return(res); + char *s1 = strdup(s); + if (!s1) + smb_panic("smb_xstrdup: malloc fail\n"); + return s1; } -/******************************************************************* - a convenient addition to interpret_addr() - ******************************************************************/ -struct in_addr *interpret_addr2(char *str) +/* + vasprintf that aborts on malloc fail +*/ +int smb_xvasprintf(char **ptr, const char *format, va_list ap) { - static struct in_addr ret; - unsigned long a = interpret_addr(str); - putip((char *)&ret,(char *)&a); - return(&ret); + int n; + n = vasprintf(ptr, format, ap); + if (n == -1 || ! *ptr) { + smb_panic("smb_xvasprintf: out of memory"); + } + return n; } -/******************************************************************* - check if an IP is the 0.0.0.0 - ******************************************************************/ -BOOL zero_ip(struct in_addr ip) +/***************************************************************** +like strdup but for memory + *****************************************************************/ +void *memdup(const void *p, size_t size) { - unsigned long a; - putip((char *)&a,(char *)&ip); - return(a == 0); + void *p2; + if (size == 0) return NULL; + p2 = malloc(size); + if (!p2) return NULL; + memcpy(p2, p, size); + return p2; } -#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) +/***************************************************************** +get local hostname and cache result + *****************************************************************/ +char *myhostname(void) { - double d; - time_t ret; - uint32 tlow,thigh; - tlow = IVAL(p,0); - thigh = IVAL(p,4); - - if (thigh == 0) return(0); - - d = ((double)thigh)*4.0*(double)(1<<30); - d += (tlow&0xFFF00000); - d *= 1.0e-7; - - /* now adjust by 369 years to make the secs since 1970 */ - d -= TIME_FIXUP_CONSTANT; - - if (d>=MAXINT) - return(0); - - ret = (time_t)(d+0.5); - - /* this takes us from kludge-GMT to real GMT */ - ret += TimeDiff(ret) - serverzone; - - return(ret); + static pstring ret; + if (ret[0] == 0) { + get_myname(ret); + } + return ret; } -/**************************************************************************** -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) +/***************************************************************** +a useful function for returning a path in the Samba lock directory + *****************************************************************/ +char *lock_path(char *name) { - uint32 tlow,thigh; - double d; - - if (t==0) { - SIVAL(p,0,0); SIVAL(p,4,0); - return; - } - - /* this converts GMT to kludge-GMT */ - t -= TimeDiff(t) - serverzone; - - d = (double) (t); + static pstring fname; - d += TIME_FIXUP_CONSTANT; + pstrcpy(fname,lp_lockdir()); + trim_string(fname,"","/"); + + if (!directory_exist(fname,NULL)) { + mkdir(fname,0755); + } + + pstrcat(fname,"/"); + pstrcat(fname,name); - d *= 1.0e7; + return fname; +} - thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30)))); - tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30)); - SIVAL(p,0,tlow); - SIVAL(p,4,thigh); +/** + * @brief Returns an absolute path to a file in the Samba lib directory. + * + * @param name File to find, relative to LIBDIR. + * + * @retval Pointer to a static #pstring containing the full path. + **/ +char *lib_path(char *name) +{ + static pstring fname; + snprintf(fname, sizeof(fname), "%s/%s", dyn_LIBDIR, name); + return fname; } /******************************************************************* -sub strings with useful parameters + Given a filename - get its directory name + NB: Returned in static storage. Caveats: + o Not safe in thread environment. + o Caller must not free. + o If caller wishes to preserve, they should copy. ********************************************************************/ -void standard_sub_basic(char *s) -{ - if (!strchr(s,'%')) return; - - string_sub(s,"%R",remote_proto); - string_sub(s,"%a",remote_arch); - string_sub(s,"%m",remote_machine); - string_sub(s,"%L",local_machine); - if (!strchr(s,'%')) return; - - string_sub(s,"%v",VERSION); - string_sub(s,"%h",myhostname); - string_sub(s,"%U",sesssetup_user); - - if (!strchr(s,'%')) return; - - string_sub(s,"%I",Client_info.addr); - string_sub(s,"%M",Client_info.name); - string_sub(s,"%T",timestring()); - - if (!strchr(s,'%')) return; - - { - char pidstr[10]; - sprintf(pidstr,"%d",(int)getpid()); - string_sub(s,"%d",pidstr); - } +char *parent_dirname(const char *path) +{ + static pstring dirpath; + char *p; - if (!strchr(s,'%')) return; + if (!path) + return(NULL); - { - struct passwd *pass = Get_Pwnam(sesssetup_user,False); - if (pass) { - string_sub(s,"%G",gidtoname(pass->pw_gid)); - } - } + pstrcpy(dirpath, path); + p = strrchr_m(dirpath, '/'); /* Find final '/', if any */ + if (!p) { + pstrcpy(dirpath, "."); /* No final "/", so dir is "." */ + } else { + if (p == dirpath) + ++p; /* For root "/", leave "/" in place */ + *p = '\0'; + } + return dirpath; } /******************************************************************* -write a string in unicoode format -********************************************************************/ -int PutUniCode(char *dst,char *src) +determine if a pattern contains any Microsoft wildcard characters + *******************************************************************/ +BOOL ms_has_wild(char *s) { - int ret = 0; - while (*src) { - dst[ret++] = src[0]; - dst[ret++] = 0; - src++; - } - dst[ret++]=0; - dst[ret++]=0; - return(ret); + char c; + while ((c = *s++)) { + switch (c) { + case '*': + case '?': + case '<': + case '>': + case '"': + return True; + } + } + return False; +} + +BOOL ms_has_wild_w(const smb_ucs2_t *s) +{ + smb_ucs2_t c; + if (!s) return False; + while ((c = *s++)) { + switch (c) { + case UCS2_CHAR('*'): + case UCS2_CHAR('?'): + case UCS2_CHAR('<'): + case UCS2_CHAR('>'): + case UCS2_CHAR('"'): + return True; + } + } + return False; } - -pstring smbrun_path = SMBRUN; - -/**************************************************************************** -run a command via system() using smbrun -****************************************************************************/ -int smbrun(char *cmd,char *outfile) +/******************************************************************* + a wrapper that handles case sensitivity and the special handling + of the ".." name + *******************************************************************/ +BOOL mask_match(char *string, char *pattern, BOOL is_case_sensitive) { - int ret; - pstring syscmd; + fstring p2, s2; - 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"); + if (strcmp(string,"..") == 0) string = "."; + if (strcmp(pattern,".") == 0) return False; + + if (is_case_sensitive) { + return ms_fnmatch(pattern, string, Protocol) == 0; + } - DEBUG(5,("smbrun - running %s ",syscmd)); - ret = system(syscmd); - DEBUG(5,("gave %d\n",ret)); - return(ret); + fstrcpy(p2, pattern); + fstrcpy(s2, string); + strlower(p2); + strlower(s2); + return ms_fnmatch(p2, s2, Protocol) == 0; } +/********************************************************* + Recursive routine that is called by unix_wild_match. +*********************************************************/ -/**************************************************************************** -a wrapper for gethostbyname() that tries with all lower and all upper case -if the initial name fails -****************************************************************************/ -struct hostent *Get_Hostbyname(char *name) -{ - char *name2 = strdup(name); - struct hostent *ret; - - if (!name2) - { - DEBUG(0,("Memory allocation error in Get_Hostbyname! panic\n")); - exit(0); - } +static BOOL unix_do_match(char *regexp, char *str) +{ + char *p; + + 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 && (*p != *str)) + str++; + + /* + * Patch from weidel@multichart.de. In the case of the regexp + * '*XX*' we want to ensure there are at least 2 'X' characters + * in the string after the '*' for a match to be made. + */ + + { + int matchcount=0; + + /* + * Eat all the characters that match, but count how many there were. + */ + + while(*str && (*p == *str)) { + str++; + matchcount++; + } + + /* + * Now check that if the regexp had n identical characters that + * matchcount had at least that many matches. + */ + + while ( *(p+1) && (*(p+1) == *p)) { + p++; + matchcount--; + } + + if ( matchcount <= 0 ) + return False; + } + + str--; /* We've eaten the match char after the '*' */ + + if(unix_do_match(p, str)) + return True; + + if(!*str) + return False; + else + str++; + } + return False; + + default: + if(*str != *p) + return False; + str++; + p++; + break; + } + } - if (!isalnum(*name2)) - { - free(name2); - return(NULL); - } + if(!*p && !*str) + return True; - ret = gethostbyname(name2); - if (ret != NULL) - { - free(name2); - return(ret); - } + if (!*p && str[0] == '.' && str[1] == 0) + return(True); + + if (!*str && *p == '?') { + while (*p == '?') + p++; + return(!*p); + } - /* try with all lowercase */ - strlower(name2); - ret = gethostbyname(name2); - if (ret != NULL) - { - free(name2); - return(ret); - } + if(!*str && (*p == '*' && p[1] == '\0')) + return True; - /* try with all uppercase */ - strupper(name2); - ret = gethostbyname(name2); - if (ret != NULL) - { - free(name2); - return(ret); - } - - /* nothing works :-( */ - free(name2); - return(NULL); + return False; } +/******************************************************************* + Simple case insensitive interface to a UNIX wildcard matcher. +*******************************************************************/ -/**************************************************************************** -check if a process exists. Does this work on all unixes? -****************************************************************************/ -BOOL process_exists(int pid) +BOOL unix_wild_match(char *pattern, char *string) { -#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); + pstring p2, s2; + char *p; - /* otherwise use kill */ - return(pid == getpid() || kill(pid,0) == 0); -#endif -} + pstrcpy(p2, pattern); + pstrcpy(s2, string); + strlower(p2); + strlower(s2); + /* Remove any *? and ** from the pattern as they are meaningless */ + for(p = p2; *p; p++) + while( *p == '*' && (p[1] == '?' ||p[1] == '*')) + pstrcpy( &p[1], &p[2]); + + if (strequal(p2,"*")) + return True; -/******************************************************************* -turn a uid into a user name -********************************************************************/ -char *uidtoname(int uid) -{ - static char name[40]; - struct passwd *pass = getpwuid(uid); - if (pass) return(pass->pw_name); - sprintf(name,"%d",uid); - return(name); + return unix_do_match(p2, s2) == 0; } /******************************************************************* -turn a gid into a group name -********************************************************************/ -char *gidtoname(int gid) + free() a data blob +*******************************************************************/ +static void free_data_blob(DATA_BLOB *d) { - static char name[40]; - struct group *grp = getgrgid(gid); - if (grp) return(grp->gr_name); - sprintf(name,"%d",gid); - return(name); + if ((d) && (d->free)) { + SAFE_FREE(d->data); + } } /******************************************************************* -block sigs -********************************************************************/ -void BlockSignals(BOOL block) + construct a data blob, must be freed with data_blob_free() + you can pass NULL for p and get a blank data blob +*******************************************************************/ +DATA_BLOB data_blob(const void *p, size_t length) { -#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 -} + DATA_BLOB ret; -#if AJT -/******************************************************************* -my own panic function - not suitable for general use -********************************************************************/ -void ajt_panic(void) -{ - pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &"; - smbrun(cmd,NULL); -} -#endif + if (!length) { + ZERO_STRUCT(ret); + return ret; + } -#ifdef USE_DIRECT -#define DIRECT direct -#else -#define DIRECT dirent -#endif + if (p) { + ret.data = smb_xmemdup(p, length); + } else { + ret.data = smb_xmalloc(length); + } + ret.length = length; + ret.free = free_data_blob; + return ret; +} /******************************************************************* -a readdir wrapper which just returns the file name -also return the inode number if requested -********************************************************************/ -char *readdirname(void *p) + construct a data blob, using supplied TALLOC_CTX +*******************************************************************/ +DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length) { - struct DIRECT *ptr; - char *dname; - - if (!p) return(NULL); - - ptr = (struct DIRECT *)readdir(p); - if (!ptr) return(NULL); - - dname = ptr->d_name; - -#ifdef KANJI - { - static pstring buf; - strcpy(buf, dname); - unix_to_dos(buf, True); - dname = buf; - } -#endif - -#ifdef NEXT2 - if (telldir(p) < 0) return(NULL); -#endif - -#ifdef SUNOS5 - /* this handles a broken compiler setup, causing a mixture - of BSD and SYSV headers and libraries */ - { - static BOOL broken_readdir = False; - if (!broken_readdir && !(*(dname)) && strequal("..",dname-2)) - { - DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n")); - broken_readdir = True; - } - if (broken_readdir) - return(dname-2); - } -#endif - - return(dname); -} - - - -#if (defined(SecureWare) && defined(SCO)) -/* This is needed due to needing the nap() function but we don't want - to include the Xenix libraries since that will break other things... - BTW: system call # 0x0c28 is the same as calling nap() */ -long nap(long milliseconds) { - return syscall(0x0c28, milliseconds); -} -#endif - -#ifdef NO_INITGROUPS -#include <sys/types.h> -#include <limits.h> -#include <grp.h> - -#ifndef NULL -#define NULL (void *)0 -#endif + DATA_BLOB ret; -/**************************************************************************** - some systems don't have an initgroups call -****************************************************************************/ -int initgroups(char *name,gid_t id) -{ -#ifdef NO_SETGROUPS - /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ - return(0); -#else - gid_t grouplst[NGROUPS_MAX]; - int i,j; - struct group *g; - char *gr; - - grouplst[0] = id; - i = 1; - while (i < NGROUPS_MAX && - ((g = (struct group *)getgrent()) != (struct group *)NULL)) - { - 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; + if (!p || !length) { + ZERO_STRUCT(ret); + return ret; } - gr = g->gr_mem[++j]; - } - } - endgrent(); - return(setgroups(i,grouplst)); -#endif -} -#endif - - -#if WRAP_MALLOC - -/* undo the wrapping temporarily */ -#undef malloc -#undef realloc -#undef free -/**************************************************************************** -wrapper for malloc() to catch memory errors -****************************************************************************/ -void *malloc_wrapped(int size,char *file,int line) -{ -#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); -} + ret.data = talloc_memdup(mem_ctx, p, length); + if (ret.data == NULL) + smb_panic("data_blob_talloc: talloc_memdup failed.\n"); -/**************************************************************************** -wrapper for realloc() to catch memory errors -****************************************************************************/ -void *realloc_wrapped(void *ptr,int size,char *file,int line) -{ -#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); + ret.length = length; + ret.free = NULL; + return ret; } -/**************************************************************************** -wrapper for free() to catch memory errors -****************************************************************************/ -void free_wrapped(void *ptr,char *file,int line) -{ -#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; -} - -/* 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__) - -#endif - -#ifdef REPLACE_STRSTR -/**************************************************************************** -Mips version of strstr doesn't seem to work correctly. -There is a #define in includes.h to redirect calls to this function. -****************************************************************************/ -char *Strstr(char *s, char *p) +/******************************************************************* +free a data blob +*******************************************************************/ +void data_blob_free(DATA_BLOB *d) { - int len = strlen(p); - - while ( *s != '\0' ) { - if ( strncmp(s, p, len) == 0 ) - return s; - s++; + if (d) { + if (d->free) { + (d->free)(d); + } + ZERO_STRUCTP(d); } - - return NULL; } -#endif /* REPLACE_STRSTR */ - -#ifdef REPLACE_MKTIME /******************************************************************* -a mktime() replacement for those who don't have it - contributed by -C.A. Lademann <cal@zls.com> -********************************************************************/ -#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++; - } - } - - 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 - } - - return(epoch); -} -#endif /* REPLACE_MKTIME */ - - - -#ifdef REPLACE_RENAME -/* Rename a file. (from libiberty in GNU binutils) */ -int -rename (zfrom, zto) - const char *zfrom; - const char *zto; +clear a DATA_BLOB's contents +*******************************************************************/ +void data_blob_clear(DATA_BLOB *d) { - if (link (zfrom, zto) < 0) - { - if (errno != EEXIST) - return -1; - if (unlink (zto) < 0 - || link (zfrom, zto) < 0) - return -1; - } - return unlink (zfrom); + if (d->data) { + memset(d->data, 0, d->length); + } } -#endif - -#ifdef REPLACE_INNETGR -/* - * Search for a match in a netgroup. This replaces it on broken systems. - */ -int InNetGr(group, host, user, dom) - char *group, *host, *user, *dom; +/******************************************************************* +free a data blob and clear its contents +*******************************************************************/ +void data_blob_clear_free(DATA_BLOB *d) { - 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); - } - endnetgrent(); - return (0); + data_blob_clear(d); + data_blob_free(d); } -#endif +#ifdef __INSURE__ -#if WRAP_MEMCPY -#undef memcpy /******************************************************************* -a wrapper around memcpy for diagnostic purposes +This routine is a trick to immediately catch errors when debugging +with insure. A xterm with a gdb is popped up when insure catches +a error. It is Linux specific. ********************************************************************/ -void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line) -{ - 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 -} -#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__) -#endif +int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) +{ + static int (*fn)(); + int ret; + char pidstr[10]; + /* you can get /usr/bin/backtrace from + http://samba.org/ftp/unpacked/junkcode/backtrace */ + pstring cmd = "/usr/bin/backtrace %d"; + + slprintf(pidstr, sizeof(pidstr)-1, "%d", sys_getpid()); + pstring_sub(cmd, "%d", pidstr); + + if (!fn) { + static void *h; + h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY); + fn = dlsym(h, "_Insure_trap_error"); + + if (!h || h == _Insure_trap_error) { + h = dlopen("/usr/local/parasoft/lib.linux2/libinsure.so", RTLD_LAZY); + fn = dlsym(h, "_Insure_trap_error"); + } + } + ret = fn(a1, a2, a3, a4, a5, a6); + system(cmd); + return ret; +} +#endif |