diff options
Diffstat (limited to 'source/lib/util_sock.c')
-rw-r--r-- | source/lib/util_sock.c | 582 |
1 files changed, 315 insertions, 267 deletions
diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c index fc2abf976f4..8f5efcab786 100644 --- a/source/lib/util_sock.c +++ b/source/lib/util_sock.c @@ -1,8 +1,8 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 1.9. Samba utility functions Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Tim Potter 2000-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 @@ -21,6 +21,13 @@ #include "includes.h" +#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; @@ -35,7 +42,8 @@ int smb_read_error = 0; BOOL is_a_socket(int fd) { - int v,l; + int v; + socklen_t l; l = sizeof(int); return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0); } @@ -50,7 +58,7 @@ typedef struct smb_socket_option { int opttype; } smb_socket_option; -static const smb_socket_option socket_options[] = { +smb_socket_option 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}, @@ -92,8 +100,9 @@ static const smb_socket_option socket_options[] = { static void print_socket_options(int s) { - int value, vlen = 4; - const smb_socket_option *p = &socket_options[0]; + int value; + socklen_t vlen = 4; + smb_socket_option *p = &socket_options[0]; for (; p->name != NULL; p++) { if (getsockopt(s, p->level, p->option, (void *)&value, &vlen) == -1) { @@ -118,7 +127,7 @@ void set_socket_options(int fd, char *options) char *p; BOOL got_value = False; - if ((p = strchr_m(tok,'='))) { + if ((p = strchr(tok,'='))) { *p = 0; value = atoi(p+1); got_value = True; @@ -186,30 +195,6 @@ ssize_t read_udp_socket(int fd,char *buf,size_t len) return(ret); } -/******************************************************************* - checks if read data is outstanding. - ********************************************************************/ -static int read_data_outstanding(int fd, unsigned int time_out) -{ - int selrtn; - fd_set fds; - struct timeval timeout; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - - timeout.tv_sec = (time_t) (time_out / 1000); - timeout.tv_usec = (long)(1000 * (time_out % 1000)); - - selrtn = sys_select_intr(fd + 1, &fds, NULL, NULL, &timeout); - - if (selrtn <= 0) - { - return selrtn; - } - return FD_ISSET(fd, &fds) ? 1 : 0; -} - /**************************************************************************** Read data from a socket with a timout in msec. mincount = if timeout, minimum to read before returning @@ -219,93 +204,109 @@ static int read_data_outstanding(int fd, unsigned int time_out) static ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out) { - fd_set fds; - int selrtn; - ssize_t readret; - size_t nread = 0; - struct timeval timeout; - - /* just checking .... */ - if (maxcnt <= 0) - return(0); - - smb_read_error = 0; - - /* Blocking read */ - if (time_out <= 0) { - if (mincnt == 0) mincnt = maxcnt; - - while (nread < mincnt) { - readret = sys_read(fd, buf + nread, maxcnt - nread); - - if (readret == 0) { - DEBUG(5,("read_socket_with_timeout: blocking read. EOF from client.\n")); - smb_read_error = READ_EOF; - return -1; - } - - if (readret == -1) { - DEBUG(0,("read_socket_with_timeout: read error = %s.\n", strerror(errno) )); - smb_read_error = READ_ERROR; - return -1; - } - nread += readret; - } - return((ssize_t)nread); - } - - /* Most difficult - timeout read */ - /* If this is ever called on a disk file and - mincnt is greater then the filesize then - system performance will suffer severely as - select always returns true on disk files */ - - /* Set initial timeout */ - timeout.tv_sec = (time_t)(time_out / 1000); - timeout.tv_usec = (long)(1000 * (time_out % 1000)); - - for (nread=0; nread < mincnt; ) { - FD_ZERO(&fds); - FD_SET(fd,&fds); - - selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout); - - /* Check if error */ - if (selrtn == -1) { - /* something is wrong. Maybe the socket is dead? */ - DEBUG(0,("read_socket_with_timeout: timeout read. select error = %s.\n", strerror(errno) )); - smb_read_error = READ_ERROR; - return -1; - } - - /* Did we timeout ? */ - if (selrtn == 0) { - DEBUG(10,("read_socket_with_timeout: timeout read. select timed out.\n")); - smb_read_error = READ_TIMEOUT; - return -1; - } - - readret = sys_read(fd, buf+nread, maxcnt-nread); - - if (readret == 0) { - /* we got EOF on the file descriptor */ - DEBUG(5,("read_socket_with_timeout: timeout read. EOF from client.\n")); - smb_read_error = READ_EOF; - return -1; - } - - if (readret == -1) { - /* the descriptor is probably dead */ - DEBUG(0,("read_socket_with_timeout: timeout read. read error = %s.\n", strerror(errno) )); - smb_read_error = READ_ERROR; - return -1; - } - - nread += readret; - } - - /* Return the number we got */ - return (ssize_t)nread; + fd_set fds; + int selrtn; + ssize_t readret; + size_t nread = 0; + struct timeval timeout; + + /* just checking .... */ + if (maxcnt <= 0) + return(0); + + smb_read_error = 0; + + /* Blocking read */ + if (time_out <= 0) { + if (mincnt == 0) mincnt = maxcnt; + + while (nread < mincnt) { +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = sys_read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ + readret = sys_read(fd, buf + nread, maxcnt - nread); +#endif /* WITH_SSL */ + + if (readret == 0) { + DEBUG(5,("read_socket_with_timeout: blocking read. EOF from client.\n")); + smb_read_error = READ_EOF; + return -1; + } + + if (readret == -1) { + DEBUG(0,("read_socket_with_timeout: read error = %s.\n", strerror(errno) )); + smb_read_error = READ_ERROR; + return -1; + } + nread += readret; + } + return((ssize_t)nread); + } + + /* Most difficult - timeout read */ + /* If this is ever called on a disk file and + mincnt is greater then the filesize then + system performance will suffer severely as + select always returns true on disk files */ + + /* Set initial timeout */ + timeout.tv_sec = (time_t)(time_out / 1000); + timeout.tv_usec = (long)(1000 * (time_out % 1000)); + + for (nread=0; nread < mincnt; ) { + FD_ZERO(&fds); + FD_SET(fd,&fds); + + selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout); + + /* Check if error */ + if(selrtn == -1) { + /* something is wrong. Maybe the socket is dead? */ + DEBUG(0,("read_socket_with_timeout: timeout read. select error = %s.\n", strerror(errno) )); + smb_read_error = READ_ERROR; + return -1; + } + + /* Did we timeout ? */ + if (selrtn == 0) { + DEBUG(10,("read_socket_with_timeout: timeout read. select timed out.\n")); + smb_read_error = READ_TIMEOUT; + return -1; + } + +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = sys_read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ + readret = sys_read(fd, buf+nread, maxcnt-nread); +#endif /* WITH_SSL */ + + if (readret == 0) { + /* we got EOF on the file descriptor */ + DEBUG(5,("read_socket_with_timeout: timeout read. EOF from client.\n")); + smb_read_error = READ_EOF; + return -1; + } + + if (readret == -1) { + /* the descriptor is probably dead */ + DEBUG(0,("read_socket_with_timeout: timeout read. read error = %s.\n", strerror(errno) )); + smb_read_error = READ_ERROR; + return -1; + } + + nread += readret; + } + + /* Return the number we got */ + return((ssize_t)nread); } /**************************************************************************** @@ -315,107 +316,124 @@ static ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t ma time_out = timeout in milliseconds ****************************************************************************/ -ssize_t read_with_timeout(int fd, char *buf, size_t mincnt, size_t maxcnt, - unsigned int time_out) +ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out) { - ssize_t readret; - size_t nread = 0; - - /* just checking .... */ - if (maxcnt <= 0) - return(0); - - /* Blocking read */ - if (time_out <= 0) { - if (mincnt == 0) mincnt = maxcnt; - - while (nread < mincnt) { - readret = sys_read(fd, buf + nread, maxcnt - nread); - - if (readret <= 0) - return readret; - - nread += readret; - } - return((ssize_t)nread); - } - - /* Most difficult - timeout read */ - /* If this is ever called on a disk file and - mincnt is greater then the filesize then - system performance will suffer severely as - select always returns true on disk files */ - - for (nread=0; nread < mincnt; ) { - int selrtn = read_data_outstanding(fd, time_out); - - if(selrtn <= 0) - return selrtn; - - readret = sys_read(fd, buf+nread, maxcnt-nread); - - if (readret <= 0) - return readret; - - nread += readret; - } - - /* Return the number we got */ - return((ssize_t)nread); + fd_set fds; + int selrtn; + ssize_t readret; + size_t nread = 0; + struct timeval timeout; + + /* just checking .... */ + if (maxcnt <= 0) + return(0); + + /* Blocking read */ + if (time_out <= 0) { + if (mincnt == 0) mincnt = maxcnt; + + while (nread < mincnt) { +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = sys_read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ + readret = sys_read(fd, buf + nread, maxcnt - nread); +#endif /* WITH_SSL */ + + if (readret <= 0) + return readret; + + nread += readret; + } + return((ssize_t)nread); + } + + /* Most difficult - timeout read */ + /* If this is ever called on a disk file and + mincnt is greater then the filesize then + system performance will suffer severely as + select always returns true on disk files */ + + /* Set initial timeout */ + timeout.tv_sec = (time_t)(time_out / 1000); + timeout.tv_usec = (long)(1000 * (time_out % 1000)); + + for (nread=0; nread < mincnt; ) { + FD_ZERO(&fds); + FD_SET(fd,&fds); + + selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout); + + if(selrtn <= 0) + return selrtn; + +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = sys_read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ + readret = sys_read(fd, buf+nread, maxcnt-nread); +#endif /* WITH_SSL */ + + if (readret <= 0) + return readret; + + nread += readret; + } + + /* Return the number we got */ + return((ssize_t)nread); } /**************************************************************************** - read data from the client, reading exactly N bytes. +send a keepalive packet (rfc1002) ****************************************************************************/ -ssize_t read_data(int fd,char *buffer,size_t N) +BOOL send_keepalive(int client) { - ssize_t ret; - size_t total=0; - - smb_read_error = 0; - - while (total < N) { - ret = sys_read(fd,buffer + total,N - total); + unsigned char buf[4]; - if (ret == 0) { - DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) )); - smb_read_error = READ_EOF; - return 0; - } + buf[0] = 0x85; + buf[1] = buf[2] = buf[3] = 0; - if (ret == -1) { - DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) )); - smb_read_error = READ_ERROR; - return -1; - } - total += ret; - } - return (ssize_t)total; + return(write_socket_data(client,(char *)buf,4) == 4); } /**************************************************************************** - Read data from a socket, reading exactly N bytes. + read data from the client, reading exactly N bytes. ****************************************************************************/ -static ssize_t read_socket_data(int fd,char *buffer,size_t N) +ssize_t read_data(int fd,char *buffer,size_t N) { - ssize_t ret; + ssize_t ret; size_t total=0; smb_read_error = 0; while (total < N) { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_read(ssl, buffer + total, N - total); + }else{ + ret = sys_read(fd,buffer + total,N - total); + } +#else /* WITH_SSL */ ret = sys_read(fd,buffer + total,N - total); +#endif /* WITH_SSL */ if (ret == 0) { - DEBUG(10,("read_socket_data: recv of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) )); + DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) )); smb_read_error = READ_EOF; return 0; } if (ret == -1) { - DEBUG(0,("read_socket_data: recv failure for %d. Error = %s\n", (int)(N - total), strerror(errno) )); + DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) )); smb_read_error = READ_ERROR; return -1; } @@ -434,17 +452,26 @@ ssize_t write_data(int fd,char *buffer,size_t N) ssize_t ret; while (total < N) { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_write(ssl,buffer + total,N - total); + } else { + ret = sys_write(fd,buffer + total,N - total); + } +#else /* WITH_SSL */ ret = sys_write(fd,buffer + total,N - total); +#endif /* WITH_SSL */ if (ret == -1) { DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) )); return -1; } if (ret == 0) - return total; + return (ssize_t)total; - total += ret; + total += (size_t)ret; } + return (ssize_t)total; } @@ -452,20 +479,28 @@ ssize_t write_data(int fd,char *buffer,size_t N) Write data to a socket - use send rather than write. ****************************************************************************/ -static ssize_t write_socket_data(int fd,char *buffer,size_t N) +ssize_t write_socket_data(int fd,char *buffer,size_t N) { size_t total=0; ssize_t ret; while (total < N) { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_write(ssl,buffer + total,N - total); + }else{ + ret = sys_send(fd,buffer + total,N - total, 0); + } +#else /* WITH_SSL */ ret = sys_send(fd,buffer + total,N - total,0); +#endif /* WITH_SSL */ if (ret == -1) { DEBUG(0,("write_socket_data: write failure. Error = %s\n", strerror(errno) )); return -1; } if (ret == 0) - return total; + return (ssize_t)total; total += ret; } @@ -492,21 +527,6 @@ ssize_t write_socket(int fd,char *buf,size_t len) } /**************************************************************************** -send a keepalive packet (rfc1002) -****************************************************************************/ - -BOOL send_keepalive(int client) -{ - unsigned char buf[4]; - - buf[0] = SMBkeepalive; - buf[1] = buf[2] = buf[3] = 0; - - return(write_socket_data(client,(char *)buf,4) == 4); -} - - -/**************************************************************************** read 4 bytes of a smb packet and return the smb length of the packet store the result in the buffer This version of the function will return a length of zero on receiving @@ -524,7 +544,7 @@ static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int if (timeout > 0) ok = (read_socket_with_timeout(fd,inbuf,4,4,timeout) == 4); else - ok = (read_socket_data(fd,inbuf,4) == 4); + ok = (read_data(fd,inbuf,4) == 4); if (!ok) return(-1); @@ -532,7 +552,7 @@ static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int len = smb_len(inbuf); msg_type = CVAL(inbuf,0); - if (msg_type == SMBkeepalive) + if (msg_type == 0x85) DEBUG(5,("Got keepalive packet\n")); } @@ -559,7 +579,7 @@ ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout) return len; /* Ignore session keepalives. */ - if(CVAL(inbuf,0) != SMBkeepalive) + if(CVAL(inbuf,0) != 0x85) break; } @@ -586,7 +606,7 @@ BOOL receive_smb(int fd,char *buffer, unsigned int timeout) len = read_smb_length_return_keepalive(fd,buffer,timeout); if (len < 0) { - DEBUG(10,("receive_smb: length < 0!\n")); + DEBUG(10,("receive_smb: length < 0 !\n")); /* * Correct fix. smb_read_error may have already been @@ -596,7 +616,7 @@ BOOL receive_smb(int fd,char *buffer, unsigned int timeout) if (smb_read_error == 0) smb_read_error = READ_ERROR; - return False; + return(False); } /* @@ -621,7 +641,7 @@ BOOL receive_smb(int fd,char *buffer, unsigned int timeout) } if(len > 0) { - ret = read_socket_data(fd,buffer+4,len); + ret = read_data(fd,buffer+4,len); if (ret != len) { if (smb_read_error == 0) smb_read_error = READ_ERROR; @@ -633,6 +653,40 @@ BOOL receive_smb(int fd,char *buffer, unsigned int timeout) } /**************************************************************************** + read an smb from a fd ignoring all keepalive packets. Note that the buffer + *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN. + The timeout is in milliseconds + + This is exactly the same as receive_smb except that it never returns + a session keepalive packet (just as receive_smb used to do). + receive_smb was changed to return keepalives as the oplock processing means this call + should never go into a blocking read. +****************************************************************************/ + +BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout) +{ + BOOL ret; + + for(;;) + { + ret = receive_smb(fd, buffer, timeout); + + if (!ret) + { + DEBUG(10,("client_receive_smb failed\n")); + show_msg(buffer); + return ret; + } + + /* Ignore session keepalive packets. */ + if(CVAL(buffer,0) != 0x85) + break; + } + show_msg(buffer); + return ret; +} + +/**************************************************************************** send an smb to a fd ****************************************************************************/ @@ -657,6 +711,45 @@ BOOL send_smb(int fd,char *buffer) } /**************************************************************************** +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 ret; + int out_fd; + struct sockaddr_in sock_out; + + /* 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 */ + memset((char *)&sock_out,'\0',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 = (sys_sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0); + + if (!ret) + DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n", + inet_ntoa(ip),port,strerror(errno))); + + close(out_fd); + return(ret); +} + +/**************************************************************************** Open a socket of the specified type, port, and address for incoming data. ****************************************************************************/ @@ -708,7 +801,7 @@ int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL reb /* now we've got a socket - we need to bind it */ if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) == -1 ) { - if( DEBUGLVL(dlevel) && (port == SMB_PORT1 || port == SMB_PORT2 || port == NMB_PORT) ) { + if( DEBUGLVL(dlevel) && (port == SMB_PORT || port == NMB_PORT) ) { dbgtext( "bind failed on port %d ", port ); dbgtext( "socket_addr = %s.\n", inet_ntoa( sock.sin_addr ) ); dbgtext( "Error = %s\n", strerror(errno) ); @@ -717,7 +810,7 @@ int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL reb return( -1 ); } - DEBUG( 10, ( "bind succeeded on port %d\n", port ) ); + DEBUG( 3, ( "bind succeeded on port %d\n", port ) ); return( res ); } @@ -789,37 +882,6 @@ connect_again: return res; } -/* - open a connected UDP socket to host on port -*/ -int open_udp_socket(const char *host, int port) -{ - int type = SOCK_DGRAM; - struct sockaddr_in sock_out; - int res; - struct in_addr *addr; - - addr = interpret_addr2(host); - - res = socket(PF_INET, type, 0); - if (res == -1) { - return -1; - } - - memset((char *)&sock_out,'\0',sizeof(sock_out)); - putip((char *)&sock_out.sin_addr,(char *)addr); - sock_out.sin_port = htons(port); - sock_out.sin_family = PF_INET; - - if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) { - close(res); - return -1; - } - - return res; -} - - /* the following 3 client_*() functions are nasty ways of allowing some generic functions to get info that really should be hidden in particular modules */ @@ -871,7 +933,7 @@ static BOOL matchname(char *remotehost,struct in_addr addr) /* 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], (char *) & addr, sizeof(addr)) == 0) + if (memcmp(hp->h_addr_list[i], (void *) & addr, sizeof(addr)) == 0) return True; } @@ -897,14 +959,6 @@ char *get_socket_name(int fd) struct hostent *hp; struct in_addr addr; char *p; - - /* reverse lookups can be *very* expensive, and in many - situations won't work because many networks don't link dhcp - with dns. To avoid the delay we avoid the lookup if - possible */ - if (!lp_hostname_lookups()) { - return get_socket_addr(fd); - } p = get_socket_addr(fd); @@ -945,7 +999,7 @@ char *get_socket_addr(int fd) { struct sockaddr sa; struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); - int length = sizeof(sa); + socklen_t length = sizeof(sa); static fstring addr_buf; fstrcpy(addr_buf,"0.0.0.0"); @@ -964,7 +1018,6 @@ char *get_socket_addr(int fd) return addr_buf; } - /******************************************************************* Create protected unix domain socket. @@ -973,10 +1026,9 @@ char *get_socket_addr(int fd) permissions, instead. ******************************************************************/ int create_pipe_sock(const char *socket_dir, - const char *socket_name, - mode_t dir_perms) + const char *socket_name, + mode_t dir_perms) { -#ifdef HAVE_UNIXSOCKET struct sockaddr_un sunaddr; struct stat st; int sock; @@ -1065,10 +1117,6 @@ int create_pipe_sock(const char *socket_dir, /* Success! */ return sock; -#else - DEBUG(0, ("create_pipe_sock: No Unix sockets on this system\n")); - return -1; -#endif /* HAVE_UNIXSOCKET */ } /******************************************************************* |