Added function which does V4/V5 compatibility for sendauth/recvauth
authorTheodore Tso <tytso@mit.edu>
Wed, 15 Dec 1993 18:11:18 +0000 (18:11 +0000)
committerTheodore Tso <tytso@mit.edu>
Wed, 15 Dec 1993 18:11:18 +0000 (18:11 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@3181 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/krb/Imakefile
src/lib/krb5/krb/compat_recv.c [new file with mode: 0644]

index 8397916570b78bb1a25391582c7de83cf4d97b6c..c649daa01714ae271d294f5b57401c5f2242ae60 100644 (file)
@@ -29,6 +29,7 @@ OBJS= addr_comp.o     \
        addr_srch.o     \
        bld_pr_ext.o    \
        bld_princ.o     \
+       compat_recv.o   \
        conv_princ.o    \
        copy_addrs.o    \
        copy_auth.o     \
@@ -87,6 +88,7 @@ SRCS= $(SRCDIR)addr_comp.c    \
        $(SRCDIR)addr_srch.c    \
        $(SRCDIR)bld_pr_ext.c   \
        $(SRCDIR)bld_princ.c    \
+       $(SRCDIR)compat_recv.c  \
        $(SRCDIR)conv_princ.c   \
        $(SRCDIR)copy_addrs.c   \
        $(SRCDIR)copy_auth.c    \
diff --git a/src/lib/krb5/krb/compat_recv.c b/src/lib/krb5/krb/compat_recv.c
new file mode 100644 (file)
index 0000000..a6c6bc8
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1993 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * convenience sendauth/recvauth functions, with compatibility with V4
+ * recvauth.
+ *
+ * NOTE: linking in this function will pull in V4 kerberos routines.
+ *
+ * WARNING: In the V4-style arguments, the ticket and kdata arguments
+ * have different types than the V4 recvauth; in V4, they were KTEXT
+ * and AUTH_DAT *, respectively.  Here, they are KTEXT * and AUTH_DAT **
+ * and they are allocated by recvauth if and only if we end up talking
+ * to a V4 sendauth.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_recvauth_c [] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/krb5.h>
+#include <krb5/osconf.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb.h>
+#include <com_err.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+static int krb_v4_recvauth();
+
+#define        KRB_V4_SENDAUTH_VERS    "AUTHV0.1" /* MUST be 8 chars long */
+#define KRB_V5_SENDAUTH_VERS   "KRB5_SENDAUTH_V1.0"
+
+#define KRB5_RECVAUTH_V4       4
+#define KRB5_RECVAUTH_V5       5
+
+krb5_error_code
+krb5_compat_recvauth(/* IN */
+                    fdp, appl_version, server, sender_addr, fetch_from,
+                    keyproc, keyprocarg, rc_type, flags,
+                    v4_options, v4_service, v4_instance, v4_faddr, v4_laddr,
+                    v4_filename, 
+                    /* OUT */
+                    auth_sys, seq_number, client, ticket, authent,
+                    v4_kdata, v4_schedule, v4_version)
+       krb5_pointer    fdp;
+       char    *appl_version;
+       krb5_principal  server;
+       krb5_address    *sender_addr;
+       krb5_pointer    fetch_from;
+       krb5_int32      *seq_number;
+       char            *rc_type;
+       krb5_int32      flags;
+       krb5_rdreq_key_proc keyproc;
+       krb5_pointer keyprocarg;
+       krb5_principal  *client;
+       krb5_ticket     **ticket;
+       krb5_authenticator      **authent;
+       krb5_int32      *auth_sys;
+       /*
+        * Version 4 arguments
+        */
+       krb5_int32 v4_options;   /* bit-pattern of options */
+       char *v4_service;        /* service expected */
+       char *v4_instance;       /* inst expected (may be filled in) */
+       struct sockaddr_in *v4_faddr; /* foreign address */
+       struct sockaddr_in *v4_laddr; /* local address */
+       AUTH_DAT **v4_kdata;     /* kerberos data (returned) */
+       char *v4_filename;       /* name of file with service keys */
+       Key_schedule v4_schedule; /* key schedule (return) */
+       char *v4_version;                /* version string (filled in) */
+{
+       union verslen {
+               krb5_int32      len;
+               char            vers[4];
+       } vers;
+       char    *buf;
+       int     len, length;
+       krb5_int32      retval;
+       int             fd = *( (int *) fdp);
+       KTEXT           v4_ticket;       /* storage for client's ticket */
+               
+       if ((retval = krb5_net_read(fd, vers.vers, 4)) != 4)
+               return((retval < 0) ? errno : ECONNABORTED);
+
+       if (!strncmp(vers.vers, KRB_V4_SENDAUTH_VERS, 4)) {
+               /*
+                * We must be talking to a V4 sendauth; read in the
+                * rest of the version string and make sure.
+                */
+               if ((retval = krb5_net_read(fd, vers.vers, 4)) != 4)
+                       return((retval < 0) ? errno : ECONNABORTED);
+               
+               if (strncmp(vers.vers, KRB_V4_SENDAUTH_VERS+4, 4))
+                       return KRB5_SENDAUTH_BADAUTHVERS;
+
+               *auth_sys = KRB5_RECVAUTH_V4;
+
+               *v4_kdata = (AUTH_DAT *) malloc( sizeof(AUTH_DAT) );
+               v4_ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
+
+               retval = krb_v4_recvauth(v4_options, fd, v4_ticket,
+                                        v4_service, v4_instance, v4_faddr,
+                                        v4_laddr, *v4_kdata, v4_filename,
+                                        v4_schedule, v4_version);
+               krb5_xfree(v4_ticket);
+               /*
+                * XXX error code translation?
+                */
+               switch (retval) {
+               case RD_AP_OK:
+                   return 0;
+               case RD_AP_TIME:
+                   return KRB5KRB_AP_ERR_SKEW;
+               case RD_AP_EXP:
+                   return KRB5KRB_AP_ERR_TKT_EXPIRED;
+               case RD_AP_NYV:
+                   return KRB5KRB_AP_ERR_TKT_NYV;
+               case RD_AP_NOT_US:
+                   return KRB5KRB_AP_ERR_NOT_US;
+               case RD_AP_UNDEC:
+                   return KRB5KRB_AP_ERR_BAD_INTEGRITY;
+               case RD_AP_REPEAT:
+                   return KRB5KRB_AP_ERR_REPEAT;
+               case RD_AP_MSG_TYPE:
+                   return KRB5KRB_AP_ERR_MSG_TYPE;
+               case RD_AP_MODIFIED:
+                   return KRB5KRB_AP_ERR_MODIFIED;
+               case RD_AP_ORDER:
+                   return KRB5KRB_AP_ERR_BADORDER;
+               case RD_AP_BADD:
+                   return KRB5KRB_AP_ERR_BADADDR;
+               default:
+                   return KRB5_SENDAUTH_BADRESPONSE;
+               }
+       }
+
+       /*
+        * Assume that we're talking to a V5 recvauth; read in the
+        * the version string, and make sure it matches.
+        */
+       
+       len = ntohl(vers.len);
+
+       if (len < 0 || len > 255)
+               return KRB5_SENDAUTH_BADAUTHVERS;
+
+       buf = malloc(len);
+       if (!buf)
+               return ENOMEM;
+       
+       length = krb5_net_read(fd, buf, len);
+       if (len != length) {
+               krb5_xfree(buf);
+               if (len < 0)
+                       return errno;
+               else
+                       return ECONNABORTED;
+       }
+
+       if (strcmp(buf, KRB_V5_SENDAUTH_VERS)) {
+               krb5_xfree(buf);
+               return KRB5_SENDAUTH_BADAUTHVERS;
+       }
+       krb5_xfree(buf);
+
+       *auth_sys = KRB5_RECVAUTH_V5;
+       
+       retval = krb5_recvauth(fdp, appl_version, server, sender_addr,
+                              fetch_from,
+                              keyproc, keyprocarg, rc_type,
+                              flags | KRB5_RECVAUTH_SKIP_VERSION,
+                              seq_number, client, ticket, authent);
+
+       return retval;
+}
+
+
+#ifndef max
+#define        max(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* max */
+
+static int
+krb_v4_recvauth(options, fd, ticket, service, instance, faddr, laddr, kdata,
+               filename, schedule, version)
+long options;                   /* bit-pattern of options */
+int fd;                                 /* file descr. to read from */
+KTEXT ticket;                   /* storage for client's ticket */
+char *service;                  /* service expected */
+char *instance;                         /* inst expected (may be filled in) */
+struct sockaddr_in *faddr;      /* address of foreign host on fd */
+struct sockaddr_in *laddr;      /* local address */
+AUTH_DAT *kdata;                /* kerberos data (returned) */
+char *filename;                         /* name of file with service keys */
+Key_schedule schedule;          /* key schedule (return) */
+char *version;                  /* version string (filled in) */
+{
+    int i, cc, old_vers = 0;
+    char krb_vers[KRB_SENDAUTH_VLEN + 1]; /* + 1 for the null terminator */
+    char *cp;
+    int rem;
+    long tkt_len, priv_len;
+    u_long cksum;
+    u_char tmp_buf[MAX_KTXT_LEN+max(KRB_SENDAUTH_VLEN+1,21)];
+
+    /* read the application version string */
+    if (krb_net_read(fd, version, KRB_SENDAUTH_VLEN) !=
+       KRB_SENDAUTH_VLEN)
+       return(errno);
+    version[KRB_SENDAUTH_VLEN] = '\0';
+
+    /* get the length of the ticket */
+    if (krb_net_read(fd, (char *)&tkt_len, sizeof(tkt_len)) !=
+       sizeof(tkt_len))
+       return(errno);
+    
+    /* sanity check */
+    ticket->length = ntohl((unsigned long)tkt_len);
+    if ((ticket->length <= 0) || (ticket->length > MAX_KTXT_LEN)) {
+       if (options & KOPT_DO_MUTUAL) {
+           rem = KFAILURE;
+           goto mutual_fail;
+       } else
+           return(KFAILURE); /* XXX there may still be junk on the fd? */
+    }          
+
+    /* read the ticket */
+    if (krb_net_read(fd, (char *) ticket->dat, ticket->length)
+       != ticket->length)
+       return(errno);
+
+    /*
+     * now have the ticket.  decrypt it to get the authenticated
+     * data.
+     */
+    rem = krb_rd_req(ticket,service,instance,faddr->sin_addr.s_addr,
+                    kdata,filename);
+
+    if (old_vers) return(rem);  /* XXX can't do mutual with old client */
+
+    /* if we are doing mutual auth, compose a response */
+    if (options & KOPT_DO_MUTUAL) {
+       if (rem != KSUCCESS)
+           /* the krb_rd_req failed */
+           goto mutual_fail;
+
+       /* add one to the (formerly) sealed checksum, and re-seal it
+          for return to the client */
+       cksum = kdata->checksum + 1;
+       cksum = htonl(cksum);
+#ifndef NOENCRYPTION
+       key_sched(kdata->session,schedule);
+#endif /* !NOENCRYPTION */
+       priv_len = krb_mk_priv((unsigned char *)&cksum,
+                              tmp_buf,
+                              (unsigned long) sizeof(cksum),
+                              schedule,
+                              kdata->session,
+                              laddr,
+                              faddr);
+       if (priv_len < 0) {
+           /* re-sealing failed; notify the client */
+           rem = KFAILURE;      /* XXX */
+mutual_fail:
+           priv_len = -1;
+           tkt_len = htonl((unsigned long) priv_len);
+           /* a length of -1 is interpreted as an authentication
+              failure by the client */
+           if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
+               != sizeof(tkt_len))
+               return(cc);
+           return(rem);
+       } else {
+           /* re-sealing succeeded, send the private message */
+           tkt_len = htonl((unsigned long)priv_len);
+           if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
+                != sizeof(tkt_len))
+               return(cc);
+           if ((cc = krb_net_write(fd, (char *)tmp_buf, (int) priv_len))
+               != (int) priv_len)
+               return(cc);
+       }
+    }
+    return(rem);
+}
+
+               
+
+       
+
+               
+               
+               
+               
+