/* * lib/krb5/krb/compat_recv.c * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include 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); #ifdef KRB5_KRB4_COMPAT KTEXT v4_ticket; /* storage for client's ticket */ #endif if ((retval = krb5_net_read(fd, vers.vers, 4)) != 4) return((retval < 0) ? errno : ECONNABORTED); #ifdef KRB5_KRB4_COMPAT 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; } } #endif /* * 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 */ #ifdef KRB5_KRB4_COMPAT 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); } #endif