Imported Upstream version 3.2.0
[debian/amanda] / common-src / krb5-security.c
index 6c6572b619abcb557e532b64eafb7db5ff45279e..c3075fa9bc2456d0aafd8afec557e4138f42d337 100644 (file)
 #include "util.h"
 #include "event.h"
 #include "packet.h"
-#include "queue.h"
 #include "security.h"
 #include "security-util.h"
 #include "stream.h"
-#include "version.h"
 #include "sockaddr-util.h"
 
 #ifdef KRB5_HEIMDAL_INCLUDES
  */
 #define GSS_TIMEOUT                     30
 
-/*
- * The largest buffer we can send/receive.
- */
-#define AMANDA_MAX_TOK_SIZE             (MAX_TAPE_BLOCK_BYTES * 4)
-
 /*
  * This is the tcp stream buffer size
  */
-#define KRB5_STREAM_BUFSIZE     (MAX_TAPE_BLOCK_BYTES * 2)
+#define KRB5_STREAM_BUFSIZE     (32768 * 2)
 
 /*
  * This is the max number of outgoing connections we can have at once.
@@ -173,6 +166,9 @@ static int k5_encrypt(void *cookie, void *buf, ssize_t buflen,
 static int k5_decrypt(void *cookie, void *buf, ssize_t buflen,
                      void **encbuf, ssize_t *encbuflen);
 
+static ssize_t krb5_tcpm_recv_token(struct tcp_conn *rc, int fd, int *handle,
+                                   char **errmsg, char **buf, ssize_t *size,
+                                   int timeout);
 /*
  * This is our interface to the outside world.
  */
@@ -180,6 +176,7 @@ const security_driver_t krb5_security_driver = {
     "KRB5",
     krb5_connect,
     krb5_accept,
+    sec_get_authenticated_peer_name_hostname,
     sec_close,
     stream_sendpkt,
     stream_recvpkt,
@@ -523,7 +520,8 @@ gss_client(
        if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED)
            break;
 
-        rvalue = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg,
+        rvalue = krb5_tcpm_recv_token(rc, rc->read, &rc->handle,
+                                &rc->errmsg,
                                 (void *)&recv_tok.value,
                                 (ssize_t *)&recv_tok.length, 60);
        if (rvalue <= 0) {
@@ -556,7 +554,6 @@ gss_server(
     gss_name_t gss_name;
     gss_cred_id_t gss_creds;
     char *p, *realm, *msg;
-    uid_t euid;
     int rval = -1;
     int rvalue;
     char errbuf[256];
@@ -571,16 +568,9 @@ gss_server(
      * out of the default keytab.  We also need to be root in
      * gss_accept_context() thanks to the replay cache code.
      */
-    euid = geteuid();
-    if (getuid() != 0) {
-       g_snprintf(errbuf, SIZEOF(errbuf),
-           _("real uid is %ld, needs to be 0 to read krb5 host key"),
-           (long)getuid());
-       goto out;
-    }
     if (!set_root_privs(0)) {
        g_snprintf(errbuf, SIZEOF(errbuf),
-           _("can't seteuid to uid 0: %s"), strerror(errno));
+           _("can't take root privileges to read krb5 host key: %s"), strerror(errno));
        goto out;
     }
 
@@ -619,7 +609,8 @@ gss_server(
 
     for (recv_tok.length = 0;;) {
        recv_tok.value = NULL;
-        rvalue = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg,
+        rvalue = krb5_tcpm_recv_token(rc, rc->read, &rc->handle,
+                                &rc->errmsg,
                                 /* (void *) is to avoid type-punning warning */
                                 (char **)(void *)&recv_tok.value,
                                 (ssize_t *)&recv_tok.length, 60);
@@ -1202,3 +1193,122 @@ common_exit:
     return(result);
 #endif /* AMANDA_PRINCIPAL */
 }
+
+/*
+ *  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
+ *  return size     :   *handle = handle && *size = size for data read
+ */
+
+static ssize_t
+krb5_tcpm_recv_token(
+    struct tcp_conn    *rc,
+    int                fd,
+    int *      handle,
+    char **    errmsg,
+    char **    buf,
+    ssize_t *  size,
+    int                timeout)
+{
+    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, _("krb5_tcpm_recv_token: A return(-1)\n"));
+       return (-1);
+    case 0:
+       *size = 0;
+       *handle = H_EOF;
+       *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
+       auth_debug(1, _("krb5_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:
+                        dbprintf(_("read: %c\n"), s[i]); i++; s[i]=' ';
+                        break;
+               }
+           }
+           s[i] = '\0';
+           *errmsg = newvstrallocf(*errmsg, _("krb5_tcpm_recv_token: invalid size: %s"), s);
+           dbprintf(_("krb5_tcpm_recv_token: invalid size %s\n"), s);
+       } else {
+           *errmsg = newvstrallocf(*errmsg, _("krb5_tcpm_recv_token: invalid size"));
+           dbprintf(_("krb5_tcpm_recv_token: invalid size %zd\n"), *size);
+       }
+       *size = -1;
+       return -1;
+    }
+    amfree(*buf);
+    *buf = alloc((size_t)*size);
+
+    if(*size == 0) {
+       auth_debug(1, _("krb5_tcpm_recv_token: read EOF from %d\n"), *handle);
+       *errmsg = newvstrallocf(*errmsg, _("EOF"));
+       return 0;
+    }
+    switch (net_read(fd, *buf, (size_t)*size, timeout)) {
+    case -1:
+       if (errmsg)
+           *errmsg = newvstrallocf(*errmsg, _("recv error: %s"), strerror(errno));
+       auth_debug(1, _("krb5_tcpm_recv_token: B return(-1)\n"));
+       return (-1);
+    case 0:
+       *size = 0;
+       *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
+       auth_debug(1, _("krb5_tcpm_recv_token: B return(0)\n"));
+       return (0);
+    default:
+       break;
+    }
+
+    auth_debug(1, _("krb5_tcpm_recv_token: read %zd bytes from %d\n"), *size, *handle);
+
+    if (*size > 0 && rc->driver->data_decrypt != NULL) {
+       void *decbuf;
+       ssize_t decsize;
+       rc->driver->data_decrypt(rc, *buf, *size, &decbuf, &decsize);
+       if (*buf != (char *)decbuf) {
+           amfree(*buf);
+           *buf = (char *)decbuf;
+       }
+       *size = decsize;
+    }
+
+    return((*size));
+}
+