X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Flib%2Futil.c;h=9d6229dbf96d373f9f1fb2229e6ef037b4e9c25b;hb=0776dea81fbf353669714a5e3ff6d62ff6303ed6;hp=6402b9a049d03e7963306ccc6c7809050a91c5ee;hpb=de411c701ed79c02875807dc60ef035d8d08334d;p=kai%2Fsamba.git diff --git a/source3/lib/util.c b/source3/lib/util.c index 6402b9a049d..9d6229dbf96 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Samba utility functions - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1997 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,6 @@ */ #include "includes.h" -#include "loadparm.h" pstring scope = ""; @@ -39,16 +38,15 @@ FILE *dbf = NULL; /* the client file descriptor */ int Client = -1; -/* info on the client */ -struct from_host Client_info= -{"UNKNOWN","0.0.0.0",NULL}; - /* the last IP received from */ struct in_addr lastip; /* the last port received from */ int lastport=0; +/* this is used by the chaining code */ +int chain_size = 0; + int trans_num = 0; /* @@ -56,7 +54,7 @@ int trans_num = 0; */ int case_default = CASE_LOWER; -pstring debugf = "/tmp/log.samba"; +pstring debugf = ""; int syslog_level; /* the following control case operations - they are put here so the @@ -74,7 +72,10 @@ fstring remote_proto="UNKNOWN"; pstring myhostname=""; pstring user_socket_options=""; pstring sesssetup_user=""; +pstring myname = ""; +fstring myworkgroup = ""; +int smb_read_error = 0; static char *filename_dos(char *path,char *buf); @@ -119,6 +120,7 @@ void reopen_logs(void) if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL)) { + int oldumask = umask(022); strcpy(debugf,fname); if (dbf) fclose(dbf); if (append_log) @@ -126,6 +128,7 @@ void reopen_logs(void) else dbf = fopen(debugf,"w"); if (dbf) setbuf(dbf,NULL); + umask(oldumask); } } else @@ -201,7 +204,9 @@ va_dcl { if (!dbf) { + int oldumask = umask(022); dbf = fopen(debugf,"w"); + umask(oldumask); if (dbf) setbuf(dbf,NULL); else @@ -266,6 +271,21 @@ va_dcl return(0); } +/**************************************************************************** + find a suitable temporary directory. The result should be copied immediately + as it may be overwritten by a subsequent call + ****************************************************************************/ +char *tmpdir(void) +{ + char *p; + if ((p = getenv("TMPDIR"))) { + return p; + } + return "/tmp"; +} + + + /**************************************************************************** determine if a file descriptor is in fact a socket ****************************************************************************/ @@ -473,6 +493,12 @@ struct #endif #ifdef SO_RCVLOWAT {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT}, +#endif +#ifdef SO_SNDTIMEO + {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT}, +#endif +#ifdef SO_RCVTIMEO + {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT}, #endif {NULL,0,0,0,0}}; @@ -588,7 +614,7 @@ char *StrCpy(char *dest,char *src) /**************************************************************************** line strncpy but always null terminates. Make sure there is room! ****************************************************************************/ -char *StrnCpy(char *dest,const char *src,int n) +char *StrnCpy(char *dest,char *src,int n) { char *d = dest; if (!dest) return(NULL); @@ -771,25 +797,38 @@ char *attrib_string(int mode) /******************************************************************* case insensitive string compararison ********************************************************************/ -int StrCaseCmp(char *s, char *t) +int StrCaseCmp(const char *s, const char *t) { - for (; tolower(*s) == tolower(*t); ++s, ++t) - if (!*s) return 0; + /* compare until we run out of string, either t or s, or find a difference */ + /* We *must* use toupper rather than tolower here due to the + asynchronous upper to lower mapping. + */ + while (*s && *t && toupper(*s) == toupper(*t)) + { + s++; t++; + } - return tolower(*s) - tolower(*t); + return(toupper(*s) - toupper(*t)); } /******************************************************************* case insensitive string compararison, length limited ********************************************************************/ -int StrnCaseCmp(char *s, char *t, int n) +int StrnCaseCmp(const char *s, const char *t, int n) { - while (n-- && *s && *t) { - if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t)); + /* compare until we run out of string, either t or s, or chars */ + /* We *must* use toupper rather than tolower here due to the + asynchronous upper to lower mapping. + */ + while (n-- && *s && *t && toupper(*s) == toupper(*t)) + { s++; t++; } - if (n) return(tolower(*s) - tolower(*t)); + /* not run out of chars - strings are different lengths */ + if (n) return(toupper(*s) - toupper(*t)); + + /* identical up to where we run out of chars, and strings are same length */ return(0); } @@ -932,9 +971,6 @@ void unix_format(char *fname) { pstring namecopy; string_replace(fname,'\\','/'); -#ifndef KANJI - dos2unix_format(fname, True); -#endif /* KANJI */ if (*fname == '/') { @@ -949,9 +985,6 @@ void unix_format(char *fname) ****************************************************************************/ void dos_format(char *fname) { -#ifndef KANJI - unix2dos_format(fname, True); -#endif /* KANJI */ string_replace(fname,'/','\\'); } @@ -962,6 +995,7 @@ void dos_format(char *fname) void show_msg(char *buf) { int i; + int j; int bcc=0; if (DEBUGLEVEL < 5) return; @@ -987,9 +1021,28 @@ void show_msg(char *buf) DEBUG(5,("smb_bcc=%d\n",bcc)); if (DEBUGLEVEL < 10) return; - for (i=0;i 128) c = '.'; + DEBUG(10,("%c",c)); + + if (j == 7) DEBUG(10, (" ")); + } + + DEBUG(10,("\n")); + } } /******************************************************************* @@ -1074,7 +1127,7 @@ return the SMB offset into an SMB buffer ********************************************************************/ int smb_offset(char *p,char *buf) { - return(PTR_DIFF(p,buf+4)); + return(PTR_DIFF(p,buf+4) + chain_size); } @@ -1158,6 +1211,13 @@ void unix_clean_name(char *s) /* remove any double slashes */ string_sub(s, "//","/"); + /* Remove leading ./ characters */ + if(strncmp(s, "./", 2) == 0) { + trim_string(s, "./", NULL); + if(*s == 0) + strcpy(s,"./"); + } + while ((p = strstr(s,"/../")) != NULL) { pstring s1; @@ -1352,6 +1412,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) DEBUG(3,("Illegal file name? (%s)\n",s)); return(False); } + + if (strlen(s) == 0) + strcpy(s,"./"); + return(True); } @@ -1651,6 +1715,35 @@ void close_low_fds(void) } } +/**************************************************************************** +Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, +else +if SYSV use O_NDELAY +if BSD use FNDELAY +****************************************************************************/ +int set_blocking(int fd, int set) +{ + int val; +#ifdef O_NONBLOCK +#define FLAG_TO_SET O_NONBLOCK +#else +#ifdef SYSV +#define FLAG_TO_SET O_NDELAY +#else /* BSD */ +#define FLAG_TO_SET FNDELAY +#endif +#endif + + if((val = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + if(set) /* Turn blocking on - ie. clear nonblock flag */ + val &= ~FLAG_TO_SET; + else + val |= FLAG_TO_SET; + return fcntl( fd, F_SETFL, val); +#undef FLAG_TO_SET +} + /**************************************************************************** write to a socket @@ -1692,103 +1785,44 @@ int read_udp_socket(int fd,char *buf,int len) return(ret); } -/**************************************************************************** -Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, -else -if SYSV use O_NDELAY -if BSD use FNDELAY -****************************************************************************/ -int set_blocking(int fd, BOOL set) -{ -int val; -#ifdef O_NONBLOCK -#define FLAG_TO_SET O_NONBLOCK -#else -#ifdef SYSV -#define FLAG_TO_SET O_NDELAY -#else /* BSD */ -#define FLAG_TO_SET FNDELAY -#endif -#endif - - if((val = fcntl(fd, F_GETFL, 0))==-1) - return -1; - if(set) /* Turn blocking on - ie. clear nonblock flag */ - val &= ~FLAG_TO_SET; - else - val |= FLAG_TO_SET; - return fcntl( fd, F_SETFL, val); -#undef FLAG_TO_SET -} - - -/**************************************************************************** -Calculate the difference in timeout values. Return 1 if val1 > val2, -0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval -may be == val1 or val2 -****************************************************************************/ -static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2) -{ - int usecdiff = val1->tv_usec - val2->tv_usec; - int secdiff = val1->tv_sec - val2->tv_sec; - if(usecdiff < 0) { - usecdiff = 1000000 + usecdiff; - secdiff--; - } - retval->tv_sec = secdiff; - retval->tv_usec = usecdiff; - if(secdiff < 0) - return -1; - if(secdiff > 0) - return 1; - return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0); -} - /**************************************************************************** read data from a device with a timout in msec. mincount = if timeout, minimum to read before returning maxcount = number to be read. ****************************************************************************/ -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact) +int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out) { fd_set fds; int selrtn; int readret; int nread = 0; - struct timeval timeout, tval1, tval2, tvaldiff; - int error_limit = 5; + struct timeval timeout; /* just checking .... */ if (maxcnt <= 0) return(0); - if(time_out == -2) - time_out = DEFAULT_PIPE_TIMEOUT; + smb_read_error = 0; /* Blocking read */ - if(time_out < 0) { + if (time_out <= 0) { if (mincnt == 0) mincnt = maxcnt; - while (nread < mincnt) - { - readret = read(fd, buf + nread, maxcnt - nread); - if (readret <= 0) return(nread); - nread += readret; + while (nread < mincnt) { + readret = read(fd, buf + nread, maxcnt - nread); + if (readret == 0) { + smb_read_error = READ_EOF; + return -1; } + + if (readret == -1) { + smb_read_error = READ_ERROR; + return -1; + } + nread += readret; + } return(nread); } - /* Non blocking read */ - if(time_out == 0) { - set_blocking(fd, False); - nread = read_data(fd, buf, mincnt); - if (nread < maxcnt) - nread += read(fd,buf+nread,maxcnt-nread); - if(nread == -1 && errno == EWOULDBLOCK) - nread = 0; - set_blocking(fd,True); - return nread; - } - /* Most difficult - timeout read */ /* If this is ever called on a disk file and mincnt is greater then the filesize then @@ -1799,69 +1833,40 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL timeout.tv_sec = time_out / 1000; timeout.tv_usec = 1000 * (time_out % 1000); - /* As most UNIXes don't modify the value of timeout - when they return from select we need to get the timeofday (in usec) - now, and also after the select returns so we know - how much time has elapsed */ - - if (exact) - GetTimeOfDay( &tval1); - nread = 0; /* Number of bytes we have read */ - - for(;;) + for (nread=0; nread= mincnt) - break; - - /* We need to do another select - but first reduce the - time_out by the amount of time already elapsed - if - this is less than zero then return */ - if (exact) { - GetTimeOfDay(&tval2); - (void)tval_sub( &tvaldiff, &tval2, &tval1); - - if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) - break; /* We timed out */ - } - - /* Save the time of day as we need to do the select - again (saves a system call) */ - tval1 = tval2; } /* Return the number we got */ @@ -1928,12 +1933,19 @@ int read_data(int fd,char *buffer,int N) int ret; int total=0; + smb_read_error = 0; + while (total < N) { ret = read(fd,buffer + total,N - total); - - if (ret <= 0) - return total; + if (ret == 0) { + smb_read_error = READ_EOF; + return 0; + } + if (ret == -1) { + smb_read_error = READ_ERROR; + return -1; + } total += ret; } return total; @@ -1952,8 +1964,8 @@ int write_data(int fd,char *buffer,int N) { ret = write(fd,buffer + total,N - total); - if (ret <= 0) - return total; + if (ret == -1) return -1; + if (ret == 0) return total; total += ret; } @@ -2057,30 +2069,19 @@ int read_smb_length(int fd,char *inbuf,int timeout) while (!ok) { if (timeout > 0) - ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4); - else + ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4); + else ok = (read_data(fd,buffer,4) == 4); if (!ok) - { - if (timeout>0) - { - DEBUG(10,("select timeout (%d)\n", timeout)); - return(-1); - } - else - { - DEBUG(6,("couldn't read from client\n")); - exit(1); - } - } + return(-1); len = smb_len(buffer); msg_type = CVAL(buffer,0); if (msg_type == 0x85) { - DEBUG(5,( "Got keepalive packet\n")); + DEBUG(5,("Got keepalive packet\n")); ok = False; } } @@ -2098,8 +2099,9 @@ The timeout is in milli seconds ****************************************************************************/ BOOL receive_smb(int fd,char *buffer,int timeout) { - int len; - BOOL ok; + int len,ret; + + smb_read_error = 0; bzero(buffer,smb_size + 100); @@ -2108,18 +2110,16 @@ BOOL receive_smb(int fd,char *buffer,int timeout) return(False); if (len > BUFFER_SIZE) { - DEBUG(0,("Invalid packet length! (%d bytes)\n",len)); + DEBUG(0,("Invalid packet length! (%d bytes).\n",len)); if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) exit(1); } - ok = (read_data(fd,buffer+4,len) == len); - - if (!ok) - { - close_sockets(); - exit(1); - } + ret = read_data(fd,buffer+4,len); + if (ret != len) { + smb_read_error = READ_ERROR; + return False; + } return(True); } @@ -2788,7 +2788,7 @@ void Abort(void ) /**************************************************************************** get my own name and IP ****************************************************************************/ -BOOL get_myname(char *myname,struct in_addr *ip) +BOOL get_myname(char *my_name,struct in_addr *ip) { struct hostent *hp; pstring hostname; @@ -2809,13 +2809,13 @@ BOOL get_myname(char *myname,struct in_addr *ip) return False; } - if (myname) + if (my_name) { /* split off any parts after an initial . */ char *p = strchr(hostname,'.'); if (p) *p = 0; - strcpy(myname,hostname); + strcpy(my_name,hostname); } if (ip) @@ -2830,7 +2830,7 @@ true if two IP addresses are equal ****************************************************************************/ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) { - unsigned long a1,a2; + uint32 a1,a2; a1 = ntohl(ip1.s_addr); a2 = ntohl(ip2.s_addr); return(a1 == a2); @@ -2840,7 +2840,7 @@ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) /**************************************************************************** open a socket of the specified type, port and address for incoming data ****************************************************************************/ -int open_socket_in(int type, int port, int dlevel) +int open_socket_in(int type, int port, int dlevel,uint32 socket_addr) { struct hostent *hp; struct sockaddr_in sock; @@ -2865,7 +2865,7 @@ int open_socket_in(int type, int port, int dlevel) #endif sock.sin_port = htons( port ); sock.sin_family = hp->h_addrtype; - sock.sin_addr.s_addr = INADDR_ANY; + sock.sin_addr.s_addr = socket_addr; res = socket(hp->h_addrtype, type, 0); if (res == -1) { DEBUG(0,("socket failed\n")); return -1; } @@ -2880,15 +2880,15 @@ int open_socket_in(int type, int port, int dlevel) { if (port) { if (port == SMB_PORT || port == NMB_PORT) - DEBUG(dlevel,("bind failed on port %d (%s)\n", - port,strerror(errno))); + DEBUG(dlevel,("bind failed on port %d socket_addr=%x (%s)\n", + port,socket_addr,strerror(errno))); close(res); if (dlevel > 0 && port < 1000) port = 7999; if (port >= 1000 && port < 9000) - return(open_socket_in(type,port+1,dlevel)); + return(open_socket_in(type,port+1,dlevel,socket_addr)); } return(-1); @@ -2902,10 +2902,12 @@ int open_socket_in(int type, int port, int dlevel) /**************************************************************************** create an outgoing socket **************************************************************************/ -int open_socket_out(int type, struct in_addr *addr, int port ) +int open_socket_out(int type, struct in_addr *addr, int port ,int timeout) { struct sockaddr_in sock_out; - int res; + int res,ret; + int connect_loop = 250; /* 250 milliseconds */ + int loops = (timeout * 1000) / connect_loop; /* create a socket to write to */ res = socket(PF_INET, type, 0); @@ -2920,15 +2922,45 @@ int open_socket_out(int type, struct in_addr *addr, int port ) sock_out.sin_port = htons( port ); sock_out.sin_family = PF_INET; + /* set it non-blocking */ + set_blocking(res,0); + DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port)); /* and connect it to the destination */ - if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) { - DEBUG(0,("connect error: %s\n",strerror(errno))); - close(res); - return(-1); +connect_again: + ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out)); + + /* Some systems return EAGAIN when they mean EINPROGRESS */ + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN) && loops--) { + msleep(connect_loop); + goto connect_again; + } + + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN)) { + DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port)); + close(res); + return -1; } +#ifdef EISCONN + if (ret < 0 && errno == EISCONN) { + errno = 0; + ret = 0; + } +#endif + + if (ret < 0) { + DEBUG(1,("error connecting to %s:%d (%s)\n", + inet_ntoa(*addr),port,strerror(errno))); + return -1; + } + + /* set it blocking again */ + set_blocking(res,1); + return res; } @@ -2977,19 +3009,26 @@ int interpret_security(char *str,int def) /**************************************************************************** interpret an internet address or name into an IP address in 4 byte form ****************************************************************************/ -unsigned long interpret_addr(char *str) +uint32 interpret_addr(char *str) { struct hostent *hp; - unsigned long res; + uint32 res; + int i; + BOOL pure_address = True; if (strcmp(str,"0.0.0.0") == 0) return(0); if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF); + for (i=0; pure_address && str[i]; i++) + if (!(isdigit(str[i]) || str[i] == '.')) + pure_address = False; + /* if it's in the form of an IP address then get the lib to interpret it */ - if (isdigit(str[0])) { + if (pure_address) { res = inet_addr(str); } else { - /* otherwise assume it's a network name of some sort and use Get_Hostbyname */ + /* otherwise assume it's a network name of some sort and use + Get_Hostbyname */ if ((hp = Get_Hostbyname(str)) == 0) { DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str)); return 0; @@ -2997,7 +3036,7 @@ unsigned long interpret_addr(char *str) putip((char *)&res,(char *)hp->h_addr); } - if (res == (unsigned long)-1) return(0); + if (res == (uint32)-1) return(0); return(res); } @@ -3008,7 +3047,7 @@ unsigned long interpret_addr(char *str) struct in_addr *interpret_addr2(char *str) { static struct in_addr ret; - unsigned long a = interpret_addr(str); + uint32 a = interpret_addr(str); ret.s_addr = a; return(&ret); } @@ -3018,11 +3057,138 @@ struct in_addr *interpret_addr2(char *str) ******************************************************************/ BOOL zero_ip(struct in_addr ip) { - unsigned long a; + uint32 a; putip((char *)&a,(char *)&ip); return(a == 0); } + +/******************************************************************* + matchname - determine if host name matches IP address + ******************************************************************/ +static BOOL matchname(char *remotehost,struct in_addr addr) +{ + struct hostent *hp; + int i; + + if ((hp = Get_Hostbyname(remotehost)) == 0) { + DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost)); + return False; + } + + /* + * Make sure that gethostbyname() returns the "correct" host name. + * Unfortunately, gethostbyname("localhost") sometimes yields + * "localhost.domain". Since the latter host name comes from the + * local DNS, we just have to trust it (all bets are off if the local + * DNS is perverted). We always check the address list, though. + */ + + if (strcasecmp(remotehost, hp->h_name) + && strcasecmp(remotehost, "localhost")) { + DEBUG(0,("host name/name mismatch: %s != %s", + remotehost, hp->h_name)); + return False; + } + + /* Look up the host address in the address list we just got. */ + for (i = 0; hp->h_addr_list[i]; i++) { + if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0) + return True; + } + + /* + * The host name does not map to the original host address. Perhaps + * someone has compromised a name server. More likely someone botched + * it, but that could be dangerous, too. + */ + + DEBUG(0,("host name/address mismatch: %s != %s", + inet_ntoa(addr), hp->h_name)); + return False; +} + +/******************************************************************* + Reset the 'done' variables so after a client process is created + from a fork call these calls will be re-done. This should be + expanded if more variables need reseting. + ******************************************************************/ + +static BOOL global_client_name_done = False; +static BOOL global_client_addr_done = False; + +void reset_globals_after_fork() +{ + global_client_name_done = False; + global_client_addr_done = False; +} + +/******************************************************************* + return the DNS name of the client + ******************************************************************/ +char *client_name(void) +{ + extern int Client; + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static pstring name_buf; + struct hostent *hp; + + if (global_client_name_done) + return name_buf; + + strcpy(name_buf,"UNKNOWN"); + + if (getpeername(Client, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return name_buf; + } + + /* Look up the remote host name. */ + if ((hp = gethostbyaddr((char *) &sockin->sin_addr, + sizeof(sockin->sin_addr), + AF_INET)) == 0) { + DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr())); + StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1); + } else { + StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1); + if (!matchname(name_buf, sockin->sin_addr)) { + DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr())); + strcpy(name_buf,"UNKNOWN"); + } + } + global_client_name_done = True; + return name_buf; +} + +/******************************************************************* + return the IP addr of the client as a string + ******************************************************************/ +char *client_addr(void) +{ + extern int Client; + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static fstring addr_buf; + + if (global_client_addr_done) + return addr_buf; + + strcpy(addr_buf,"0.0.0.0"); + + if (getpeername(Client, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return addr_buf; + } + + strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); + + global_client_addr_done = True; + return addr_buf; +} + /******************************************************************* sub strings with useful parameters ********************************************************************/ @@ -3043,8 +3209,9 @@ void standard_sub_basic(char *s) if (!strchr(s,'%')) return; - string_sub(s,"%I",Client_info.addr); - string_sub(s,"%M",Client_info.name); + string_sub(s,"%I",client_addr()); + if (strstr(s,"%M")) + string_sub(s,"%M",client_name()); string_sub(s,"%T",timestring()); if (!strchr(s,'%')) return; @@ -3071,7 +3238,7 @@ are two IPs on the same subnet? ********************************************************************/ BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) { - unsigned long net1,net2,nmask; + uint32 net1,net2,nmask; nmask = ntohl(mask.s_addr); net1 = ntohl(ip1.s_addr); @@ -3118,7 +3285,7 @@ struct hostent *Get_Hostbyname(char *name) return(NULL); } - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -3127,7 +3294,7 @@ struct hostent *Get_Hostbyname(char *name) /* try with all lowercase */ strlower(name2); - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -3136,7 +3303,7 @@ struct hostent *Get_Hostbyname(char *name) /* try with all uppercase */ strupper(name2); - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -3165,7 +3332,7 @@ BOOL process_exists(int pid) fstring s; if (!tested) { tested = True; - sprintf(s,"/proc/%05d",getpid()); + sprintf(s,"/proc/%05d",(int)getpid()); ok = file_exist(s,NULL); } if (ok) { @@ -3174,11 +3341,8 @@ BOOL process_exists(int pid) } } - /* a best guess for non root access */ - if (geteuid() != 0) return(True); - - /* otherwise use kill */ - return(pid == getpid() || kill(pid,0) == 0); + /* CGH 8/16/96 - added ESRCH test */ + return(pid == getpid() || kill(pid,0) == 0 || errno != ESRCH); #endif } @@ -3210,16 +3374,20 @@ char *gidtoname(int gid) /******************************************************************* block sigs ********************************************************************/ -void BlockSignals(BOOL block) +void BlockSignals(BOOL block,int signum) { #ifdef USE_SIGBLOCK - int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV) - |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)| - sigmask(SIGINT)); + int block_mask = sigmask(signum); + static int oldmask = 0; if (block) - sigblock(block_mask); + oldmask = sigblock(block_mask); else - sigunblock(block_mask); + sigsetmask(oldmask); +#elif defined(USE_SIGPROCMASK) + sigset_t set; + sigemptyset(&set); + sigaddset(&set,signum); + sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL); #endif } @@ -3229,7 +3397,7 @@ my own panic function - not suitable for general use ********************************************************************/ void ajt_panic(void) { - system("/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT"); + system("/usr/bin/X11/xedit -display ljus:0 /tmp/ERROR_FAULT"); } #endif @@ -3255,15 +3423,6 @@ char *readdirname(void *p) dname = ptr->d_name; -#ifdef KANJI - { - static pstring buf; - strcpy(buf, dname); - unix_to_dos(buf, True); - dname = buf; - } -#endif - #ifdef NEXT2 if (telldir(p) < 0) return(NULL); #endif @@ -3279,12 +3438,248 @@ char *readdirname(void *p) broken_readdir = True; } if (broken_readdir) - return(dname-2); + dname = dname - 2; } #endif + { + static pstring buf; + strcpy(buf, dname); + unix_to_dos(buf, True); + dname = buf; + } + return(dname); } +/* + * Utility function used by is_hidden_path() and is_vetoed_name() + * to decide if the last component of a path matches a (possibly + * wildcarded) entry in a namelist. + */ + +static BOOL is_in_path(char *name, char *namelist) +{ + pstring last_component; + char *p; + char *nameptr = namelist; + char *name_end; + + DEBUG(5, ("is_in_path: %s list: %s\n", name, namelist)); + + /* if we have no list it's obviously not in the path */ + if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) + { + DEBUG(5,("is_in_path: no name list. return False\n")); + return False; + } + + /* Get the last component of the unix name. */ + p = strrchr(name, '/'); + strncpy(last_component, p ? p : name, sizeof(last_component)-1); + last_component[sizeof(last_component)-1] = '\0'; + + /* now, we need to find the names one by one and check them + they can contain spaces and all sorts of stuff so we + separate them with of all things '\' which can never be in a filename + I could use "" but then I have to break them all out + maybe such a routine exists somewhere? + */ + + /* lkcl 03jul97 - the separator character used to be a '/'. + i changed it to a '\', after examining the code, and seeing + that unix_convert is called before check_path and dos_mode. + unix_convert changes, in the path, all dos '\'s to unix '/'s. + + the alternatives are: + + 1) move all check_path and dos_mode calls to before the + unix_convert calls. + + 2) have a corresponding dos_convert call, which can be used + in here to reverse '/'s into '\'s and vice-versa. users + would specify the lp_veto_files and lp_hide_files parameters + in dos mode path format ('\' for directory separator), with a + list separator of '/', and they would be swapped inside this + function, before making the search. + + */ + + while (*nameptr) + { + if ( *nameptr == '/' ) + { + /* cope with multiple (useless) /s) */ + nameptr++; + continue; + } + /* find the next / */ + if ((name_end = strchr(nameptr,'/')) != NULL) + { + *name_end = 0; + } + + /* look for a match. */ + if (mask_match(last_component, nameptr, case_sensitive, False)) + { + DEBUG(5,("is_in_path: mask match succeeded\n")); + return True; + } + + /* oops - the last check for a / didn't find one. */ + if (name_end == NULL) + { + DEBUG(5,("is_in_path: last name. failed\n")); + return False; + } + + /* next segment please */ + nameptr = name_end + 1; + } + + DEBUG(5,("is_in_path: not found\n")); + + return False; +} + +BOOL is_hidden_path(int snum, char *name) +{ + return is_in_path(name, lp_hide_files(snum)); +} + +BOOL is_vetoed_name(int snum, char *name) +{ + return is_in_path(name, lp_veto_files(snum)); +} + +/**************************************************************************** +routine to do file locking +****************************************************************************/ +BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) +{ +#if HAVE_FCNTL_LOCK + struct flock lock; + int ret; + +#if 1 + uint32 mask = 0xC0000000; + + /* make sure the count is reasonable, we might kill the lockd otherwise */ + count &= ~mask; + + /* the offset is often strange - remove 2 of its bits if either of + the top two bits are set. Shift the top ones by two bits. This + still allows OLE2 apps to operate, but should stop lockd from + dieing */ + if ((offset & mask) != 0) + offset = (offset & ~mask) | ((offset & mask) >> 2); +#else + uint32 mask = ((unsigned)1<<31); + + /* interpret negative counts as large numbers */ + if (count < 0) + count &= ~mask; + + /* no negative offsets */ + offset &= ~mask; + + /* count + offset must be in range */ + while ((offset < 0 || (offset + count < 0)) && mask) + { + offset &= ~mask; + mask = mask >> 1; + } +#endif + + + DEBUG(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); +}