/*
Unix SMB/Netbios implementation.
- Version 1.9.
+ Version 3.0.
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
#include "includes.h"
#ifdef WITH_SSL
-#include <ssl.h>
+#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 */
-extern int DEBUGLEVEL;
-
/* the last IP received from */
struct in_addr lastip;
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) {
+ 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 = read(fd, buf + nread, maxcnt - nread);
- }
+ if (fd == sslFd) {
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ } else {
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
#else /* WITH_SSL */
- readret = read(fd, buf + nread, maxcnt - nread);
+ readret = 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,&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;
- }
-
+
+ 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,&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 = read(fd, buf + nread, maxcnt - nread);
- }
+ if (fd == sslFd) {
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
#else /* WITH_SSL */
- readret = read(fd, buf+nread, maxcnt-nread);
+ readret = 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);
+
+ 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;
}
/****************************************************************************
ssize_t read_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);
-
- /* Blocking read */
- if (time_out <= 0) {
- if (mincnt == 0) mincnt = maxcnt;
-
- while (nread < mincnt) {
+ 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 = read(fd, buf + nread, maxcnt - nread);
- }
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
#else /* WITH_SSL */
- readret = read(fd, buf + nread, maxcnt - nread);
+ readret = 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,&timeout);
-
- if(selrtn <= 0)
- return selrtn;
-
+
+ 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,&timeout);
+
+ if(selrtn <= 0)
+ return selrtn;
+
#ifdef WITH_SSL
- if(fd == sslFd){
- readret = SSL_read(ssl, buf + nread, maxcnt - nread);
- }else{
- readret = read(fd, buf + nread, maxcnt - nread);
- }
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
#else /* WITH_SSL */
- readret = read(fd, buf+nread, maxcnt-nread);
+ readret = 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);
+
+ if (readret <= 0)
+ return readret;
+
+ nread += readret;
+ }
+
+ /* Return the number we got */
+ return((ssize_t)nread);
}
/****************************************************************************
{
unsigned char buf[4];
- buf[0] = 0x85;
+ buf[0] = SMBkeepalive;
buf[1] = buf[2] = buf[3] = 0;
return(write_socket_data(client,(char *)buf,4) == 4);
len = smb_len(inbuf);
msg_type = CVAL(inbuf,0);
- if (msg_type == 0x85)
+ if (msg_type == SMBkeepalive)
DEBUG(5,("Got keepalive packet\n"));
}
return len;
/* Ignore session keepalives. */
- if(CVAL(inbuf,0) != 0x85)
+ if(CVAL(inbuf,0) != SMBkeepalive)
break;
}
}
/* Ignore session keepalive packets. */
- if(CVAL(buffer,0) != 0x85)
+ if(CVAL(buffer,0) != SMBkeepalive)
break;
}
show_msg(buffer);
}
/****************************************************************************
-open a socket of the specified type, port, and address for incoming data
+ Open a socket of the specified type, port, and address for incoming data.
****************************************************************************/
-int open_socket_in( int type, int port, int dlevel,
- uint32 socket_addr, BOOL rebind )
- {
- struct sockaddr_in sock;
- int res;
+int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL rebind )
+{
+ struct sockaddr_in sock;
+ int res;
- /* Clear the sockaddr_in structure (why not bzero()?). */
- memset( (char *)&sock, '\0', sizeof(sock) );
+ memset( (char *)&sock, '\0', sizeof(sock) );
#ifdef HAVE_SOCK_SIN_LEN
- sock.sin_len = sizeof(sock);
+ sock.sin_len = sizeof(sock);
#endif
- sock.sin_port = htons( port );
- sock.sin_family = AF_INET;
- sock.sin_addr.s_addr = socket_addr;
-
- res = socket( AF_INET, type, 0 );
- if( res < 0 )
- {
- if( DEBUGLVL(0) )
- {
- dbgtext( "open_socket_in(): socket() call failed: " );
- dbgtext( "%s\n", strerror( errno ) );
- }
- return -1;
- }
+ sock.sin_port = htons( port );
+ sock.sin_family = AF_INET;
+ sock.sin_addr.s_addr = socket_addr;
+
+ res = socket( AF_INET, type, 0 );
+ if( res == -1 ) {
+ if( DEBUGLVL(0) ) {
+ dbgtext( "open_socket_in(): socket() call failed: " );
+ dbgtext( "%s\n", strerror( errno ) );
+ }
+ return -1;
+ }
- /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
- {
- int val = rebind ? 1 : 0;
- if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) == -1 )
- {
- if( DEBUGLVL( dlevel ) )
- {
- dbgtext( "open_socket_in(): setsockopt: " );
- dbgtext( "SO_REUSEADDR = %d ", val?"True":"False" );
- dbgtext( "on port %d failed ", port );
- dbgtext( "with error = %s\n", strerror(errno) );
- }
- }
+ /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
+ {
+ int val = rebind ? 1 : 0;
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: " );
+ dbgtext( "SO_REUSEADDR = %s ", val?"True":"False" );
+ dbgtext( "on port %d failed ", port );
+ dbgtext( "with error = %s\n", strerror(errno) );
+ }
+ }
#ifdef SO_REUSEPORT
- if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) == -1 )
- {
- if( DEBUGLVL( dlevel ) )
- {
- dbgtext( "open_socket_in(): setsockopt: "
- dbgtext( "SO_REUSEPORT = %d ", val?"True":"False" );
- dbgtext( "on port %d failed ", port );
- dbgtext( "with error = %s\n", strerror(errno) );
- }
- }
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: ");
+ dbgtext( "SO_REUSEPORT = %s ", val?"True":"False" );
+ dbgtext( "on port %d failed ", port );
+ dbgtext( "with error = %s\n", strerror(errno) );
+ }
+ }
#endif /* SO_REUSEPORT */
- }
+ }
- /* now we've got a socket - we need to bind it */
- if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) < 0 )
- {
- 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) );
- }
- close( res );
- return( -1 );
- }
+ /* 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_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) );
+ }
+ close( res );
+ return( -1 );
+ }
- DEBUG( 3, ( "bind succeeded on port %d\n", port ) );
+ DEBUG( 3, ( "bind succeeded on port %d\n", port ) );
- return( res );
- }
+ return( res );
+ }
/****************************************************************************
create an outgoing socket. timeout is in milliseconds.
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 */
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);
return sock;
}
-int create_pipe_socket(char *dir, int dir_perms,
- char *path, int path_perms)
-{
- int s;
- struct sockaddr_un sa;
-
- DEBUG(0,("create_pipe_socket: %s %d %s %d\n",
- dir, dir_perms, path, path_perms));
-
- DEBUG(0,("*** RACE CONDITION. PLEASE SOMEONE EXAMINE create_pipe_Socket AND FIX IT ***\n"));
-
- mkdir(dir, dir_perms);
-
- if (chmod(dir, dir_perms) < 0)
- {
- DEBUG(0, ("chmod on %s failed\n", dir));
- return -1;
- }
-
- if (!remove(path))
- {
- DEBUG(0, ("remove on %s failed\n", path));
- }
-
- /* start listening on unix socket */
- s = socket(AF_UNIX, SOCK_STREAM, 0);
-
- if (s < 0)
- {
- DEBUG(0, ("socket open failed\n"));
- return -1;
- }
-
- ZERO_STRUCT(sa);
- sa.sun_family = AF_UNIX;
- safe_strcpy(sa.sun_path, path, sizeof(sa.sun_path)-1);
-
- if (bind(s, (struct sockaddr*) &sa, sizeof(sa)) < 0)
- {
- DEBUG(0, ("socket bind to %s failed\n", sa.sun_path));
- close(s);
- remove(path);
- return -1;
- }
-
- if (s == -1)
- {
- DEBUG(0,("bind failed\n"));
- remove(path);
- return -1;
- }
-
- if (path_perms != 0)
- {
- chmod(path, path_perms);
- }
-
- if (listen(s, 5) == -1)
- {
- DEBUG(0,("listen failed\n"));
- return -1;
- }
-
- DEBUG(5,("unix socket opened: %s\n", path));
+/*******************************************************************
+ Create protected unix domain socket.
- return s;
+ some unixen cannot set permissions on a ux-dom-sock, so we
+ have to make sure that the directory contains the protection
+ permissions, instead.
+ ******************************************************************/
+int create_pipe_sock(const char *socket_dir,
+ const char *socket_name,
+ mode_t dir_perms)
+{
+ struct sockaddr_un sunaddr;
+ struct stat st;
+ int sock;
+ mode_t old_umask;
+ pstring path;
+
+ /* Create the socket directory or reuse the existing one */
+
+ if (lstat(socket_dir, &st) == -1) {
+
+ if (errno == ENOENT) {
+
+ /* Create directory */
+
+ if (mkdir(socket_dir, dir_perms) == -1) {
+ DEBUG(0, ("error creating socket directory "
+ "%s: %s\n", socket_dir,
+ strerror(errno)));
+ return -1;
+ }
+
+ } else {
+
+ DEBUG(0, ("lstat failed on socket directory %s: %s\n",
+ socket_dir, strerror(errno)));
+ return -1;
+ }
+
+ } else {
+
+ /* Check ownership and permission on existing directory */
+
+ if (!S_ISDIR(st.st_mode)) {
+ DEBUG(0, ("socket directory %s isn't a directory\n",
+ socket_dir));
+ return -1;
+ }
+
+ if ((st.st_uid != sec_initial_uid()) ||
+ ((st.st_mode & 0777) != dir_perms)) {
+ DEBUG(0, ("invalid permissions on socket directory "
+ "%s\n", socket_dir));
+ return -1;
+ }
+ }
+
+ /* Create the socket file */
+
+ old_umask = umask(0);
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if (sock == -1) {
+ perror("socket");
+ umask(old_umask);
+ return -1;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", socket_dir, socket_name);
+
+ unlink(path);
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ safe_strcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)-1);
+
+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
+ DEBUG(0, ("bind failed on pipe socket %s: %s\n",
+ path,
+ strerror(errno)));
+ close(sock);
+ umask(old_umask);
+ return -1;
+ }
+
+ if (listen(sock, 5) == -1) {
+ DEBUG(0, ("listen failed on pipe socket %s: %s\n",
+ path,
+ strerror(errno)));
+ close(sock);
+ umask(old_umask);
+ return -1;
+ }
+
+ umask(old_umask);
+
+ /* Success! */
+
+ return sock;
}
/*******************************************************************
close(fd[1]);
return fd[0];
}
-