Imported Upstream version 3.2.0
[debian/amanda] / common-src / security-util.c
index 4fa750d4e8c26826e9bb5b95cf073623a5f09ce8..bc108cdd0fbfcd4747579ce02ce4f933bdd728c9 100644 (file)
 #include "stream.h"
 #include "sockaddr-util.h"
 
-/*
- * Magic values for sec_conn->handle
- */
-#define        H_TAKEN -1              /* sec_conn->tok was already read */
-#define        H_EOF   -2              /* this connection has been shut down */
-
 /*
  * This is a queue of open connections
  */
@@ -108,7 +102,7 @@ sec_accept(
 {
     struct tcp_conn *rc;
 
-    rc = sec_tcp_conn_get("unknown",0);
+    rc = sec_tcp_conn_get("",0); /* no hostname yet */
     rc->read = in;
     rc->write = out;
     rc->accept_fn = fn;
@@ -432,11 +426,18 @@ tcpm_send_token(
     char               *encbuf;
     ssize_t            encsize;
     int                        save_errno;
+    time_t             logtime;
 
     assert(SIZEOF(netlength) == 4);
 
+    logtime = time(NULL);
+    if (rc && logtime > rc->logstamp + 10) {
+       g_debug("tcpm_send_token: data is still flowing");
+        rc->logstamp = logtime;
+    }
+
     auth_debug(1, "tcpm_send_token: write %zd bytes to handle %d\n",
-         len, handle);
+              len, handle);
     /*
      * Format is:
      *   32 bit length (network byte order)
@@ -487,6 +488,7 @@ tcpm_send_token(
 }
 
 /*
+ *  return -2 for incomplete packet
  *  return -1 on error
  *  return  0 on EOF:   *handle = H_EOF  && *size = 0    if socket closed
  *  return  0 on EOF:   *handle = handle && *size = 0    if stream closed
@@ -500,93 +502,118 @@ tcpm_recv_token(
     int *      handle,
     char **    errmsg,
     char **    buf,
-    ssize_t *  size,
-    int                timeout)
+    ssize_t *  size)
 {
-    unsigned int netint[2];
-
-    assert(SIZEOF(netint) == 8);
-
-    switch (net_read(fd, &netint, SIZEOF(netint), timeout)) {
-    case -1:
-       if (errmsg)
-           *errmsg = newvstrallocf(*errmsg, _("recv error: %s"), strerror(errno));
-       auth_debug(1, _("tcpm_recv_token: A return(-1)\n"));
-       return (-1);
-    case 0:
-       *size = 0;
-       *handle = H_EOF;
-       *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
-       auth_debug(1, _("tcpm_recv_token: A return(0)\n"));
-       return (0);
-    default:
-       break;
-    }
-
-    *size = (ssize_t)ntohl(netint[0]);
-    *handle = (int)ntohl(netint[1]);
-    /* amanda protocol packet can be above NETWORK_BLOCK_BYTES */
-    if (*size > 128*NETWORK_BLOCK_BYTES || *size < 0) {
-       if (isprint((int)(*size        ) & 0xFF) &&
-           isprint((int)(*size   >> 8 ) & 0xFF) &&
-           isprint((int)(*size   >> 16) & 0xFF) &&
-           isprint((int)(*size   >> 24) & 0xFF) &&
-           isprint((*handle      ) & 0xFF) &&
-           isprint((*handle >> 8 ) & 0xFF) &&
-           isprint((*handle >> 16) & 0xFF) &&
-           isprint((*handle >> 24) & 0xFF)) {
-           char s[101];
-           int i;
-           s[0] = ((int)(*size)  >> 24) & 0xFF;
-           s[1] = ((int)(*size)  >> 16) & 0xFF;
-           s[2] = ((int)(*size)  >>  8) & 0xFF;
-           s[3] = ((int)(*size)       ) & 0xFF;
-           s[4] = (*handle >> 24) & 0xFF;
-           s[5] = (*handle >> 16) & 0xFF;
-           s[6] = (*handle >> 8 ) & 0xFF;
-           s[7] = (*handle      ) & 0xFF;
-           i = 8; s[i] = ' ';
-           while(i<100 && isprint((int)s[i]) && s[i] != '\n') {
-               switch(net_read(fd, &s[i], 1, 0)) {
-               case -1: s[i] = '\0'; break;
-               case  0: s[i] = '\0'; break;
-               default:
+    ssize_t     rval;
+
+    assert(SIZEOF(rc->netint) == 8);
+    if (rc->size_header_read < (ssize_t)SIZEOF(rc->netint)) {
+       rval = read(fd, ((char *)&rc->netint) + rc->size_header_read,
+                       SIZEOF(rc->netint) - rc->size_header_read);
+       if (rval == -1) {
+           if (errmsg)
+               *errmsg = newvstrallocf(*errmsg, _("recv error: %s"),
+                                       strerror(errno));
+           auth_debug(1, _("tcpm_recv_token: A return(-1)\n"));
+           return(-1);
+       } else if (rval == 0) {
+           *size = 0;
+           *handle = H_EOF;
+           *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
+           auth_debug(1, _("tcpm_recv_token: A return(0)\n"));
+           return(0);
+       } else if (rval < (ssize_t)SIZEOF(rc->netint) - rc->size_header_read) {
+           rc->size_header_read += rval;
+           return(-2);
+       }
+       rc->size_header_read += rval;
+        amfree(rc->buffer);
+       *size = (ssize_t)ntohl(rc->netint[0]);
+       *handle = (int)ntohl(rc->netint[1]);
+        rc->buffer = NULL;
+       rc->size_buffer_read = 0;
+
+       /* amanda protocol packet can be above NETWORK_BLOCK_BYTES */
+       if (*size > 128*NETWORK_BLOCK_BYTES || *size < 0) {
+           if (isprint((int)(*size        ) & 0xFF) &&
+               isprint((int)(*size   >> 8 ) & 0xFF) &&
+               isprint((int)(*size   >> 16) & 0xFF) &&
+               isprint((int)(*size   >> 24) & 0xFF) &&
+               isprint((*handle      ) & 0xFF) &&
+               isprint((*handle >> 8 ) & 0xFF) &&
+               isprint((*handle >> 16) & 0xFF) &&
+               isprint((*handle >> 24) & 0xFF)) {
+               char s[201];
+               char *s1;
+               int i;
+               s[0] = ((int)(*size)  >> 24) & 0xFF;
+               s[1] = ((int)(*size)  >> 16) & 0xFF;
+               s[2] = ((int)(*size)  >>  8) & 0xFF;
+               s[3] = ((int)(*size)       ) & 0xFF;
+               s[4] = (*handle >> 24) & 0xFF;
+               s[5] = (*handle >> 16) & 0xFF;
+               s[6] = (*handle >> 8 ) & 0xFF;
+               s[7] = (*handle      ) & 0xFF;
+               i = 8; s[i] = ' ';
+               while(i<200 && isprint((int)s[i]) && s[i] != '\n') {
+                   switch(net_read(fd, &s[i], 1, 0)) {
+                   case -1: s[i] = '\0'; break;
+                   case  0: s[i] = '\0'; break;
+                   default:
                         dbprintf(_("read: %c\n"), s[i]); i++; s[i]=' ';
                         break;
+                   }
                }
+               s[i] = '\0';
+               s1 = quote_string(s);
+               *errmsg = newvstrallocf(*errmsg,
+                               _("tcpm_recv_token: invalid size: %s"), s1);
+               dbprintf(_("tcpm_recv_token: invalid size %s\n"), s1);
+               amfree(s1);
+           } else {
+               *errmsg = newvstrallocf(*errmsg,
+                                       _("tcpm_recv_token: invalid size"));
+               dbprintf(_("tcpm_recv_token: invalid size %zd\n"), *size);
            }
-           s[i] = '\0';
-           *errmsg = newvstrallocf(*errmsg, _("tcpm_recv_token: invalid size: %s"), s);
-           dbprintf(_("tcpm_recv_token: invalid size %s\n"), s);
-       } else {
-           *errmsg = newvstrallocf(*errmsg, _("tcpm_recv_token: invalid size"));
-           dbprintf(_("tcpm_recv_token: invalid size %zd\n"), *size);
+           *size = -1;
+           return -1;
        }
-       *size = -1;
-       return -1;
-    }
-    amfree(*buf);
-    *buf = alloc((size_t)*size);
+        rc->buffer = alloc((size_t)*size);
 
-    if(*size == 0) {
-       auth_debug(1, _("tcpm_recv_token: read EOF from %d\n"), *handle);
-       *errmsg = newvstrallocf(*errmsg, _("EOF"));
-       return 0;
+       if (*size == 0) {
+           auth_debug(1, _("tcpm_recv_token: read EOF from %d\n"), *handle);
+           *errmsg = newvstrallocf(*errmsg, _("EOF"));
+           rc->size_header_read = 0;
+           return 0;
+       }
     }
-    switch (net_read(fd, *buf, (size_t)*size, timeout)) {
-    case -1:
+
+    *size = (ssize_t)ntohl(rc->netint[0]);
+    *handle = (int)ntohl(rc->netint[1]);
+
+    rval = read(fd, rc->buffer + rc->size_buffer_read,
+                   (size_t)*size - rc->size_buffer_read);
+    if (rval == -1) {
        if (errmsg)
-           *errmsg = newvstrallocf(*errmsg, _("recv error: %s"), strerror(errno));
+           *errmsg = newvstrallocf(*errmsg, _("recv error: %s"),
+                                   strerror(errno));
        auth_debug(1, _("tcpm_recv_token: B return(-1)\n"));
        return (-1);
-    case 0:
+    } else if (rval == 0) {
        *size = 0;
        *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
        auth_debug(1, _("tcpm_recv_token: B return(0)\n"));
        return (0);
-    default:
-       break;
+    } else if (rval < (ssize_t)*size - rc->size_buffer_read) {
+       rc->size_buffer_read += rval;
+       return (-2);
     }
+    rc->size_buffer_read += rval;
+    amfree(*buf);
+    *buf = rc->buffer;
+    rc->size_header_read = 0;
+    rc->size_buffer_read = 0;
+    rc->buffer = NULL;
 
     auth_debug(1, _("tcpm_recv_token: read %zd bytes from %d\n"), *size, *handle);
 
@@ -654,7 +681,7 @@ tcpma_stream_client(
        return (NULL);
     }
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->handle = id;
     rs->ev_read = NULL;
@@ -688,7 +715,7 @@ tcpma_stream_server(
 
     assert(rh != NULL);
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->closed_by_me = 0;
     rs->closed_by_network = 0;
@@ -740,6 +767,7 @@ tcpma_stream_close(
     security_stream_read_cancel(&rs->secstr);
     if(rs->closed_by_network == 0)
        sec_tcp_conn_put(rs->rc);
+    amfree(((security_stream_t *)rs)->error);
     amfree(rs);
 }
 
@@ -756,7 +784,7 @@ tcp1_stream_server(
 
     assert(rh != NULL);
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->closed_by_me = 0;
     rs->closed_by_network = 0;
@@ -828,7 +856,7 @@ tcp1_stream_client(
 
     assert(rh != NULL);
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->handle = id;
     rs->ev_read = NULL;
@@ -865,9 +893,16 @@ tcp_stream_write(
     size_t     size)
 {
     struct sec_stream *rs = s;
+    time_t             logtime;
 
     assert(rs != NULL);
 
+    logtime = time(NULL);
+    if (rs && rs->rc && logtime > rs->rc->logstamp + 10) {
+       g_debug("tcp_stream_write: data is still flowing");
+       rs->rc->logstamp = logtime;
+    }
+
     if (full_write(rs->fd, buf, size) < size) {
         security_stream_seterror(&rs->secstr,
             _("write error on stream %d: %s"), rs->port, strerror(errno));
@@ -1379,7 +1414,7 @@ udp_netfd_read_callback(
        return;
     }
 
-    rh = alloc(SIZEOF(*rh));
+    rh = g_new0(struct sec_handle, 1);
     rh->proto_handle=NULL;
     rh->udp = udp;
     rh->rc = NULL;
@@ -1460,7 +1495,7 @@ sec_tcp_conn_get(
     /*
      * We can't be creating a new handle if we are the client
      */
-    rc = alloc(SIZEOF(*rc));
+    rc = g_new0(struct tcp_conn, 1);
     rc->read = rc->write = -1;
     rc->driver = NULL;
     rc->pid = -1;
@@ -1673,8 +1708,15 @@ stream_read_callback(
     void *     arg)
 {
     struct sec_stream *rs = arg;
+    time_t             logtime;
+
     assert(rs != NULL);
 
+    logtime = time(NULL);
+    if (rs && rs->rc && logtime > rs->rc->logstamp + 10) {
+       g_debug("stream_read_callback: data is still flowing");
+       rs->rc->logstamp = logtime;
+    }
     auth_debug(1, _("sec: stream_read_callback: handle %d\n"), rs->handle);
 
     /*
@@ -1734,9 +1776,14 @@ sec_tcp_conn_read_callback(
 
     /* Read the data off the wire.  If we get errors, shut down. */
     rval = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg, &rc->pkt,
-                               &rc->pktlen, 60);
+                               &rc->pktlen);
     auth_debug(1, _("sec: conn_read_callback: tcpm_recv_token returned %zd\n"),
                   rval);
+
+    if (rval == -2) {
+       return;
+    }
+
     if (rval < 0 || rc->handle == H_EOF) {
        rc->pktlen = rval;
        rc->handle = H_EOF;
@@ -1784,7 +1831,7 @@ sec_tcp_conn_read_callback(
        return;
     }
 
-    rh = alloc(SIZEOF(*rh));
+    rh = g_new0(struct sec_handle, 1);
     security_handleinit(&rh->sech, rc->driver);
     rh->hostname = stralloc(rc->hostname);
     rh->ev_timeout = NULL;
@@ -2572,7 +2619,7 @@ check_name_give_sockaddr(
        }
     }
 
-    dbprintf(_("%s doesn't resolve to %s"),
+    g_debug("%s doesn't resolve to %s",
            hostname, str_sockaddr((sockaddr_union *)addr));
     *errstr = newvstrallocf(*errstr,
                           "%s doesn't resolve to %s",
@@ -2612,3 +2659,20 @@ find_port_for_service(
 
     return port;
 }
+
+char *
+sec_get_authenticated_peer_name_localhost(
+    security_handle_t *hdl G_GNUC_UNUSED)
+{
+    return "localhost";
+}
+
+char *
+sec_get_authenticated_peer_name_hostname(
+    security_handle_t *hdl)
+{
+    char *hostname = ((struct sec_handle *)hdl)->hostname;
+    if (!hostname)
+       hostname = "";
+    return hostname;
+}