A couple of coding syle updates to follow the re-indent.
[ira/wip.git] / source / lib / util_sock.c
index 16b457c413086ac461e16d90a95d386e18110b62..8e7b69cac8860bc7bc5bb95ed061389e7eb0620c 100644 (file)
@@ -1,8 +1,9 @@
 /* 
    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;
 
@@ -204,109 +203,109 @@ ssize_t read_udp_socket(int fd,char *buf,size_t len)
 
 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;
 }
 
 /****************************************************************************
@@ -318,76 +317,76 @@ static ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t ma
 
 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);
 }
 
 /****************************************************************************
@@ -398,7 +397,7 @@ BOOL send_keepalive(int client)
 {
   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);
@@ -594,7 +593,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 == 0x85
+    if (msg_type == SMBkeepalive
       DEBUG(5,("Got keepalive packet\n"));
   }
 
@@ -622,7 +621,7 @@ ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout)
       return len;
 
     /* Ignore session keepalives. */
-    if(CVAL(inbuf,0) != 0x85)
+    if(CVAL(inbuf,0) != SMBkeepalive)
       break;
   }
 
@@ -704,7 +703,7 @@ BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
     }
 
     /* Ignore session keepalive packets. */
-    if(CVAL(buffer,0) != 0x85)
+    if(CVAL(buffer,0) != SMBkeepalive)
       break;
   }
   show_msg(buffer);
@@ -815,8 +814,8 @@ int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL reb
 #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( "open_socket_in(): setsockopt: ");
+                               dbgtext( "SO_REUSEPORT = %s ", val?"True":"False" );
                                dbgtext( "on port %d failed ", port );
                                dbgtext( "with error = %s\n", strerror(errno) );
                        }
@@ -907,6 +906,37 @@ 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 */
@@ -984,6 +1014,14 @@ 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);
 
@@ -1075,72 +1113,105 @@ int open_pipe_sock(char *path)
        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;
 }
 
 /*******************************************************************
@@ -1235,4 +1306,3 @@ int sock_exec(const char *prog)
        close(fd[1]);
        return fd[0];
 }
-