mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-03 08:22:44 +00:00
260 lines
7.7 KiB
C
260 lines
7.7 KiB
C
/*
|
|
* Copyright 1987, 1988 by the Massachusetts Institute of Technology.
|
|
* For copying and distribution information, please see the file
|
|
* <Copyright.MIT>.
|
|
*
|
|
* from: sendauth.c,v 4.6 90/03/10 23:18:28 jon Exp $
|
|
* $Id$
|
|
*/
|
|
|
|
#if 0
|
|
#ifndef lint
|
|
static char rcsid[] =
|
|
"$Id$";
|
|
#endif lint
|
|
#endif
|
|
|
|
#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_recvauth.c
|
|
*/
|
|
|
|
extern int errno;
|
|
|
|
extern char *krb_get_phost();
|
|
|
|
/*
|
|
* This file contains two routines: krb_sendauth() and krb_sendsrv().
|
|
*
|
|
* krb_sendauth() transmits a ticket over a file descriptor for a
|
|
* desired service, instance, and realm, doing mutual authentication
|
|
* with the server if desired.
|
|
*
|
|
* krb_sendsvc() sends a service name to a remote knetd server.
|
|
*/
|
|
|
|
/*
|
|
* The first argument to krb_sendauth() contains a bitfield of
|
|
* options (the options are defined in "krb.h"):
|
|
*
|
|
* KOPT_DONT_CANON Don't canonicalize instance as a hostname.
|
|
* (If this option is not chosen, krb_get_phost()
|
|
* is called to canonicalize it.)
|
|
*
|
|
* KOPT_DONT_MK_REQ Don't request server ticket from Kerberos.
|
|
* A ticket must be supplied in the "ticket"
|
|
* argument.
|
|
* (If this option is not chosen, and there
|
|
* is no ticket for the given server in the
|
|
* ticket cache, one will be fetched using
|
|
* krb_mk_req() and returned in "ticket".)
|
|
*
|
|
* KOPT_DO_MUTUAL Do mutual authentication, requiring that the
|
|
* receiving server return the checksum+1 encrypted
|
|
* in the session key. The mutual authentication
|
|
* is done using krb_mk_priv() on the other side
|
|
* (see "recvauth.c") and krb_rd_priv() on this
|
|
* side.
|
|
*
|
|
* The "fd" argument is a file descriptor to write to the remote
|
|
* server on. The "ticket" argument is used to store the new ticket
|
|
* from the krb_mk_req() call. If the KOPT_DONT_MK_REQ options is
|
|
* chosen, the ticket must be supplied in the "ticket" argument.
|
|
* The "service", "inst", and "realm" arguments identify the ticket.
|
|
* If "realm" is null, the local realm is used.
|
|
*
|
|
* The following arguments are only needed if the KOPT_DO_MUTUAL option
|
|
* is chosen:
|
|
*
|
|
* The "checksum" argument is a number that the server will add 1 to
|
|
* to authenticate itself back to the client; the "msg_data" argument
|
|
* holds the returned mutual-authentication message from the server
|
|
* (i.e., the checksum+1); the "cred" structure is used to hold the
|
|
* session key of the server, extracted from the ticket file, for use
|
|
* in decrypting the mutual authentication message from the server;
|
|
* and "schedule" holds the key schedule for that decryption. The
|
|
* the local and server addresses are given in "laddr" and "faddr".
|
|
*
|
|
* The application protocol version number (of up to KRB_SENDAUTH_VLEN
|
|
* characters) is passed in "version".
|
|
*
|
|
* If all goes well, KSUCCESS is returned, otherwise some error code.
|
|
*
|
|
* The format of the message sent to the server is:
|
|
*
|
|
* Size Variable Field
|
|
* ---- -------- -----
|
|
*
|
|
* KRB_SENDAUTH_VLEN KRB_SENDAUTH_VER sendauth protocol
|
|
* bytes version number
|
|
*
|
|
* KRB_SENDAUTH_VLEN version application protocol
|
|
* bytes version number
|
|
*
|
|
* 4 bytes ticket->length length of ticket
|
|
*
|
|
* ticket->length ticket->dat ticket itself
|
|
*/
|
|
|
|
/*
|
|
* XXX: Note that krb_rd_priv() is coded in such a way that
|
|
* "msg_data->app_data" will be pointing into "priv_buf", which
|
|
* will disappear when krb_sendauth() returns.
|
|
*/
|
|
|
|
int
|
|
krb_sendauth(options, fd, ticket, service, inst, realm, checksum,
|
|
msg_data, cred, schedule, laddr, faddr, version)
|
|
long options; /* bit-pattern of options */
|
|
int fd; /* file descriptor to write onto */
|
|
KTEXT ticket; /* where to put ticket (return); or
|
|
* supplied in case of KOPT_DONT_MK_REQ */
|
|
char *service, *inst, *realm; /* service name, instance, realm */
|
|
u_long checksum; /* checksum to include in request */
|
|
MSG_DAT *msg_data; /* mutual auth MSG_DAT (return) */
|
|
CREDENTIALS *cred; /* credentials (return) */
|
|
Key_schedule schedule; /* key schedule (return) */
|
|
struct sockaddr_in *laddr; /* local address */
|
|
struct sockaddr_in *faddr; /* address of foreign host on fd */
|
|
char *version; /* version string */
|
|
{
|
|
int rem, i, cc;
|
|
char srv_inst[INST_SZ];
|
|
char krb_realm[REALM_SZ];
|
|
char buf[BUFSIZ];
|
|
long tkt_len;
|
|
u_char priv_buf[1024];
|
|
u_long cksum;
|
|
|
|
rem=KSUCCESS;
|
|
|
|
/* get current realm if not passed in */
|
|
if (!realm) {
|
|
rem = krb_get_lrealm(krb_realm,1);
|
|
if (rem != KSUCCESS)
|
|
return(rem);
|
|
realm = krb_realm;
|
|
}
|
|
|
|
/* copy instance into local storage, canonicalizing if desired */
|
|
if (options & KOPT_DONT_CANON)
|
|
(void) strncpy(srv_inst, inst, INST_SZ);
|
|
else
|
|
(void) strncpy(srv_inst, krb_get_phost(inst), INST_SZ);
|
|
|
|
/* get the ticket if desired */
|
|
if (!(options & KOPT_DONT_MK_REQ)) {
|
|
rem = krb_mk_req(ticket, service, srv_inst, realm, checksum);
|
|
if (rem != KSUCCESS)
|
|
return(rem);
|
|
}
|
|
|
|
#ifdef ATHENA_COMPAT
|
|
/* this is only for compatibility with old servers */
|
|
if (options & KOPT_DO_OLDSTYLE) {
|
|
(void) sprintf(buf,"%d ",ticket->length);
|
|
(void) write(fd, buf, strlen(buf));
|
|
(void) write(fd, (char *) ticket->dat, ticket->length);
|
|
return(rem);
|
|
}
|
|
#endif ATHENA_COMPAT
|
|
/* if mutual auth, get credentials so we have service session
|
|
keys for decryption below */
|
|
if (options & KOPT_DO_MUTUAL)
|
|
if ((cc = krb_get_cred(service, srv_inst, realm, cred)))
|
|
return(cc);
|
|
|
|
/* zero the buffer */
|
|
(void) bzero(buf, BUFSIZ);
|
|
|
|
/* insert version strings */
|
|
(void) strncpy(buf, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN);
|
|
(void) strncpy(buf+KRB_SENDAUTH_VLEN, version, KRB_SENDAUTH_VLEN);
|
|
|
|
/* increment past vers strings */
|
|
i = 2*KRB_SENDAUTH_VLEN;
|
|
|
|
/* put ticket length into buffer */
|
|
tkt_len = htonl((unsigned long) ticket->length);
|
|
(void) bcopy((char *) &tkt_len, buf+i, sizeof(tkt_len));
|
|
i += sizeof(tkt_len);
|
|
|
|
/* put ticket into buffer */
|
|
(void) bcopy((char *) ticket->dat, buf+i, ticket->length);
|
|
i += ticket->length;
|
|
|
|
/* write the request to the server */
|
|
if ((cc = krb_net_write(fd, buf, i)) != i)
|
|
return(cc);
|
|
|
|
/* mutual authentication, if desired */
|
|
if (options & KOPT_DO_MUTUAL) {
|
|
/* get the length of the reply */
|
|
if (krb_net_read(fd, (char *) &tkt_len, sizeof(tkt_len)) !=
|
|
sizeof(tkt_len))
|
|
return(errno);
|
|
tkt_len = ntohl((unsigned long)tkt_len);
|
|
|
|
/* if the length is negative, the server failed to recognize us. */
|
|
if ((tkt_len < 0) || (tkt_len > sizeof(priv_buf)))
|
|
return(KFAILURE); /* XXX */
|
|
/* read the reply... */
|
|
if (krb_net_read(fd, (char *)priv_buf, (int) tkt_len) != (int) tkt_len)
|
|
return(errno);
|
|
|
|
/* ...and decrypt it */
|
|
#ifndef NOENCRYPTION
|
|
key_sched((C_Block *)cred->session,schedule);
|
|
#endif
|
|
if ((cc = krb_rd_priv(priv_buf,(unsigned long) tkt_len, schedule,
|
|
cred->session, faddr, laddr, msg_data)))
|
|
return(cc);
|
|
|
|
/* fetch the (modified) checksum */
|
|
(void) bcopy((char *)msg_data->app_data, (char *)&cksum,
|
|
sizeof(cksum));
|
|
cksum = ntohl(cksum);
|
|
|
|
/* if it doesn't match, fail */
|
|
if (cksum != checksum + 1)
|
|
return(KFAILURE); /* XXX */
|
|
}
|
|
return(KSUCCESS);
|
|
}
|
|
|
|
#ifdef ATHENA_COMPAT
|
|
/*
|
|
* krb_sendsvc
|
|
*/
|
|
|
|
int
|
|
krb_sendsvc(fd, service)
|
|
int fd;
|
|
char *service;
|
|
{
|
|
/* write the service name length and then the service name to
|
|
the fd */
|
|
long serv_length;
|
|
int cc;
|
|
|
|
serv_length = htonl((unsigned long)strlen(service));
|
|
if ((cc = krb_net_write(fd, (char *) &serv_length,
|
|
sizeof(serv_length)))
|
|
!= sizeof(serv_length))
|
|
return(cc);
|
|
if ((cc = krb_net_write(fd, service, strlen(service)))
|
|
!= strlen(service))
|
|
return(cc);
|
|
return(KSUCCESS);
|
|
}
|
|
#endif ATHENA_COMPAT
|