summaryrefslogtreecommitdiff
path: root/kerberosIV/kerberos
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>1997-11-28 12:49:35 +0000
committerArtur Grabowski <art@cvs.openbsd.org>1997-11-28 12:49:35 +0000
commitc7b7a71f79cef9dbb230f353d9bbf3d6ef3a5aed (patch)
tree5817f345511882de1c9e1a57f3095352ce671421 /kerberosIV/kerberos
parent0857c8c45edb4fe59f82903f40d99a3aa19a04f7 (diff)
The first big step towards a complete upgrade to kth-krb4-0.9.7
Diffstat (limited to 'kerberosIV/kerberos')
-rw-r--r--kerberosIV/kerberos/Makefile4
-rw-r--r--kerberosIV/kerberos/kerberos.c1046
2 files changed, 593 insertions, 457 deletions
diff --git a/kerberosIV/kerberos/Makefile b/kerberosIV/kerberos/Makefile
index 455fe5ad922..8b16fd72bcc 100644
--- a/kerberosIV/kerberos/Makefile
+++ b/kerberosIV/kerberos/Makefile
@@ -1,9 +1,11 @@
# from @(#)Makefile 8.1 (Berkeley) 6/1/93
-# $Id: Makefile,v 1.1 1995/12/14 06:52:52 tholo Exp $
+# $Id: Makefile,v 1.2 1997/11/28 12:48:46 art Exp $
PROG= kerberos
DPADD= ${LIBKDB} ${LIBKRB} ${LIBDES}
LDADD= -lkdb -lkrb -ldes
MAN= kerberos.8
+CFLAGS+=-I${.CURDIR}
+
.include <bsd.prog.mk>
diff --git a/kerberosIV/kerberos/kerberos.c b/kerberosIV/kerberos/kerberos.c
index 9d0dbe42550..7f66aa55e65 100644
--- a/kerberosIV/kerberos/kerberos.c
+++ b/kerberosIV/kerberos/kerberos.c
@@ -1,103 +1,73 @@
-/* $Id: kerberos.c,v 1.5 1997/06/29 10:32:14 provos Exp $ */
+/* $KTH: kerberos.c,v 1.70 1997/09/26 18:06:38 joda Exp $ */
-/*-
- * Copyright 1987, 1988 by the Student Information Processing Board
- * of the Massachusetts Institute of Technology
+
+/*
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
*
- * 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 names of M.I.T. and the M.I.T. S.I.P.B. not be
- * used in advertising or publicity pertaining to distribution
- * of the software without specific, written prior permission.
- * M.I.T. and the M.I.T. S.I.P.B. make no representations about
- * the suitability of this software for any purpose. It is
- * provided "as is" without express or implied warranty.
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
*/
-#include "kerberosIV/site.h"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
-
#include <sys/time.h>
#include <time.h>
-
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
+#include <sys/select.h>
#include <errno.h>
#include <unistd.h>
-
+#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/filio.h>
#include <netdb.h>
+#include <stdarg.h>
+#include <err.h>
#include <des.h>
#include <kerberosIV/krb.h>
#include <kerberosIV/krb_db.h>
-
#include <prot.h>
-#include <klog.h>
-#include <kdc.h>
+#include "klog.h"
-static struct sockaddr_in sina = {AF_INET};
-int f;
-
-/* XXX several files in libkdb know about this */
-char *progname;
+#include "version.h"
+#include "krb_log.h"
+#include "kdc.h"
static des_key_schedule master_key_schedule;
static des_cblock master_key;
static struct timeval kerb_time;
-static Principal a_name_data; /* for requesting user */
-static Principal s_name_data; /* for services requested */
-static des_cblock session_key;
static u_char master_key_version;
static char k_instance[INST_SZ];
static char *lt;
static int more;
static int mflag; /* Are we invoked manually? */
-static int lflag; /* Have we set an alterate log file? */
-static char *log_file; /* name of alt. log file */
+static char *log_file = KRBLOG; /* name of alt. log file */
static int nflag; /* don't check max age */
static int rflag; /* alternate realm specified */
/* fields within the received request packet */
-static u_char req_msg_type;
-static u_char req_version;
static char *req_name_ptr;
static char *req_inst_ptr;
static char *req_realm_ptr;
-static u_long req_time_ws;
-
-int req_act_vno = KRB_PROT_VERSION; /* Temporary for version skew */
+static u_int32_t req_time_ws;
static char local_realm[REALM_SZ];
-/* statistics */
-static int q_bytes; /* current bytes remaining in queue */
-static int q_n; /* how many consecutive non-zero
- * q_bytes */
-static int max_q_bytes;
-static int max_q_n;
-static int n_auth_req;
-static int n_appl_req;
-static int n_packets;
-
+/* options */
static int max_age = -1;
static int pause_int = -1;
+static char progname[]="kerberos";
/*
* Print usage message and exit.
@@ -105,31 +75,31 @@ static int pause_int = -1;
static void
usage(void)
{
- fprintf(stderr, "Usage: %s [-s] [-m] [-n] [-p pause_seconds]%s%s\n", progname,
- " [-a max_age] [-l log_file] [-r realm]"
- ," [database_pathname]"
- );
+ fprintf(stderr, "Usage: %s [-s] [-m] [-n] [-p pause_seconds]"
+ " [-a max_age] [-l log_file] [-i address_to_listen_on]"
+ " [-r realm] [database_pathname]\n",
+ progname);
exit(1);
}
/*
- * kerb_er_reply creates an error reply packet and sends it to the
+ * kerb_err_reply creates an error reply packet and sends it to the
* client.
*/
static void
-kerb_err_reply(struct sockaddr_in *client, KTEXT pkt, long int err, char *string)
+kerb_err_reply(int f, struct sockaddr_in *client, int err, char *string)
{
static KTEXT_ST e_pkt_st;
KTEXT e_pkt = &e_pkt_st;
static char e_msg[128];
- bzero(e_msg, sizeof e_msg);
strcpy(e_msg, "\nKerberos error -- ");
strcat(e_msg, string);
cr_err_reply(e_pkt, req_name_ptr, req_inst_ptr, req_realm_ptr,
req_time_ws, err, e_msg);
- sendto(f, e_pkt->dat, e_pkt->length, 0, (struct sockaddr*)client, S_AD_SZ);
+ sendto(f, (char*)e_pkt->dat, e_pkt->length, 0, (struct sockaddr *)client,
+ sizeof(*client));
}
static void
@@ -141,9 +111,9 @@ hang(void)
pause();
} else {
char buf[256];
- (void) snprintf(buf, sizeof(buf),
- "Kerberos will wait %d seconds before dying so as not to loop init",
- pause_int);
+ snprintf(buf, sizeof(buf),
+ "Kerberos will wait %d seconds before dying so as not to loop init",
+ pause_int);
klog(L_KRB_PERR, buf);
sleep(pause_int);
klog(L_KRB_PERR, "Do svedania....\n");
@@ -151,29 +121,6 @@ hang(void)
}
}
-/*
- * Given a pointer to a long containing the number of seconds
- * since the beginning of time (midnight 1 Jan 1970 GMT), return
- * a string containing the local time in the form:
- *
- * "25-Jan-88 10:17:56"
- */
-
-static char *
-strtime(time_t *t)
-{
- static char st_data[40];
- static char *st = st_data;
- struct tm *tm;
- char *month_sname(int n);
-
- tm = localtime(t);
- (void) snprintf(st, sizeof(st_data), "%2d-%s-%02d %02d:%02d:%02d",
- tm->tm_mday, month_sname(tm->tm_mon + 1), tm->tm_year,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- return st;
-}
-
static int
check_princ(char *p_name, char *instance, unsigned int lifetime, Principal *p)
{
@@ -181,9 +128,6 @@ check_princ(char *p_name, char *instance, unsigned int lifetime, Principal *p)
static int more;
n = kerb_get_principal(p_name, instance, p, 1, &more);
- klog(L_ALL_REQ,
- "Principal: \"%s\", Instance: \"%s\" Lifetime = %d n = %d",
- p_name, instance, lifetime, n, 0);
if (n < 0) {
lt = klog(L_KRB_PERR, "Database unavailable!");
@@ -197,43 +141,47 @@ check_princ(char *p_name, char *instance, unsigned int lifetime, Principal *p)
*/
if (n == 0) {
/* service unknown, log error, skip to next request */
- lt = klog(L_ERR_UNK, "UNKNOWN \"%s\" \"%s\"", p_name,
- instance, 0);
+ lt = klog(L_ERR_UNK, "UNKNOWN %s.%s", p_name, instance);
return KERB_ERR_PRINCIPAL_UNKNOWN;
}
if (more) {
/* not unique, log error */
- lt = klog(L_ERR_NUN, "Principal NOT UNIQUE \"%s\" \"%s\"",
- p_name, instance, 0);
+ lt = klog(L_ERR_NUN, "Principal not unique %s.%s", p_name, instance);
return KERB_ERR_PRINCIPAL_NOT_UNIQUE;
}
/* If the user's key is null, we want to return an error */
if ((p->key_low == 0) && (p->key_high == 0)) {
/* User has a null key */
- lt = klog(L_ERR_NKY, "Null key \"%s\" \"%s\"", p_name,
- instance, 0);
+ lt = klog(L_ERR_NKY, "Null key %s.%s", p_name, instance);
return KERB_ERR_NULL_KEY;
}
if (master_key_version != p->kdc_key_ver) {
/* log error reply */
lt = klog(L_ERR_MKV,
- "Key vers incorrect, KRB = %d, \"%s\" \"%s\" = %d",
- master_key_version, p->name, p->instance, p->kdc_key_ver,
- 0);
+ "Incorrect master key version for %s.%s: %d (should be %d)",
+ p->name, p->instance, p->kdc_key_ver, master_key_version);
return KERB_ERR_NAME_MAST_KEY_VER;
}
/* make sure the service hasn't expired */
- if ((u_long) p->exp_date < (u_long) kerb_time.tv_sec) {
+ if ((u_int32_t) p->exp_date < (u_int32_t) kerb_time.tv_sec) {
/* service did expire, log it */
+ time_t t = p->exp_date;
lt = klog(L_ERR_SEXP,
- "EXPIRED \"%s\" \"%s\" %s", p->name, p->instance,
- strtime((time_t*)&(p->exp_date)), 0);
+ "Principal %s.%s expired at %s", p->name, p->instance,
+ krb_stime(&t));
return KERB_ERR_NAME_EXP;
}
/* ok is zero */
return 0;
}
+static void
+unseal(des_cblock *key)
+{
+ kdb_encrypt_key(key, key, &master_key, master_key_schedule, DES_DECRYPT);
+}
+
+
/* Set the key for krb_rd_req so we can check tgt */
static int
set_tgtkey(char *r)
@@ -248,315 +196,236 @@ set_tgtkey(char *r)
if (!strcmp(lastrealm, r))
return (KSUCCESS);
- log("Getting key for %s", r);
+ klog(L_ALL_REQ, "Getting key for %s", r);
- n = kerb_get_principal("krbtgt", r, p, 1, &more);
+ n = kerb_get_principal(KRB_TICKET_GRANTING_TICKET, r, p, 1, &more);
if (n == 0)
return (KFAILURE);
/* unseal tgt key from master key */
- bcopy(&p->key_low, key, 4);
- bcopy(&p->key_high, ((long *) key) + 1, 4);
- kdb_encrypt_key(&key, &key, &master_key,
- master_key_schedule, DES_DECRYPT);
+ copy_to_key(&p->key_low, &p->key_high, key);
+ unseal(&key);
krb_set_key(key, 0);
strcpy(lastrealm, r);
return (KSUCCESS);
}
-static void
-kerberos(struct sockaddr_in *client, KTEXT pkt)
-{
- static KTEXT_ST rpkt_st;
- KTEXT rpkt = &rpkt_st;
- static KTEXT_ST ciph_st;
- KTEXT ciph = &ciph_st;
- static KTEXT_ST tk_st;
- KTEXT tk = &tk_st;
- static KTEXT_ST auth_st;
- KTEXT auth = &auth_st;
- AUTH_DAT ad_st;
- AUTH_DAT *ad = &ad_st;
-
-
- static struct in_addr client_host;
- static int msg_byte_order;
- static int swap_bytes;
- static u_char k_flags;
- u_long lifetime;
- int i;
- des_cblock key;
- des_key_schedule key_s;
- char *ptr;
-
-
-
- ciph->length = 0;
- client_host = client->sin_addr;
-
- /* eval macros and correct the byte order and alignment as needed */
- req_version = pkt_version(pkt); /* 1 byte, version */
- req_msg_type = pkt_msg_type(pkt); /* 1 byte, Kerberos msg type */
-
- req_act_vno = req_version;
-
- /* check packet version */
- if (req_version != KRB_PROT_VERSION) {
- lt = klog(L_KRB_PERR,
- "KRB prot version mismatch: KRB =%d request = %d",
- KRB_PROT_VERSION, req_version, 0);
- /* send an error reply */
- kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt);
- return;
- }
- msg_byte_order = req_msg_type & 1;
-
- swap_bytes = 0;
- if (msg_byte_order != HOST_BYTE_ORDER) {
- swap_bytes++;
+static int
+kerberos(unsigned char *buf, int len,
+ char *proto, struct sockaddr_in *client,
+ struct sockaddr_in *server,
+ KTEXT rpkt)
+{
+ int pvno;
+ int msg_type;
+ int lsb;
+ int life;
+ int flags = 0;
+ char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
+ char service[SNAME_SZ], sinst[INST_SZ];
+ u_int32_t req_time;
+ static KTEXT_ST ticket, cipher, adat;
+ KTEXT tk = &ticket, ciph = &cipher, auth = &adat;
+ AUTH_DAT ad;
+ des_cblock session, key;
+ int err;
+ Principal a_name, s_name;
+
+ char *msg;
+
+
+ unsigned char *p = buf;
+ if(len < 2){
+ strcpy((char*)rpkt->dat, "Packet too short");
+ return KFAILURE;
}
- klog(L_KRB_PINFO,
- "Prot version: %d, Byte order: %d, Message type: %d",
- req_version, msg_byte_order, req_msg_type);
- switch (req_msg_type & ~1) {
+ gettimeofday(&kerb_time, NULL);
+ pvno = *p++;
+ if(pvno != KRB_PROT_VERSION){
+ msg = klog(L_KRB_PERR, "KRB protocol version mismatch (%d)", pvno);
+ strcpy((char*)rpkt->dat, msg);
+ return KERB_ERR_PKT_VER;
+ }
+ msg_type = *p++;
+ lsb = msg_type & 1;
+ msg_type &= ~1;
+ switch(msg_type){
case AUTH_MSG_KDC_REQUEST:
+ /* XXX range check */
+ p += krb_get_nir(p, name, inst, realm);
+ p += krb_get_int(p, &req_time, 4, lsb);
+ life = *p++;
+ p += krb_get_nir(p, service, sinst, NULL);
+ klog(L_INI_REQ,
+ "AS REQ %s.%s@%s for %s.%s from %s (%s/%u)",
+ name, inst, realm, service, sinst,
+ inet_ntoa(client->sin_addr),
+ proto, ntohs(server->sin_port));
+ if((err = check_princ(name, inst, 0, &a_name))){
+ strcpy((char*)rpkt->dat, krb_get_err_text(err));
+ return err;
+ }
+ tk->length = 0;
+ if((err = check_princ(service, sinst, 0, &s_name))){
+ strcpy((char*)rpkt->dat, krb_get_err_text(err));
+ return err;
+ }
+ life = min(life, s_name.max_life);
+ life = min(life, a_name.max_life);
+
+ des_new_random_key(&session);
+ copy_to_key(&s_name.key_low, &s_name.key_high, key);
+ unseal(&key);
+ krb_create_ticket(tk, flags, a_name.name, a_name.instance,
+ local_realm, client->sin_addr.s_addr,
+ session,
+ life, kerb_time.tv_sec,
+ s_name.name, s_name.instance, &key);
+ copy_to_key(&a_name.key_low, &a_name.key_high, key);
+ unseal(&key);
+ create_ciph(ciph, session, s_name.name, s_name.instance,
+ local_realm, life, s_name.key_version, tk,
+ kerb_time.tv_sec, &key);
+ memset(&session, 0, sizeof(session));
+ memset(&key, 0, sizeof(key));
{
- u_long req_life; /* Requested liftime */
- char *service; /* Service name */
- char *instance; /* Service instance */
-
- n_auth_req++;
- tk->length = 0;
- k_flags = 0; /* various kerberos flags */
-
-
- /* set up and correct for byte order and alignment */
- req_name_ptr = (char *) pkt_a_name(pkt);
- req_inst_ptr = (char *) pkt_a_inst(pkt);
- req_realm_ptr = (char *) pkt_a_realm(pkt);
- bcopy(pkt_time_ws(pkt), &req_time_ws, sizeof(req_time_ws));
- /* time has to be diddled */
- if (swap_bytes) {
- swap_u_long(req_time_ws);
- }
- ptr = (char *) pkt_time_ws(pkt) + 4;
-
- req_life = (unsigned char) (*ptr++);
-
- service = ptr;
- instance = ptr + strlen(service) + 1;
-
- rpkt = &rpkt_st;
- klog(L_INI_REQ,
- "Initial ticket request Host: %s User: \"%s\" \"%s\"",
- inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0);
-
- if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
- &a_name_data))) {
- kerb_err_reply(client, pkt, i, lt);
- return;
- }
- tk->length = 0; /* init */
- if (strcmp(service, "krbtgt"))
- klog(L_NTGT_INTK,
- "INITIAL request from %s.%s for %s.%s",
- req_name_ptr, req_inst_ptr, service, instance, 0);
- /* this does all the checking */
- if ((i = check_princ(service, instance, 0,
- &s_name_data))) {
- kerb_err_reply(client, pkt, i, lt);
- return;
- }
- /* Bound requested lifetime with service and user */
- lifetime = min(req_life, ((u_long) s_name_data.max_life));
- lifetime = min(lifetime, ((u_long) a_name_data.max_life));
-
-#ifdef NOENCRYPTION
- bzero(session_key, sizeof(des_cblock));
-#else
- des_new_random_key(&session_key);
-#endif
- /* unseal server's key from master key */
- bcopy(&s_name_data.key_low, key, 4);
- bcopy(&s_name_data.key_high, ((long *) key) + 1, 4);
- kdb_encrypt_key(&key, &key, &master_key,
- master_key_schedule, DES_DECRYPT);
- /* construct and seal the ticket */
- krb_create_ticket(tk, k_flags, a_name_data.name,
- a_name_data.instance, local_realm,
- client_host.s_addr, session_key, lifetime, kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance, &key);
- bzero(key, sizeof(key));
- bzero(key_s, sizeof(key_s));
-
- /*
- * get the user's key, unseal it from the server's key, and
- * use it to seal the cipher
- */
-
- /* a_name_data.key_low a_name_data.key_high */
- bcopy(&a_name_data.key_low, key, 4);
- bcopy(&a_name_data.key_high, ((long *) key) + 1, 4);
-
- /* unseal the a_name key from the master key */
- kdb_encrypt_key(&key, &key, &master_key,
- master_key_schedule, DES_DECRYPT);
-
- create_ciph(ciph, session_key, s_name_data.name,
- s_name_data.instance, local_realm, lifetime,
- s_name_data.key_version, tk, kerb_time.tv_sec, &key);
-
- /* clear session key */
- bzero(session_key, sizeof(session_key));
-
- bzero(key, sizeof(key));
-
-
-
- /* always send a reply packet */
- rpkt = create_auth_reply(req_name_ptr, req_inst_ptr,
- req_realm_ptr, req_time_ws, 0, a_name_data.exp_date,
- a_name_data.key_version, ciph);
- sendto(f, rpkt->dat, rpkt->length, 0, (struct sockaddr*)client, S_AD_SZ);
- bzero(&a_name_data, sizeof(a_name_data));
- bzero(&s_name_data, sizeof(s_name_data));
- break;
+ KTEXT r;
+ r = create_auth_reply(name, inst, realm, req_time, 0,
+ a_name.exp_date, a_name.key_version, ciph);
+ memcpy(rpkt, r, sizeof(*rpkt));
}
+ return 0;
case AUTH_MSG_APPL_REQUEST:
- {
- u_long time_ws; /* Workstation time */
- u_long req_life; /* Requested liftime */
- char *service; /* Service name */
- char *instance; /* Service instance */
- int kerno; /* Kerberos error number */
- char tktrlm[REALM_SZ];
-
- n_appl_req++;
- tk->length = 0;
- k_flags = 0; /* various kerberos flags */
-
- auth->length = 4 + strlen((char*)pkt->dat + 3);
- auth->length += (int) *(pkt->dat + auth->length) +
- (int) *(pkt->dat + auth->length + 1) + 2;
-
- bcopy(pkt->dat, auth->dat, auth->length);
-
- strncpy(tktrlm, (char*)(auth->dat + 3), REALM_SZ);
- if (set_tgtkey(tktrlm)) {
- lt = klog(L_ERR_UNK,
- "FAILED realm %s unknown. Host: %s ",
- tktrlm, inet_ntoa(client_host));
- kerb_err_reply(client, pkt, kerno, lt);
- return;
- }
- kerno = krb_rd_req(auth, "ktbtgt", tktrlm, client_host.s_addr,
- ad, 0);
-
- if (kerno) {
- klog(L_ERR_UNK, "FAILED krb_rd_req from %s: %s",
- inet_ntoa(client_host), krb_err_txt[kerno]);
- kerb_err_reply(client, pkt, kerno, "krb_rd_req failed");
- return;
- }
- ptr = (char *) pkt->dat + auth->length;
-
- bcopy(ptr, &time_ws, 4);
- ptr += 4;
-
- req_life = (unsigned char) (*ptr++);
-
- service = ptr;
- instance = ptr + strlen(service) + 1;
+ strcpy(realm, (char*)buf + 3);
+ if((err = set_tgtkey(realm))){
+ msg = klog(L_ERR_UNK,
+ "Unknown realm %s from %s (%s/%u)",
+ realm, inet_ntoa(client->sin_addr),
+ proto, ntohs(server->sin_port));
+ strcpy((char*)rpkt->dat, msg);
+ return err;
+ }
+ p = buf + strlen(realm) + 4;
+ p = p + p[0] + p[1] + 2;
+ auth->length = p - buf;
+ memcpy(auth->dat, buf, auth->length);
+ err = krb_rd_req(auth, KRB_TICKET_GRANTING_TICKET,
+ realm, client->sin_addr.s_addr, &ad, 0);
+ if(err){
+ msg = klog(L_ERR_UNK,
+ "krb_rd_req from %s (%s/%u): %s",
+ inet_ntoa(client->sin_addr),
+ proto,
+ ntohs(server->sin_port),
+ krb_get_err_text(err));
+ strcpy((char*)rpkt->dat, msg);
+ return err;
+ }
+ p += krb_get_int(p, &req_time, 4, lsb);
+ life = *p++;
+ p += krb_get_nir(p, service, sinst, NULL);
+ klog(L_APPL_REQ,
+ "APPL REQ %s.%s@%s for %s.%s from %s (%s/%u)",
+ ad.pname, ad.pinst, ad.prealm,
+ service, sinst,
+ inet_ntoa(client->sin_addr),
+ proto,
+ ntohs(server->sin_port));
+
+ if(strcmp(ad.prealm, realm)){
+ msg = klog(L_ERR_UNK, "Can't hop realms: %s -> %s",
+ realm, ad.prealm);
+ strcpy((char*)rpkt->dat, msg);
+ return KERB_ERR_PRINCIPAL_UNKNOWN;
+ }
- klog(L_APPL_REQ, "APPL Request %s.%s@%s on %s for %s.%s",
- ad->pname, ad->pinst, ad->prealm, inet_ntoa(client_host),
- service, instance, 0);
+ if(!strcmp(service, "changepw")){
+ strcpy((char*)rpkt->dat,
+ "Can't authorize password changed based on TGT");
+ return KERB_ERR_PRINCIPAL_UNKNOWN;
+ }
- if (strcmp(ad->prealm, tktrlm)) {
- kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN,
- "Can't hop realms");
- return;
- }
- if (!strcmp(service, "changepw")) {
- kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN,
- "Can't authorize password changed based on TGT");
- return;
- }
- kerno = check_princ(service, instance, req_life,
- &s_name_data);
- if (kerno) {
- kerb_err_reply(client, pkt, kerno, lt);
- return;
- }
- /* Bound requested lifetime with service and user */
- lifetime = min(req_life,
- krb_time_to_life(kerb_time.tv_sec,krb_life_to_time(ad->time_sec,ad->life)));
- lifetime = min(lifetime, ((u_long) s_name_data.max_life));
-
- /* unseal server's key from master key */
- bcopy(&s_name_data.key_low, key, 4);
- bcopy(&s_name_data.key_high, ((long *) key) + 1, 4);
- kdb_encrypt_key(&key, &key, &master_key,
- master_key_schedule, DES_DECRYPT);
- /* construct and seal the ticket */
-
-#ifdef NOENCRYPTION
- bzero(session_key, sizeof(des_cblock));
-#else
- des_new_random_key(&session_key);
-#endif
-
- krb_create_ticket(tk, k_flags, ad->pname, ad->pinst,
- ad->prealm, client_host.s_addr,
- session_key, lifetime, kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- &key);
- bzero(key, sizeof(key));
- bzero(key_s, sizeof(key_s));
-
- create_ciph(ciph, session_key, service, instance,
- local_realm,
- lifetime, s_name_data.key_version, tk,
- kerb_time.tv_sec, &ad->session);
-
- /* clear session key */
- bzero(session_key, sizeof(session_key));
-
- bzero(ad->session, sizeof(ad->session));
-
- rpkt = create_auth_reply(ad->pname, ad->pinst,
- ad->prealm, time_ws,
- 0, 0, 0, ciph);
- sendto(f, rpkt->dat, rpkt->length, 0, (struct sockaddr*)client, S_AD_SZ);
- bzero(&s_name_data, sizeof(s_name_data));
- break;
+ err = check_princ(service, sinst, life, &s_name);
+ if(err){
+ strcpy((char*)rpkt->dat, krb_get_err_text(err));
+ return err;
}
+ life = min(life,
+ krb_time_to_life(kerb_time.tv_sec,
+ krb_life_to_time(ad.time_sec,
+ ad.life)));
+ life = min(life, s_name.max_life);
+ copy_to_key(&s_name.key_low, &s_name.key_high, key);
+ unseal(&key);
+ des_new_random_key(&session);
+ krb_create_ticket(tk, flags, ad.pname, ad.pinst, ad.prealm,
+ client->sin_addr.s_addr, &session,
+ life, kerb_time.tv_sec,
+ s_name.name, s_name.instance,
+ &key);
+
+ memset(&key, 0, sizeof(key));
+ create_ciph(ciph, session, service, sinst, local_realm,
+ life, s_name.key_version, tk,
+ kerb_time.tv_sec, &ad.session);
-#ifdef notdef_DIE
- case AUTH_MSG_DIE:
+ memset(&session, 0, sizeof(session));
+ memset(ad.session, 0, sizeof(ad.session));
{
- lt = klog(L_DEATH_REQ,
- "Host: %s User: \"%s\" \"%s\" Kerberos killed",
- inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0);
- exit(0);
+ KTEXT r;
+ r =create_auth_reply(ad.pname, ad.pinst, ad.prealm,
+ req_time, 0, 0, 0, ciph);
+ memcpy(rpkt, r, sizeof(*rpkt));
}
-#endif /* notdef_DIE */
-
+ memset(&s_name, 0, sizeof(s_name));
+ return 0;
+
+ case AUTH_MSG_ERR_REPLY:
+ return -1;
default:
- {
- lt = klog(L_KRB_PERR,
- "Unknown message type: %d from %s port %u",
- req_msg_type, inet_ntoa(client_host),
- ntohs(client->sin_port));
- break;
- }
+ msg = klog(L_KRB_PERR,
+ "Unknown message type: %d from %s (%s/%u)",
+ msg_type,
+ inet_ntoa(client->sin_addr),
+ proto,
+ ntohs(server->sin_port));
+ strcpy((char*)rpkt->dat, msg);
+ return KFAILURE;
+ }
+}
+
+
+static void
+kerberos_wrap(int s, KTEXT data, char *proto, struct sockaddr_in *client,
+ struct sockaddr_in *server)
+{
+ KTEXT_ST pkt;
+ int http_flag = strcmp(proto, "http") == 0;
+ int err = kerberos(data->dat, data->length, proto, client, server, &pkt);
+ if(err == -1)
+ return;
+ if(http_flag){
+ const char *msg =
+ "HTTP/1.1 200 OK\r\n"
+ "Server: KTH-KRB/" VERSION "\r\n"
+ "Content-type: application/octet-stream\r\n"
+ "Content-transfer-encoding: binary\r\n\r\n";
+ sendto(s, msg, strlen(msg), 0, (struct sockaddr *)client,
+ sizeof(*client));
+ }
+ if(err){
+ kerb_err_reply(s, client, err, (char*)pkt.dat);
+ return;
}
+ sendto(s, pkt.dat, pkt.length, 0, (struct sockaddr *)client,
+ sizeof(*client));
}
+
/*
* setup_disc
*
@@ -570,16 +439,16 @@ setup_disc(void)
int s;
for (s = 0; s < 3; s++) {
- (void) close(s);
+ close(s);
}
- (void) open("/dev/null", 0);
- (void) dup2(0, 1);
- (void) dup2(0, 2);
+ open("/dev/null", 0);
+ dup2(0, 1);
+ dup2(0, 2);
setsid();
- (void) chdir("/tmp");
+ chdir("/tmp");
return;
}
@@ -589,7 +458,8 @@ setup_disc(void)
* Exit if it is; we don't want to tell lies.
*/
-static void check_db_age(void)
+static void
+check_db_age(void)
{
long age;
@@ -609,25 +479,159 @@ static void check_db_age(void)
}
}
+struct descr{
+ int s;
+ KTEXT_ST buf;
+ int type;
+ int timeout;
+ struct sockaddr_in addr;
+};
+
+static void
+mksocket(struct descr *d, struct in_addr addr, int type,
+ const char *service, int port)
+{
+ int on = 1;
+ int sock;
+
+ memset(d, 0, sizeof(struct descr));
+ if ((sock = socket(AF_INET, type, 0)) < 0)
+ err (1, "socket");
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
+ sizeof(on)) < 0)
+ warn ("setsockopt (SO_REUSEADDR)");
+ memset(&d->addr, 0, sizeof(d->addr));
+ d->addr.sin_family = AF_INET;
+ d->addr.sin_port = port;
+ d->addr.sin_addr = addr;
+ if (bind(sock, (struct sockaddr *)&d->addr, sizeof(d->addr)) < 0)
+ err (1, "bind '%s/%s' (%d)",
+ service, (type == SOCK_DGRAM) ? "udp" : "tcp",
+ ntohs(d->addr.sin_port));
+
+ if(type == SOCK_STREAM)
+ listen(sock, SOMAXCONN);
+ d->s = sock;
+ d->type = type;
+}
+
+
+static void loop(struct descr *fds, int maxfd);
+
+struct port_spec {
+ int port;
+ int type;
+};
+
+static int
+add_port(struct port_spec **ports, int *num_ports, int port, int type)
+{
+ struct port_spec *tmp;
+ tmp = realloc(*ports, (*num_ports + 1) * sizeof(*tmp));
+ if(tmp == NULL)
+ return ENOMEM;
+ *ports = tmp;
+ tmp[*num_ports].port = port;
+ tmp[*num_ports].type = type;
+ (*num_ports)++;
+ return 0;
+}
+
+void make_sockets(char *port_spec, struct in_addr *i_addr,
+ struct descr **fds, int *nfds)
+{
+ int tp;
+ struct in_addr *a;
+ char *p, *q, *pos = NULL;
+ struct servent *sp;
+ struct port_spec *ports = NULL;
+ int num_ports = 0;
+ int i, j;
+
+
+ for(p = strtok_r(port_spec, " \t", &pos);
+ p;
+ p = strtok_r(NULL, " \t", &pos)){
+ if(strcmp(p, "+") == 0){
+ add_port(&ports, &num_ports, 88, SOCK_DGRAM);
+ add_port(&ports, &num_ports, 88, SOCK_STREAM);
+ add_port(&ports, &num_ports, 750, SOCK_DGRAM);
+ add_port(&ports, &num_ports, 750, SOCK_STREAM);
+ }else{
+ q = strchr(p, '/');
+ if(q){
+ *q = 0;
+ q++;
+ }
+ sp = getservbyname(p, q);
+ if(sp)
+ tp = ntohs(sp->s_port);
+ else if(sscanf(p, "%d", &tp) != 1) {
+ warnx("Unknown port: %s%s%s", p, q ? "/" : "", q ? q : "");
+ continue;
+ }
+ if(q){
+ if(strcasecmp(q, "tcp") == 0)
+ add_port(&ports, &num_ports, tp, SOCK_STREAM);
+ else if(strcasecmp(q, "udp") == 0)
+ add_port(&ports, &num_ports, tp, SOCK_DGRAM);
+ else
+ warnx("Unknown protocol type: %s", q);
+ }else{
+ add_port(&ports, &num_ports, tp, SOCK_DGRAM);
+ add_port(&ports, &num_ports, tp, SOCK_STREAM);
+ }
+ }
+ }
+
+ if(num_ports == 0)
+ errx(1, "No valid ports specified!");
+
+ if (i_addr) {
+ *nfds = 1;
+ a = malloc(sizeof(*a) * *nfds);
+ memcpy(a, i_addr, sizeof(struct in_addr));
+ } else
+ *nfds = k_get_all_addrs (&a);
+ if (*nfds < 0) {
+ struct in_addr any;
+
+ any.s_addr = INADDR_ANY;
+
+ warnx ("Could not get local addresses, binding to INADDR_ANY");
+ *nfds = 1;
+ a = malloc(sizeof(*a) * *nfds);
+ memcpy(a, &any, sizeof(struct in_addr));
+ }
+ *fds = malloc(*nfds * num_ports * sizeof(**fds));
+ for (i = 0; i < *nfds; i++) {
+ for(j = 0; j < num_ports; j++) {
+ mksocket(*fds + num_ports * i + j, a[i],
+ ports[j].type, "", htons(ports[j].port));
+ }
+ }
+ *nfds *= num_ports;
+ free(ports);
+ free (a);
+}
+
+
int
main(int argc, char **argv)
{
- struct sockaddr_in from;
- register int n;
- int on = 1;
int child;
- struct servent *sp;
- int fromlen;
- static KTEXT_ST pkt_st;
- KTEXT pkt = &pkt_st;
- int kerror;
int c;
- extern char *optarg;
- extern int optind;
+ struct descr *fds;
+ int nfds;
+ int n;
+ int kerror;
+ int i_flag = 0;
+ struct in_addr i_addr;
+ char *port_spec = "+";
- progname = argv[0];
+ umask(077); /* Create protected files */
- while ((c = getopt(argc, argv, "snmp:a:l:r:")) != -1) {
+ while ((c = getopt(argc, argv, "snmp:P:a:l:r:i:")) != EOF) {
switch(c) {
case 's':
/*
@@ -637,10 +641,6 @@ main(int argc, char **argv)
max_age = ONE_DAY; /* 24 hours */
if (pause_int == -1)
pause_int = FIVE_MINUTES; /* 5 minutes */
- if (lflag == 0) {
- log_file = KRBSLAVELOG;
- lflag++;
- }
break;
case 'n':
max_age = -1; /* don't check max age. */
@@ -659,6 +659,9 @@ main(int argc, char **argv)
usage();
}
break;
+ case 'P':
+ port_spec = optarg;
+ break;
case 'a':
/* Set max age. */
if (!isdigit(optarg[0]))
@@ -671,7 +674,6 @@ main(int argc, char **argv)
break;
case 'l':
/* Set alternate log file */
- lflag++;
log_file = optarg;
break;
case 'r':
@@ -679,12 +681,20 @@ main(int argc, char **argv)
rflag++;
strcpy(local_realm, optarg);
break;
+ case 'i':
+ /* Only listen on this address */
+ if(inet_aton (optarg, &i_addr) == 0) {
+ fprintf (stderr, "Bad address: %s\n", optarg);
+ exit (1);
+ }
+ ++i_flag;
+ break;
default:
usage();
break;
}
}
-
+
if (optind == (argc-1)) {
if (kerb_db_set_name(argv[optind]) != 0) {
fprintf(stderr, "Could not set alternate database name\n");
@@ -707,40 +717,22 @@ main(int argc, char **argv)
if (mflag)
printf("\tMaster key will be entered manually\n");
- printf("\tLog file is %s\n", lflag ? log_file : KRBLOG);
+ printf("\tLog file is %s\n", log_file);
- if (lflag)
- kset_logfile(log_file);
+ kset_logfile(log_file);
/* find our hostname, and use it as the instance */
- if (gethostname(k_instance, INST_SZ)) {
- fprintf(stderr, "%s: gethostname error\n", progname);
- exit(1);
- }
-
- if ((sp = getservbyname("kerberos", "udp")) == 0) {
- fprintf(stderr, "%s: udp/kerberos unknown service\n", progname);
- exit(1);
- }
- sina.sin_port = sp->s_port;
+ if (k_gethostname(k_instance, INST_SZ))
+ err (1, "gethostname");
- if ((f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- fprintf(stderr, "%s: Can't open socket\n", progname);
- exit(1);
- }
- if (setsockopt(f, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
- fprintf(stderr, "%s: setsockopt (SO_REUSEADDR)\n", progname);
+ make_sockets(port_spec, i_flag ? &i_addr : NULL, &fds, &nfds);
- if (bind(f, (struct sockaddr*)&sina, sizeof(sina)) < 0) {
- fprintf(stderr, "%s: Can't bind socket\n", progname);
- exit(1);
- }
/* do all the database and cache inits */
if ((n = kerb_init())) {
if (mflag) {
printf("Kerberos db and cache init ");
printf("failed = %d ...exiting\n", n);
- exit(-1);
+ exit (1);
} else {
klog(L_KRB_PERR,
"Kerberos db and cache init failed = %d ...exiting", n);
@@ -753,15 +745,15 @@ main(int argc, char **argv)
/* setup master key */
if (kdb_get_master_key (mflag, &master_key, master_key_schedule) != 0) {
- klog (L_KRB_PERR, "kerberos: couldn't get master key.\n");
- exit (-1);
+ klog (L_KRB_PERR, "kerberos: couldn't get master key.");
+ exit (1);
}
kerror = kdb_verify_master_key (&master_key, master_key_schedule, stdout);
if (kerror < 0) {
klog (L_KRB_PERR, "Can't verify master key.");
- bzero (master_key, sizeof (master_key));
- bzero (master_key_schedule, sizeof (master_key_schedule));
- exit (-1);
+ memset(master_key, 0, sizeof (master_key));
+ memset (master_key_schedule, 0, sizeof (master_key_schedule));
+ exit (1);
}
master_key_version = (u_char) kerror;
@@ -790,28 +782,170 @@ main(int argc, char **argv)
}
setup_disc();
}
+
+ klog(L_ALL_REQ, "Starting Kerberos for %s (kvno %d)",
+ local_realm, master_key_version);
+
/* receive loop */
+ loop(fds, nfds);
+ exit(1);
+}
+
+
+void
+read_socket(struct descr *n)
+{
+ int b;
+ struct sockaddr_in from;
+ int fromlen = sizeof(from);
+ b = recvfrom(n->s, n->buf.dat + n->buf.length,
+ MAX_PKT_LEN - n->buf.length, 0,
+ (struct sockaddr *)&from, &fromlen);
+ if(b < 0){
+ if(n->type == SOCK_STREAM){
+ close(n->s);
+ n->s = -1;
+ }
+ n->buf.length = 0;
+ return;
+ }
+ n->buf.length += b;
+ if(n->type == SOCK_STREAM){
+ char *proto = "tcp";
+ if(n->buf.length > 4 &&
+ strncmp(n->buf.dat, "GET ", 4) == 0 &&
+ strncmp(n->buf.dat + n->buf.length - 4,
+ "\r\n\r\n", 4) == 0){
+ char *p;
+ n->buf.dat[n->buf.length - 1] = 0;
+ strtok(n->buf.dat, " \t\r\n");
+ p = strtok(NULL, " \t\r\n");
+ if(p == NULL)
+ p = "";
+ if(*p == '/') p++;
+ p = strdup(p);
+ n->buf.length = base64_decode(p, n->buf.dat);
+ free(p);
+ if(n->buf.length <= 0){
+ const char *msg =
+ "HTTP/1.1 404 Not found\r\n"
+ "Server: KTH-KRB/" VERSION "\r\n"
+ "Content-type: text/html\r\n"
+ "Content-transfer-encoding: 8bit\r\n\r\n"
+ "<TITLE>404 Not found</TITLE>\r\n"
+ "<H1>404 Not found</H1>\r\n"
+ "That page does not exist. Information about "
+ "<A HREF=\"http://www.pdc.kth.se/kth-krb\">KTH-KRB</A> "
+ "is available elsewhere.\r\n";
+ write(n->s, msg, strlen(msg));
+ close(n->s);
+ n->s = -1;
+ n->buf.length = 0;
+ return;
+ }
+ proto = "http";
+ b = 0;
+ }
+ else if(n->buf.length >= 4 && n->buf.dat[0] == 0){
+ /* if this is a new type of packet (with
+ the length attached to the head of the
+ packet), and there is no more data to
+ be read, fake an old packet, so the
+ code below will work */
+ u_int32_t len;
+ krb_get_int(n->buf.dat, &len, 4, 0);
+ if(n->buf.length == len + 4){
+ memmove(n->buf.dat, n->buf.dat + 4, len);
+ b = 0;
+ }
+ }
+ if(b == 0){
+ /* handle request if there are
+ no more bytes to read */
+ fromlen = sizeof(from);
+ getpeername(n->s,(struct sockaddr*)&from, &fromlen);
+ kerberos_wrap(n->s, &n->buf, proto, &from,
+ &n->addr);
+ n->buf.length = 0;
+ close(n->s);
+ n->s = -1;
+ }
+ }else{
+ /* udp packets are atomic */
+ kerberos_wrap(n->s, &n->buf, "udp", &from,
+ &n->addr);
+ n->buf.length = 0;
+ }
+}
+
+static void
+loop(struct descr *fds, int nfds)
+{
for (;;) {
- fromlen = S_AD_SZ;
- n = recvfrom(f, pkt->dat, MAX_PKT_LEN, 0, (struct sockaddr*)&from, &fromlen);
- if (n > 0) {
- pkt->length = n;
- pkt->mbz = 0; /* force zeros to catch runaway strings */
- /* see what is left in the input queue */
- ioctl(f, FIONREAD, &q_bytes);
- gettimeofday(&kerb_time, NULL);
- q_n++;
- max_q_n = max(max_q_n, q_n);
- n_packets++;
- klog(L_NET_INFO,
- "q_byt %d, q_n %d, rd_byt %d, mx_q_b %d, mx_q_n %d, n_pkt %d",
- q_bytes, q_n, n, max_q_bytes, max_q_n, n_packets, 0);
- max_q_bytes = max(max_q_bytes, q_bytes);
- if (!q_bytes)
- q_n = 0; /* reset consecutive packets */
- kerberos(&from, pkt);
- } else
- klog(L_NET_ERR,
- "%s: bad recvfrom n = %d errno = %d", progname, n, errno, 0);
+ int ret;
+ fd_set readfds;
+ struct timeval tv;
+ int maxfd = 0;
+ struct descr *n, *minfree;
+ int accepted; /* accept at most one socket per `round' */
+
+ FD_ZERO(&readfds);
+ gettimeofday(&tv, NULL);
+ maxfd = 0;
+ minfree = NULL;
+ /* Remove expired TCP sockets, and add all other
+ to the set we are selecting on */
+ for(n = fds; n < fds + nfds; n++){
+ if(n->s >= 0 && n->timeout && tv.tv_sec > n->timeout){
+ kerb_err_reply(n->s, NULL, KERB_ERR_TIMEOUT, "Timeout");
+ close(n->s);
+ n->s = -1;
+ }
+ if(n->s < 0){
+ if(minfree == NULL) minfree = n;
+ continue;
+ }
+ FD_SET(n->s, &readfds);
+ maxfd = max(maxfd, n->s);
+ }
+ /* add more space for sockets */
+ if(minfree == NULL){
+ int i = nfds;
+ struct descr *new;
+ nfds *=2;
+ new = realloc(fds, sizeof(struct descr) * nfds);
+ if(new){
+ fds = new;
+ minfree = fds + i;
+ for(; i < nfds; i++) fds[i].s = -1;
+ }
+ }
+ ret = select(maxfd + 1, &readfds, 0, 0, 0);
+ accepted = 0;
+ for (n = fds; n < fds + nfds; n++){
+ if(n->s < 0) continue;
+ if (FD_ISSET(n->s, &readfds)){
+ if(n->type == SOCK_STREAM && n->timeout == 0){
+ /* add accepted socket to list of sockets we are
+ selecting on */
+ int s;
+ if(accepted) continue;
+ accepted = 1;
+ s = accept(n->s, NULL, 0);
+ if(minfree == NULL){
+ kerb_err_reply(s, NULL, KFAILURE, "Out of memory");
+ close(s);
+ }else{
+ minfree->s = s;
+ minfree->type = SOCK_STREAM;
+ gettimeofday(&tv, NULL);
+ minfree->timeout = tv.tv_sec + 4; /* XXX */
+ minfree->buf.length = 0;
+ memcpy(&minfree->addr, &n->addr, sizeof(minfree->addr));
+ }
+ }else
+ read_socket(n);
+ }
+ }
}
}