diff options
Diffstat (limited to 'eBones/krb/recvauth.c')
-rw-r--r-- | eBones/krb/recvauth.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/eBones/krb/recvauth.c b/eBones/krb/recvauth.c new file mode 100644 index 0000000..fe26814 --- /dev/null +++ b/eBones/krb/recvauth.c @@ -0,0 +1,286 @@ +/* + * Copyright 1987, 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * from: recvauth.c,v 4.4 90/03/10 19:03:08 jon Exp $"; + * $Id: recvauth.c,v 1.2 1994/07/19 19:26:18 g89r4222 Exp $ + */ + +#ifndef lint +static char rcsid[] = +"$Id: recvauth.c,v 1.2 1994/07/19 19:26:18 g89r4222 Exp $"; +#endif lint + +#include <krb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <syslog.h> +#include <errno.h> +#include <stdio.h> +#include <strings.h> + + +#define KRB_SENDAUTH_VERS "AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN + chars */ + +/* + * If the protocol changes, you will need to change the version string + * and make appropriate changes in krb_sendauth.c + * be sure to support old versions of krb_sendauth! + */ + +extern int errno; + +/* + * krb_recvauth() reads (and optionally responds to) a message sent + * using krb_sendauth(). The "options" argument is a bit-field of + * selected options (see "sendauth.c" for options description). + * The only option relevant to krb_recvauth() is KOPT_DO_MUTUAL + * (mutual authentication requested). The "fd" argument supplies + * a file descriptor to read from (and write to, if mutual authenti- + * cation is requested). + * + * Part of the received message will be a Kerberos ticket sent by the + * client; this is read into the "ticket" argument. The "service" and + * "instance" arguments supply the server's Kerberos name. If the + * "instance" argument is the string "*", it is treated as a wild card + * and filled in during the krb_rd_req() call (see read_service_key()). + * + * The "faddr" and "laddr" give the sending (client) and receiving + * (local server) network addresses. ("laddr" may be left NULL unless + * mutual authentication is requested, in which case it must be set.) + * + * The authentication information extracted from the message is returned + * in "kdata". The "filename" argument indicates the file where the + * server's key can be found. (It is passed on to krb_rd_req().) If + * left null, the default "/etc/srvtab" will be used. + * + * If mutual authentication is requested, the session key schedule must + * be computed in order to reply; this schedule is returned in the + * "schedule" argument. A string containing the application version + * number from the received message is returned in "version", which + * should be large enough to hold a KRB_SENDAUTH_VLEN-character string. + * + * See krb_sendauth() for the format of the received client message. + * + * This routine supports another client format, for backward + * compatibility, consisting of: + * + * Size Variable Field + * ---- -------- ----- + * + * string tmp_buf, tkt_len length of ticket, in + * ascii + * + * char ' ' (space char) separator + * + * tkt_len ticket->dat the ticket + * + * This old-style version does not support mutual authentication. + * + * krb_recvauth() first reads the protocol version string from the + * given file descriptor. If it doesn't match the current protocol + * version (KRB_SENDAUTH_VERS), the old-style format is assumed. In + * that case, the string of characters up to the first space is read + * and interpreted as the ticket length, then the ticket is read. + * + * If the first string did match KRB_SENDAUTH_VERS, krb_recvauth() + * next reads the application protocol version string. Then the + * ticket length and ticket itself are read. + * + * The ticket is decrypted and checked by the call to krb_rd_req(). + * If no mutual authentication is required, the result of the + * krb_rd_req() call is retured by this routine. If mutual authenti- + * cation is required, a message in the following format is returned + * on "fd": + * + * Size Variable Field + * ---- -------- ----- + * + * 4 bytes tkt_len length of ticket or -1 + * if error occurred + * + * priv_len tmp_buf "private" message created + * by krb_mk_priv() which + * contains the incremented + * checksum sent by the client + * encrypted in the session + * key. (This field is not + * present in case of error.) + * + * If all goes well, KSUCCESS is returned; otherwise KFAILURE or some + * other error code is returned. + */ + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif /* max */ + +int +krb_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 protocol version number */ + if (krb_net_read(fd, krb_vers, KRB_SENDAUTH_VLEN) != + KRB_SENDAUTH_VLEN) + return(errno); + krb_vers[KRB_SENDAUTH_VLEN] = '\0'; + + /* check version string */ + if (strcmp(krb_vers,KRB_SENDAUTH_VERS)) { + /* Assume the old version of sendkerberosdata: send ascii + length, ' ', and ticket. */ + if (options & KOPT_DO_MUTUAL) + return(KFAILURE); /* XXX can't do old style with mutual auth */ + old_vers = 1; + + /* copy what we have read into tmp_buf */ + (void) bcopy(krb_vers, (char *) tmp_buf, KRB_SENDAUTH_VLEN); + + /* search for space, and make it a null */ + for (i = 0; i < KRB_SENDAUTH_VLEN; i++) + if (tmp_buf[i]== ' ') { + tmp_buf[i] = '\0'; + /* point cp to the beginning of the real ticket */ + cp = (char *) &tmp_buf[i+1]; + break; + } + + if (i == KRB_SENDAUTH_VLEN) + /* didn't find the space, keep reading to find it */ + for (; i<20; i++) { + if (read(fd, (char *)&tmp_buf[i], 1) != 1) { + return(KFAILURE); + } + if (tmp_buf[i] == ' ') { + tmp_buf[i] = '\0'; + /* point cp to the beginning of the real ticket */ + cp = (char *) &tmp_buf[i+1]; + break; + } + } + + tkt_len = (long) atoi((char *) tmp_buf); + + /* sanity check the length */ + if ((i==20)||(tkt_len<=0)||(tkt_len>MAX_KTXT_LEN)) + return(KFAILURE); + + if (i < KRB_SENDAUTH_VLEN) { + /* since we already got the space, and part of the ticket, + we read fewer bytes to get the rest of the ticket */ + if (krb_net_read(fd, (char *)(tmp_buf+KRB_SENDAUTH_VLEN), + (int) (tkt_len - KRB_SENDAUTH_VLEN + 1 + i)) + != (int)(tkt_len - KRB_SENDAUTH_VLEN + 1 + i)) + return(errno); + } else { + if (krb_net_read(fd, (char *)(tmp_buf+i), (int)tkt_len) != + (int) tkt_len) + return(errno); + } + ticket->length = tkt_len; + /* copy the ticket into the struct */ + (void) bcopy(cp, (char *) ticket->dat, ticket->length); + + } else { + /* 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 + 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); +} |