d79d4a7ced
- Get all functions prototyped or at least defined before use. - Make code compile (Mostly) clean with -Wall set - Start to reduce the degree to which DES aka libdes is built in. - get all functions to the same uniform standard of definition: int foo(a, b) int a; int *b; { : } - fix numerous bugs exposed by above processes. Note - this replaces the previous work which used an unpopular function definition style.
817 lines
21 KiB
C
817 lines
21 KiB
C
/*
|
|
* Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
|
|
* of Technology.
|
|
* For copying and distribution information, please see the file
|
|
* <Copyright.MIT>.
|
|
*
|
|
* from: kerberos.c,v 4.19 89/11/01 17:18:07 qjb Exp $
|
|
* $Id: kerberos.c,v 1.4 1995/07/18 16:37:51 mark Exp $
|
|
*/
|
|
|
|
#if 0
|
|
#ifndef lint
|
|
static char rcsid[] =
|
|
"$Id: kerberos.c,v 1.4 1995/07/18 16:37:51 mark Exp $";
|
|
#endif lint
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <signal.h>
|
|
#include <sgtty.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <sys/file.h>
|
|
#include <ctype.h>
|
|
|
|
#include <krb.h>
|
|
#include <des.h>
|
|
#include <klog.h>
|
|
#include <prot.h>
|
|
#include <krb_db.h>
|
|
#include <kdc.h>
|
|
|
|
void cr_err_reply(KTEXT pkt, char *pname, char *pinst, char *prealm,
|
|
u_long time_ws, u_long e, char *e_string);
|
|
void kerb_err_reply(struct sockaddr_in *client, KTEXT pkt, long err,
|
|
char *string);
|
|
void setup_disc(void);
|
|
void kerberos(struct sockaddr_in *client, KTEXT pkt);
|
|
int check_princ(char *p_name, char *instance, unsigned lifetime, Principal *p);
|
|
int set_tgtkey(char *r);
|
|
|
|
struct sockaddr_in s_in = {AF_INET};
|
|
int f;
|
|
|
|
/* XXX several files in libkdb know about this */
|
|
char *progname;
|
|
|
|
static Key_schedule master_key_schedule;
|
|
static C_Block master_key;
|
|
|
|
static struct timeval kerb_time;
|
|
static Principal a_name_data; /* for requesting user */
|
|
static Principal s_name_data; /* for services requested */
|
|
static C_Block 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 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 char local_realm[REALM_SZ];
|
|
|
|
/* statistics */
|
|
static long q_bytes; /* current bytes remaining in queue */
|
|
static long q_n; /* how many consecutive non-zero
|
|
* q_bytes */
|
|
static long max_q_bytes;
|
|
static long max_q_n;
|
|
static long n_auth_req;
|
|
static long n_appl_req;
|
|
static long n_packets;
|
|
|
|
static long max_age = -1;
|
|
static long pause_int = -1;
|
|
|
|
static void check_db_age();
|
|
static void hang();
|
|
|
|
/*
|
|
* Print usage message and exit.
|
|
*/
|
|
static void usage()
|
|
{
|
|
fprintf(stderr, "Usage: %s [-s] [-m] [-n] [-p pause_seconds]%s%s\n", progname,
|
|
" [-a max_age] [-l log_file] [-r realm]"
|
|
," [database_pathname]"
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int
|
|
main(argc, argv)
|
|
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;
|
|
|
|
progname = argv[0];
|
|
|
|
while ((c = getopt(argc, argv, "snmp:a:l:r:")) != EOF) {
|
|
switch(c) {
|
|
case 's':
|
|
/*
|
|
* Set parameters to slave server defaults.
|
|
*/
|
|
if (max_age == -1 && !nflag)
|
|
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. */
|
|
nflag++;
|
|
break;
|
|
case 'm':
|
|
mflag++; /* running manually; prompt for master key */
|
|
break;
|
|
case 'p':
|
|
/* Set pause interval. */
|
|
if (!isdigit(optarg[0]))
|
|
usage();
|
|
pause_int = atoi(optarg);
|
|
if ((pause_int < 5) || (pause_int > ONE_HOUR)) {
|
|
fprintf(stderr, "pause_int must be between 5 and 3600 seconds.\n");
|
|
usage();
|
|
}
|
|
break;
|
|
case 'a':
|
|
/* Set max age. */
|
|
if (!isdigit(optarg[0]))
|
|
usage();
|
|
max_age = atoi(optarg);
|
|
if ((max_age < ONE_HOUR) || (max_age > THREE_DAYS)) {
|
|
fprintf(stderr, "max_age must be between one hour and three days, in seconds\n");
|
|
usage();
|
|
}
|
|
break;
|
|
case 'l':
|
|
/* Set alternate log file */
|
|
lflag++;
|
|
log_file = optarg;
|
|
break;
|
|
case 'r':
|
|
/* Set realm name */
|
|
rflag++;
|
|
strcpy(local_realm, optarg);
|
|
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");
|
|
exit(1);
|
|
}
|
|
optind++;
|
|
}
|
|
|
|
if (optind != argc)
|
|
usage();
|
|
|
|
printf("Kerberos server starting\n");
|
|
|
|
if ((!nflag) && (max_age != -1))
|
|
printf("\tMaximum database age: %ld seconds\n", max_age);
|
|
if (pause_int != -1)
|
|
printf("\tSleep for %ld seconds on error\n", pause_int);
|
|
else
|
|
printf("\tSleep forever on error\n");
|
|
if (mflag)
|
|
printf("\tMaster key will be entered manually\n");
|
|
|
|
printf("\tLog file is %s\n", lflag ? log_file : KRBLOG);
|
|
|
|
if (lflag)
|
|
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);
|
|
}
|
|
s_in.sin_port = sp->s_port;
|
|
|
|
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);
|
|
|
|
if (bind(f, (struct sockaddr *) &s_in, S_AD_SZ) < 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);
|
|
} else {
|
|
klog(L_KRB_PERR,
|
|
"Kerberos db and cache init failed = %d ...exiting", n);
|
|
hang();
|
|
}
|
|
}
|
|
|
|
/* Make sure database isn't stale */
|
|
check_db_age();
|
|
|
|
/* 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);
|
|
}
|
|
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);
|
|
}
|
|
|
|
master_key_version = (u_char) kerror;
|
|
|
|
fprintf(stdout, "\nCurrent Kerberos master key version is %d\n",
|
|
master_key_version);
|
|
|
|
if (!rflag) {
|
|
/* Look up our local realm */
|
|
krb_get_lrealm(local_realm, 1);
|
|
}
|
|
fprintf(stdout, "Local realm: %s\n", local_realm);
|
|
fflush(stdout);
|
|
|
|
if (set_tgtkey(local_realm)) {
|
|
/* Ticket granting service unknown */
|
|
klog(L_KRB_PERR, "Ticket granting ticket service unknown");
|
|
fprintf(stderr, "Ticket granting ticket service unknown\n");
|
|
exit(1);
|
|
}
|
|
if (mflag) {
|
|
if ((child = fork()) != 0) {
|
|
printf("Kerberos started, PID=%d\n", child);
|
|
exit(0);
|
|
}
|
|
setup_disc();
|
|
}
|
|
/* receive loop */
|
|
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);
|
|
}
|
|
}
|
|
|
|
void
|
|
kerberos(client, pkt)
|
|
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;
|
|
C_Block key;
|
|
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++;
|
|
}
|
|
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) {
|
|
|
|
case AUTH_MSG_KDC_REQUEST:
|
|
{
|
|
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 = (u_long) (*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, lifetime,
|
|
&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(C_Block));
|
|
#else
|
|
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, 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, 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;
|
|
}
|
|
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(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, 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 = (u_long) (*ptr++);
|
|
|
|
service = ptr;
|
|
instance = ptr + strlen(service) + 1;
|
|
|
|
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(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,
|
|
(ad->life - ((kerb_time.tv_sec - ad->time_sec) / 300)));
|
|
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, DECRYPT);
|
|
/* construct and seal the ticket */
|
|
|
|
#ifdef NOENCRYPTION
|
|
bzero(session_key, sizeof(C_Block));
|
|
#else
|
|
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;
|
|
}
|
|
|
|
|
|
#ifdef notdef_DIE
|
|
case AUTH_MSG_DIE:
|
|
{
|
|
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);
|
|
}
|
|
#endif notdef_DIE
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* setup_disc
|
|
*
|
|
* disconnect all descriptors, remove ourself from the process
|
|
* group that spawned us.
|
|
*/
|
|
|
|
void
|
|
setup_disc()
|
|
{
|
|
|
|
int s;
|
|
|
|
for (s = 0; s < 3; s++) {
|
|
(void) close(s);
|
|
}
|
|
|
|
(void) open("/dev/null", 0);
|
|
(void) dup2(0, 1);
|
|
(void) dup2(0, 2);
|
|
|
|
s = open("/dev/tty", 2);
|
|
|
|
if (s >= 0) {
|
|
ioctl(s, TIOCNOTTY, (struct sgttyb *) 0);
|
|
(void) close(s);
|
|
}
|
|
(void) chdir("/tmp");
|
|
}
|
|
|
|
|
|
/*
|
|
* kerb_er_reply creates an error reply packet and sends it to the
|
|
* client.
|
|
*/
|
|
|
|
void
|
|
kerb_err_reply(client, pkt, err, string)
|
|
struct sockaddr_in *client;
|
|
KTEXT pkt;
|
|
long err;
|
|
char *string;
|
|
|
|
{
|
|
static KTEXT_ST e_pkt_st;
|
|
KTEXT e_pkt = &e_pkt_st;
|
|
static char e_msg[128];
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
/*
|
|
* Make sure that database isn't stale.
|
|
*
|
|
* Exit if it is; we don't want to tell lies.
|
|
*/
|
|
|
|
static void check_db_age()
|
|
{
|
|
long age;
|
|
|
|
if (max_age != -1) {
|
|
/* Requires existance of kerb_get_db_age() */
|
|
gettimeofday(&kerb_time, 0);
|
|
age = kerb_get_db_age();
|
|
if (age == 0) {
|
|
klog(L_KRB_PERR, "Database currently being updated!");
|
|
hang();
|
|
}
|
|
if ((age + max_age) < kerb_time.tv_sec) {
|
|
klog(L_KRB_PERR, "Database out of date!");
|
|
hang();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
check_princ(p_name, instance, lifetime, p)
|
|
char *p_name;
|
|
char *instance;
|
|
unsigned lifetime;
|
|
|
|
Principal *p;
|
|
{
|
|
static int n;
|
|
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!");
|
|
hang();
|
|
}
|
|
|
|
/*
|
|
* if more than one p_name, pick one, randomly create a session key,
|
|
* compute maximum lifetime, lookup authorizations if applicable,
|
|
* and stuff into cipher.
|
|
*/
|
|
if (n == 0) {
|
|
/* service unknown, log error, skip to next request */
|
|
lt = klog(L_ERR_UNK, "UNKNOWN \"%s\" \"%s\"", p_name,
|
|
instance, 0);
|
|
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);
|
|
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);
|
|
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);
|
|
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) {
|
|
/* service did expire, log it */
|
|
lt = klog(L_ERR_SEXP,
|
|
"EXPIRED \"%s\" \"%s\" %s", p->name, p->instance,
|
|
stime(&(p->exp_date)), 0);
|
|
return KERB_ERR_NAME_EXP;
|
|
}
|
|
/* ok is zero */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Set the key for krb_rd_req so we can check tgt */
|
|
int
|
|
set_tgtkey(r)
|
|
char *r; /* Realm for desired key */
|
|
{
|
|
int n;
|
|
static char lastrealm[REALM_SZ];
|
|
Principal p_st;
|
|
Principal *p = &p_st;
|
|
C_Block key;
|
|
|
|
if (!strcmp(lastrealm, r))
|
|
return (KSUCCESS);
|
|
|
|
log("Getting key for %s", r);
|
|
|
|
n = kerb_get_principal("krbtgt", 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, DECRYPT);
|
|
krb_set_key(key, 0);
|
|
strcpy(lastrealm, r);
|
|
return (KSUCCESS);
|
|
}
|
|
|
|
static void
|
|
hang()
|
|
{
|
|
if (pause_int == -1) {
|
|
klog(L_KRB_PERR, "Kerberos will pause so as not to loop init");
|
|
for (;;)
|
|
pause();
|
|
} else {
|
|
char buf[256];
|
|
sprintf(buf, "Kerberos will wait %ld 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");
|
|
exit(1);
|
|
}
|
|
}
|