r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.git] / source / lib / util_sock.c
index 12fc2ead95cffb30c91128c13e8cb8810cc2bc6c..46d640cd55f58c5c5d7d3f7afff1a87719271a14 100644 (file)
@@ -7,7 +7,7 @@
    
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -278,7 +277,12 @@ ssize_t read_udp_socket(int fd,char *buf,size_t len)
        memset((char *)&lastip,'\0',sizeof(lastip));
        ret = (ssize_t)sys_recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen);
        if (ret <= 0) {
-               DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
+               /* Don't print a low debug error for a non-blocking socket. */
+               if (errno == EAGAIN) {
+                       DEBUG(10,("read socket returned EAGAIN. ERRNO=%s\n",strerror(errno)));
+               } else {
+                       DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
+               }
                return(0);
        }
 
@@ -653,10 +657,12 @@ ssize_t read_smb_length(int fd, char *inbuf, unsigned int timeout)
  BUFFER_SIZE+SAFETY_MARGIN.
  The timeout is in milliseconds. 
  This function will return on receipt of a session keepalive packet.
+ maxlen is the max number of bytes to return, not including the 4 byte
+ length. If zero it means BUFFER_SIZE+SAFETY_MARGIN limit.
  Doesn't check the MAC on signed packets.
 ****************************************************************************/
 
-BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
+ssize_t receive_smb_raw(int fd, char *buffer, unsigned int timeout, size_t maxlen)
 {
        ssize_t len,ret;
 
@@ -674,7 +680,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
 
                if (smb_read_error == 0)
                        smb_read_error = READ_ERROR;
-               return False;
+               return -1;
        }
 
        /*
@@ -694,11 +700,15 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
 
                        if (smb_read_error == 0)
                                smb_read_error = READ_ERROR;
-                       return False;
+                       return -1;
                }
        }
 
        if(len > 0) {
+               if (maxlen) {
+                       len = MIN(len,maxlen);
+               }
+
                if (timeout > 0) {
                        ret = read_socket_with_timeout(fd,buffer+4,len,len,timeout);
                } else {
@@ -709,7 +719,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
                        if (smb_read_error == 0) {
                                smb_read_error = READ_ERROR;
                        }
-                       return False;
+                       return -1;
                }
                
                /* not all of samba3 properly checks for packet-termination of strings. This
@@ -717,7 +727,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
                SSVAL(buffer+4,len, 0);
        }
 
-       return True;
+       return len;
 }
 
 /****************************************************************************
@@ -727,19 +737,32 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
 
 BOOL receive_smb(int fd, char *buffer, unsigned int timeout)
 {
-       if (!receive_smb_raw(fd, buffer, timeout)) {
+       if (receive_smb_raw(fd, buffer, timeout, 0) < 0) {
                return False;
        }
 
+       if (srv_encryption_on()) {
+               NTSTATUS status = srv_decrypt_buffer(buffer);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("receive_smb: SMB decryption failed on incoming packet! Error %s\n",
+                               nt_errstr(status) ));
+                       if (smb_read_error == 0) {
+                               smb_read_error = READ_BAD_DECRYPT;
+                       }
+                       return False;
+               }
+       }
+
        /* Check the incoming SMB signature. */
        if (!srv_check_sign_mac(buffer, True)) {
                DEBUG(0, ("receive_smb: SMB Signature verification failed on incoming packet!\n"));
-               if (smb_read_error == 0)
+               if (smb_read_error == 0) {
                        smb_read_error = READ_BAD_SIG;
+               }
                return False;
-       };
+       }
 
-       return(True);
+       return True;
 }
 
 /****************************************************************************
@@ -751,22 +774,34 @@ BOOL send_smb(int fd, char *buffer)
        size_t len;
        size_t nwritten=0;
        ssize_t ret;
+       char *buf_out = buffer;
 
        /* Sign the outgoing packet if required. */
-       srv_calculate_sign_mac(buffer);
+       srv_calculate_sign_mac(buf_out);
 
-       len = smb_len(buffer) + 4;
+       if (srv_encryption_on()) {
+               NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("send_smb: SMB encryption failed on outgoing packet! Error %s\n",
+                               nt_errstr(status) ));
+                       return False;
+               }
+       }
+
+       len = smb_len(buf_out) + 4;
 
        while (nwritten < len) {
-               ret = write_data(fd,buffer+nwritten,len - nwritten);
+               ret = write_data(fd,buf_out+nwritten,len - nwritten);
                if (ret <= 0) {
                        DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
                                (int)len,(int)ret, strerror(errno) ));
+                       srv_free_enc_buffer(buf_out);
                        return False;
                }
                nwritten += ret;
        }
 
+       srv_free_enc_buffer(buf_out);
        return True;
 }
 
@@ -969,7 +1004,10 @@ BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs,
                }
 
                if (errno == EINPROGRESS || errno == EALREADY ||
-                   errno == EAGAIN) {
+#ifdef EISCONN
+                       errno == EISCONN ||
+#endif
+                   errno == EAGAIN || errno == EINTR) {
                        /* These are the error messages that something is
                           progressing. */
                        good_connect = True;
@@ -1003,7 +1041,7 @@ BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs,
        tv.tv_sec = 0;
        tv.tv_usec = connect_loop;
 
-       res = sys_select(maxfd+1, &r_fds, &wr_fds, NULL, &tv);
+       res = sys_select_intr(maxfd+1, &r_fds, &wr_fds, NULL, &tv);
 
        if (res < 0)
                goto done;