Import an updated revision of the MIT kprop program for distributing

kerberos databases to slave servers.

NOTE: This method was abandoned by MIT long ago, this code is close to
      garbage,  but it is slightly more secure than using rdist.
      There is no documentation available on how to use it, and
      it should -not- be built by default.

Obtained from:	MIT Project Athena
This commit is contained in:
Paul Traina 1995-08-02 22:11:44 +00:00
parent e0deda6676
commit fa84c42025
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor-crypto/eBones/dist/; revision=9864
6 changed files with 1296 additions and 0 deletions

11
eBones/kprop/Makefile Normal file
View File

@ -0,0 +1,11 @@
# From: @(#)Makefile 5.1 (Berkeley) 6/25/90
# $Id$
PROG= kprop
CFLAGS+=-I${.CURDIR}/../include
DPADD= ${LIBKRB} ${LIBDES}
LDADD= -L${KRBOBJDIR} -lkrb -L${DESOBJDIR} -ldes
BINDIR= /usr/sbin
NOMAN= noman
.include <bsd.prog.mk>

604
eBones/kprop/kprop.c Normal file
View File

@ -0,0 +1,604 @@
/*
*
* Copyright 1987 by the Massachusetts Institute of Technology.
*
* For copying and distribution information,
* please see the file <mit-copyright.h>.
*
* $Revision: 4.7 $
* $Date: 92/11/10 23:01:06 $
* $State: Exp $
* $Source: /afs/net.mit.edu/project/krb4/src/slave/RCS/kprop.c,v $
* $Author: tytso $
* $Locker: $
*
* $Log: kprop.c,v $
* Revision 4.7 92/11/10 23:01:06 tytso
* Removed incompatible #include
*
* Revision 4.6 91/02/28 22:49:34 probe
* Fixed header file inclusion
*
* Revision 4.5 90/03/20 15:37:57 jon
* Stop kpropd port number from being bashed (static buffers)
* Programmer: jtkohl
* Auditor: jon
*
* Revision 4.4 90/01/02 13:42:40 jtkohl
* add back in accidentally deleted $ in rcsid string
*
* Revision 4.3 89/12/30 21:22:27 qjb
* Added #define MAXHOSTNAMELEN if not already defined for the benifit
* of Unixes that don't have this variable in sys/param.h.
*
* Revision 4.2 89/03/23 10:23:43 jtkohl
* fix misuse of mkstemp to use mktemp
* NOENCRYPTION changes
*
* Revision 4.1 89/01/24 20:35:17 root
* name change
*
* Revision 4.0 89/01/24 18:44:38 wesommer
* Original version; programmer: wesommer
* auditor: jon.
*
* Revision 4.4 88/01/08 18:05:21 jon
* formating changes and rcs header info
*
*
*/
#ifndef lint
static char rcsid_kprop_c[] =
"$Id: kprop.c,v 4.7 92/11/10 23:01:06 tytso Exp $";
#endif lint
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/file.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <netdb.h>
#include <krb.h>
#include <des.h>
#include "kprop.h"
/* for those broken Unixes without this defined... should be in sys/param.h */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
static char kprop_version[KPROP_PROT_VERSION_LEN] = KPROP_PROT_VERSION;
int debug = 0;
char my_realm[REALM_SZ];
int princ_data_size = 3 * sizeof(long) + 3 * sizeof(unsigned char);
short transfer_mode, net_transfer_mode;
int force_flag;
static char ok[] = ".dump_ok";
extern char *krb_get_phost(char *);
struct slave_host {
u_long net_addr;
char *name;
char *instance;
char *realm;
int not_time_yet;
int succeeded;
struct slave_host *next;
};
main(argc, argv)
int argc;
char *argv[];
{
int fd, i;
char *floc, *floc_ok;
char *fslv;
struct stat stbuf, stbuf_ok;
long l_init, l_final;
char *pc;
int l_diff, prop_to_slaves(), get_slaves();
static struct slave_host *slave_host_list = NULL;
struct slave_host *sh;
transfer_mode = KPROP_TRANSFER_PRIVATE;
time(&l_init);
pc = ctime(&l_init);
pc[strlen(pc) - 1] = '\0';
printf("\nStart slave propagation: %s\n", pc);
floc = (char *) NULL;
fslv = (char *) NULL;
if (krb_get_lrealm(my_realm,1) != KSUCCESS)
Death ("Getting my kerberos realm. Check krb.conf");
for (i = 1; i < argc; i++)
switch (argv[i][0]) {
case '-':
if (strcmp (argv[i], "-private") == 0)
transfer_mode = KPROP_TRANSFER_PRIVATE;
#ifdef not_safe_yet
else if (strcmp (argv[i], "-safe") == 0)
transfer_mode = KPROP_TRANSFER_SAFE;
else if (strcmp (argv[i], "-clear") == 0)
transfer_mode = KPROP_TRANSFER_CLEAR;
#endif
else if (strcmp (argv[i], "-realm") == 0) {
i++;
if (i < argc)
strcpy(my_realm, argv[i]);
else
goto usage;
} else if (strcmp (argv[i], "-force") == 0)
force_flag++;
else {
fprintf (stderr, "kprop: unknown control argument %s.\n",
argv[i]);
exit (1);
}
break;
default:
/* positional arguments are marginal at best ... */
if (floc == (char *) NULL)
floc = argv[i];
else {
if (fslv == (char *) NULL)
fslv = argv[i];
else {
usage:
/* already got floc and fslv, what is this? */
fprintf(stderr,
"\nUsage: kprop [-force] [-realm realm] [-private|-safe|-clear] data_file slaves_file\n\n");
exit(1);
}
}
}
if ((floc == (char *)NULL) || (fslv == (char *)NULL))
goto usage;
if ((floc_ok = (char *) malloc(strlen(floc) + strlen(ok) + 1))
== NULL) {
Death(floc);
}
strcat(strcpy(floc_ok, floc), ok);
if ((fd = open(floc, O_RDONLY)) < 0) {
Death(floc);
}
if (flock(fd, LOCK_EX | LOCK_NB)) {
Death(floc);
}
if (stat(floc, &stbuf)) {
Death(floc);
}
if (stat(floc_ok, &stbuf_ok)) {
Death(floc_ok);
}
if (stbuf.st_mtime > stbuf_ok.st_mtime) {
fprintf(stderr, "kprop: '%s' more recent than '%s'.\n",
floc, floc_ok);
exit(1);
}
if (!get_slaves(&slave_host_list, fslv, stbuf_ok.st_mtime)) {
fprintf(stderr,
"kprop: can't read slave host file '%s'.\n", fslv);
exit(1);
}
#ifdef KPROP_DBG
{
struct slave_host *sh;
int i;
fprintf(stderr, "\n\n");
fflush(stderr);
for (sh = slave_host_list; sh; sh = sh->next) {
fprintf(stderr, "slave %d: %s, %s", i++, sh->name,
inet_ntoa(sh->net_addr));
fflush(stderr);
}
}
#endif /* KPROP_DBG */
if (!prop_to_slaves(slave_host_list, fd, fslv)) {
fprintf(stderr,
"kprop: propagation failed.\n");
exit(1);
}
if (flock(fd, LOCK_UN)) {
Death(floc);
}
fprintf(stderr, "\n\n");
for (sh = slave_host_list; sh; sh = sh->next) {
fprintf(stderr, "%s:\t\t%s\n", sh->name,
(sh->not_time_yet? "Not time yet" : (sh->succeeded ? "Succeeded" : "FAILED")));
}
time(&l_final);
l_diff = l_final - l_init;
printf("propagation finished, %d:%02d:%02d elapsed\n",
l_diff / 3600, (l_diff % 3600) / 60, l_diff % 60);
exit(0);
}
Death(s)
char *s;
{
fprintf(stderr, "kprop: ");
perror(s);
exit(1);
}
/* The master -> slave protocol looks like this:
1) 8 byte version string
2) 2 bytes of "transfer mode" (net byte order of course)
3) ticket/authentication send by sendauth
4) 4 bytes of "block" length (u_long)
5) data
4 and 5 repeat til EOF ...
*/
int prop_to_slaves(sl, fd, fslv)
struct slave_host *sl;
int fd;
char *fslv;
{
char buf[KPROP_BUFSIZ];
char obuf[KPROP_BUFSIZ + 64 /* leave room for private msg overhead */ ];
struct servent *sp;
struct sockaddr_in sin, my_sin;
int i, n, s;
struct slave_host *cs; /* current slave */
char path[256], my_host_name[MAXHOSTNAMELEN], *p_my_host_name;
char kprop_service_instance[INST_SZ];
char *pc;
u_long cksum, get_data_checksum();
u_long length, nlength;
long kerror;
KTEXT_ST ticket;
CREDENTIALS cred;
MSG_DAT msg_dat;
static char tkstring[] = "/tmp/kproptktXXXXXX";
Key_schedule session_sched;
(void) mktemp(tkstring);
krb_set_tkt_string(tkstring);
if ((sp = getservbyname("krb_prop", "tcp")) == 0) {
fprintf(stderr, "tcp/krb_prop: service unknown.\n");
exit(1);
}
bzero(&sin, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_port = sp->s_port;
strcpy(path, fslv);
if (pc = rindex(path, '/')) {
pc += 1;
} else {
pc = path;
}
for (i = 0; i < 5; i++) { /* try each slave five times max */
for (cs = sl; cs; cs = cs->next) {
if (!cs->succeeded) {
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("kprop: socket");
exit(1);
}
bcopy(&cs->net_addr, &sin.sin_addr,
sizeof cs->net_addr);
if (connect(s, (struct sockaddr *) &sin, sizeof sin) < 0) {
fprintf(stderr, "%s: ", cs->name);
perror("connect");
close(s);
continue; /*** NEXT SLAVE ***/
}
/* for krb_mk_{priv, safe} */
bzero (&my_sin, sizeof my_sin);
n = sizeof my_sin;
if (getsockname (s, (struct sockaddr *) &my_sin, &n) != 0) {
fprintf (stderr, "kprop: can't get socketname.");
perror ("getsockname");
close (s);
continue; /*** NEXT SLAVE ***/
}
if (n != sizeof (my_sin)) {
fprintf (stderr, "kprop: can't get socketname. len");
close (s);
continue; /*** NEXT SLAVE ***/
}
/* Get ticket */
kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME,
cs->instance, cs->realm, (u_long) 0);
/* if ticket has expired try to get a new one, but
* first get a TGT ...
*/
if (kerror != MK_AP_OK) {
if (gethostname (my_host_name, sizeof(my_host_name)) != 0) {
fprintf (stderr, "%s:", cs->name);
perror ("getting my hostname");
close (s);
break; /* next one can't work either! */
}
/* get canonical kerberos service instance name */
p_my_host_name = krb_get_phost (my_host_name);
/* copy it to make sure gethostbyname static doesn't
* screw us. */
strcpy (kprop_service_instance, p_my_host_name);
kerror = krb_get_svc_in_tkt (KPROP_SERVICE_NAME,
#if 0
kprop_service_instance,
#else
KRB_MASTER,
#endif
my_realm,
TGT_SERVICE_NAME,
my_realm,
96,
KPROP_SRVTAB);
if (kerror != INTK_OK) {
fprintf (stderr,
"%s: %s. While getting initial ticket\n",
cs->name, krb_err_txt[kerror]);
close (s);
goto punt;
}
kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME,
cs->instance, cs->realm, (u_long) 0);
}
if (kerror != MK_AP_OK) {
fprintf (stderr, "%s: %s. Calling krb_mk_req.",
cs->name, krb_err_txt[kerror]);
close (s);
continue; /*** NEXT SLAVE ***/
}
if (write(s, kprop_version, sizeof(kprop_version))
!= sizeof(kprop_version)) {
fprintf (stderr, "%s: ", cs->name);
perror ("write (version) error");
close (s);
continue; /*** NEXT SLAVE ***/
}
net_transfer_mode = htons (transfer_mode);
if (write(s, &net_transfer_mode, sizeof(net_transfer_mode))
!= sizeof(net_transfer_mode)) {
fprintf (stderr, "%s: ", cs->name);
perror ("write (transfer_mode) error");
close (s);
continue; /*** NEXT SLAVE ***/
}
kerror = krb_get_cred (KPROP_SERVICE_NAME, cs->instance,
cs->realm, &cred);
if (kerror != KSUCCESS) {
fprintf (stderr, "%s: %s. Getting session key.",
cs->name, krb_err_txt[kerror]);
close (s);
continue; /*** NEXT SLAVE ***/
}
#ifdef NOENCRYPTION
bzero((char *)session_sched, sizeof(session_sched));
#else
if (key_sched (cred.session, session_sched)) {
fprintf (stderr, "%s: can't make key schedule.",
cs->name);
close (s);
continue; /*** NEXT SLAVE ***/
}
#endif
/* SAFE (quad_cksum) and CLEAR are just not good enough */
cksum = 0;
#ifdef not_working_yet
if (transfer_mode != KPROP_TRANSFER_PRIVATE) {
cksum = get_data_checksum(fd, session_sched);
lseek(fd, 0L, 0);
}
else
#endif
{
struct stat st;
fstat (fd, &st);
cksum = st.st_size;
}
kerror = krb_sendauth(KOPT_DO_MUTUAL,
s,
&ticket,
KPROP_SERVICE_NAME,
cs->instance,
cs->realm,
cksum,
&msg_dat,
&cred,
session_sched,
&my_sin,
&sin,
KPROP_PROT_VERSION);
if (kerror != KSUCCESS) {
fprintf (stderr, "%s: %s. Calling krb_sendauth.",
cs->name, krb_err_txt[kerror]);
close (s);
continue; /*** NEXT SLAVE ***/
}
while (n = read(fd, buf, sizeof buf)) {
if (n < 0) {
perror("input file read error");
exit(1);
}
switch (transfer_mode) {
case KPROP_TRANSFER_PRIVATE:
case KPROP_TRANSFER_SAFE:
if (transfer_mode == KPROP_TRANSFER_PRIVATE)
length = krb_mk_priv (buf, obuf, n,
session_sched, cred.session,
&my_sin, &sin);
else
length = krb_mk_safe (buf, obuf, n,
cred.session,
&my_sin, &sin);
if (length == -1) {
fprintf (stderr, "%s: %s failed.",
cs->name,
(transfer_mode == KPROP_TRANSFER_PRIVATE)
? "krb_rd_priv" : "krb_rd_safe");
close (s);
continue; /*** NEXT SLAVE ***/
}
nlength = htonl(length);
if (write(s, &nlength, sizeof nlength)
!= sizeof nlength) {
fprintf (stderr, "%s: ", cs->name);
perror ("write error");
close (s);
continue; /*** NEXT SLAVE ***/
}
if (write(s, obuf, length) != length) {
fprintf(stderr, "%s: ", cs->name);
perror("write error");
close(s);
continue; /*** NEXT SLAVE ***/
}
break;
case KPROP_TRANSFER_CLEAR:
if (write(s, buf, n) != n) {
fprintf(stderr, "%s: ", cs->name);
perror("write error");
close(s);
continue; /*** NEXT SLAVE ***/
}
break;
}
}
close(s);
cs->succeeded = 1;
fprintf(stderr, "%s: success.\n", cs->name);
strcat(strcpy(pc, cs->name), "-last-prop");
close(creat(path, 0600));
}
}
}
punt:
dest_tkt();
for (cs = sl; cs; cs = cs->next) {
if (!cs->succeeded)
return (0); /* didn't get this slave */
}
return (1);
}
int get_slaves(psl, file, ok_mtime)
struct slave_host **psl;
char *file;
time_t ok_mtime;
{
FILE *fin;
char namebuf[128], *inst;
char *pc;
struct hostent *host;
struct slave_host **th;
char path[256];
char *ppath;
struct stat stbuf;
if ((fin = fopen(file, "r")) == NULL) {
fprintf(stderr, "Can't open slave host file, '%s'.\n", file);
exit(-1);
}
strcpy(path, file);
if (ppath = rindex(path, '/')) {
ppath += 1;
} else {
ppath = path;
}
for (th = psl; fgets(namebuf, sizeof namebuf, fin); th = &(*th)->next) {
if (pc = index(namebuf, '\n')) {
*pc = '\0';
} else {
fprintf(stderr, "Host name too long (>= %d chars) in '%s'.\n",
sizeof namebuf, file);
exit(-1);
}
host = gethostbyname(namebuf);
if (host == NULL) {
fprintf(stderr, "Unknown host '%s' in '%s'.\n", namebuf, file);
exit(-1);
}
(*th) = (struct slave_host *) malloc(sizeof(struct slave_host));
if (!*th) {
fprintf(stderr, "No memory reading host list from '%s'.\n",
file);
exit(-1);
}
(*th)->name = malloc(strlen(namebuf) + 1);
if (!(*th)->name) {
fprintf(stderr, "No memory reading host list from '%s'.\n",
file);
exit(-1);
}
/* get kerberos cannonical instance name */
strcpy((*th)->name, namebuf);
inst = krb_get_phost ((*th)->name);
(*th)->instance = malloc(strlen(inst) + 1);
if (!(*th)->instance) {
fprintf(stderr, "No memory reading host list from '%s'.\n",
file);
exit(-1);
}
strcpy((*th)->instance, inst);
/* what a concept, slave servers in different realms! */
(*th)->realm = my_realm;
(*th)->net_addr = *(u_long *) host->h_addr;
(*th)->succeeded = 0;
(*th)->next = NULL;
strcat(strcpy(ppath, (*th)->name), "-last-prop");
if (!force_flag && !stat(path, &stbuf) && stbuf.st_mtime > ok_mtime) {
(*th)->not_time_yet = 1;
(*th)->succeeded = 1; /* no change since last success */
}
}
fclose(fin);
return (1);
}
#ifdef doesnt_work_yet
u_long get_data_checksum(fd, key_sched)
int fd;
Key_schedule key_sched;
{
unsigned long cksum = 0;
unsigned long cbc_cksum();
int n;
char buf[BUFSIZ];
long obuf[2];
while (n = read(fd, buf, sizeof buf)) {
if (n < 0) {
fprintf(stderr, "Input data file read error: ");
perror("read");
exit(1);
}
cksum = cbc_cksum(buf, obuf, n, key_sched, key_sched);
}
return cksum;
}
#endif

33
eBones/kprop/kprop.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright 1987 by the Massachusetts Institute of Technology.
*
* For copying and distribution information,
* please see the file <mit-copyright.h>.
*
* $Revision: 4.1 $
* $Date: 92/10/23 15:45:13 $
* $State: Exp $
* $Source: /afs/net.mit.edu/project/krb4/src/slave/RCS/kprop.h,v $
* $Author: tytso $
* $Locker: $
*
* $Log: kprop.h,v $
* Revision 4.1 92/10/23 15:45:13 tytso
* Change the location of KPROP_KDBUTIL to be /kerberos/bin/kdb_util.
*
* Revision 4.0 89/01/24 18:44:46 wesommer
* Original version; programmer: wesommer
* auditor: jon
*
*/
#define KPROP_SERVICE_NAME "rcmd"
#define KPROP_SRVTAB "/etc/kerberosIV/srvtab"
#define TGT_SERVICE_NAME "krbtgt"
#define KPROP_PROT_VERSION_LEN 8
#define KPROP_PROT_VERSION "kprop01"
#define KPROP_TRANSFER_PRIVATE 1
#define KPROP_TRANSFER_SAFE 2
#define KPROP_TRANSFER_CLEAR 3
#define KPROP_BUFSIZ 32768
#define KPROP_KDB_UTIL "/usr/sbin/kdb_util"

View File

@ -0,0 +1,11 @@
# From: @(#)Makefile 5.1 (Berkeley) 6/25/90
# $Id$
PROG= kprop
CFLAGS+=-I${.CURDIR}/../include
DPADD= ${LIBKRB} ${LIBDES}
LDADD= -L${KRBOBJDIR} -lkrb -L${DESOBJDIR} -ldes
BINDIR= /usr/sbin
NOMAN= noman
.include <bsd.prog.mk>

View File

@ -0,0 +1,604 @@
/*
*
* Copyright 1987 by the Massachusetts Institute of Technology.
*
* For copying and distribution information,
* please see the file <mit-copyright.h>.
*
* $Revision: 4.7 $
* $Date: 92/11/10 23:01:06 $
* $State: Exp $
* $Source: /afs/net.mit.edu/project/krb4/src/slave/RCS/kprop.c,v $
* $Author: tytso $
* $Locker: $
*
* $Log: kprop.c,v $
* Revision 4.7 92/11/10 23:01:06 tytso
* Removed incompatible #include
*
* Revision 4.6 91/02/28 22:49:34 probe
* Fixed header file inclusion
*
* Revision 4.5 90/03/20 15:37:57 jon
* Stop kpropd port number from being bashed (static buffers)
* Programmer: jtkohl
* Auditor: jon
*
* Revision 4.4 90/01/02 13:42:40 jtkohl
* add back in accidentally deleted $ in rcsid string
*
* Revision 4.3 89/12/30 21:22:27 qjb
* Added #define MAXHOSTNAMELEN if not already defined for the benifit
* of Unixes that don't have this variable in sys/param.h.
*
* Revision 4.2 89/03/23 10:23:43 jtkohl
* fix misuse of mkstemp to use mktemp
* NOENCRYPTION changes
*
* Revision 4.1 89/01/24 20:35:17 root
* name change
*
* Revision 4.0 89/01/24 18:44:38 wesommer
* Original version; programmer: wesommer
* auditor: jon.
*
* Revision 4.4 88/01/08 18:05:21 jon
* formating changes and rcs header info
*
*
*/
#ifndef lint
static char rcsid_kprop_c[] =
"$Id: kprop.c,v 4.7 92/11/10 23:01:06 tytso Exp $";
#endif lint
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/file.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <netdb.h>
#include <krb.h>
#include <des.h>
#include "kprop.h"
/* for those broken Unixes without this defined... should be in sys/param.h */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
static char kprop_version[KPROP_PROT_VERSION_LEN] = KPROP_PROT_VERSION;
int debug = 0;
char my_realm[REALM_SZ];
int princ_data_size = 3 * sizeof(long) + 3 * sizeof(unsigned char);
short transfer_mode, net_transfer_mode;
int force_flag;
static char ok[] = ".dump_ok";
extern char *krb_get_phost(char *);
struct slave_host {
u_long net_addr;
char *name;
char *instance;
char *realm;
int not_time_yet;
int succeeded;
struct slave_host *next;
};
main(argc, argv)
int argc;
char *argv[];
{
int fd, i;
char *floc, *floc_ok;
char *fslv;
struct stat stbuf, stbuf_ok;
long l_init, l_final;
char *pc;
int l_diff, prop_to_slaves(), get_slaves();
static struct slave_host *slave_host_list = NULL;
struct slave_host *sh;
transfer_mode = KPROP_TRANSFER_PRIVATE;
time(&l_init);
pc = ctime(&l_init);
pc[strlen(pc) - 1] = '\0';
printf("\nStart slave propagation: %s\n", pc);
floc = (char *) NULL;
fslv = (char *) NULL;
if (krb_get_lrealm(my_realm,1) != KSUCCESS)
Death ("Getting my kerberos realm. Check krb.conf");
for (i = 1; i < argc; i++)
switch (argv[i][0]) {
case '-':
if (strcmp (argv[i], "-private") == 0)
transfer_mode = KPROP_TRANSFER_PRIVATE;
#ifdef not_safe_yet
else if (strcmp (argv[i], "-safe") == 0)
transfer_mode = KPROP_TRANSFER_SAFE;
else if (strcmp (argv[i], "-clear") == 0)
transfer_mode = KPROP_TRANSFER_CLEAR;
#endif
else if (strcmp (argv[i], "-realm") == 0) {
i++;
if (i < argc)
strcpy(my_realm, argv[i]);
else
goto usage;
} else if (strcmp (argv[i], "-force") == 0)
force_flag++;
else {
fprintf (stderr, "kprop: unknown control argument %s.\n",
argv[i]);
exit (1);
}
break;
default:
/* positional arguments are marginal at best ... */
if (floc == (char *) NULL)
floc = argv[i];
else {
if (fslv == (char *) NULL)
fslv = argv[i];
else {
usage:
/* already got floc and fslv, what is this? */
fprintf(stderr,
"\nUsage: kprop [-force] [-realm realm] [-private|-safe|-clear] data_file slaves_file\n\n");
exit(1);
}
}
}
if ((floc == (char *)NULL) || (fslv == (char *)NULL))
goto usage;
if ((floc_ok = (char *) malloc(strlen(floc) + strlen(ok) + 1))
== NULL) {
Death(floc);
}
strcat(strcpy(floc_ok, floc), ok);
if ((fd = open(floc, O_RDONLY)) < 0) {
Death(floc);
}
if (flock(fd, LOCK_EX | LOCK_NB)) {
Death(floc);
}
if (stat(floc, &stbuf)) {
Death(floc);
}
if (stat(floc_ok, &stbuf_ok)) {
Death(floc_ok);
}
if (stbuf.st_mtime > stbuf_ok.st_mtime) {
fprintf(stderr, "kprop: '%s' more recent than '%s'.\n",
floc, floc_ok);
exit(1);
}
if (!get_slaves(&slave_host_list, fslv, stbuf_ok.st_mtime)) {
fprintf(stderr,
"kprop: can't read slave host file '%s'.\n", fslv);
exit(1);
}
#ifdef KPROP_DBG
{
struct slave_host *sh;
int i;
fprintf(stderr, "\n\n");
fflush(stderr);
for (sh = slave_host_list; sh; sh = sh->next) {
fprintf(stderr, "slave %d: %s, %s", i++, sh->name,
inet_ntoa(sh->net_addr));
fflush(stderr);
}
}
#endif /* KPROP_DBG */
if (!prop_to_slaves(slave_host_list, fd, fslv)) {
fprintf(stderr,
"kprop: propagation failed.\n");
exit(1);
}
if (flock(fd, LOCK_UN)) {
Death(floc);
}
fprintf(stderr, "\n\n");
for (sh = slave_host_list; sh; sh = sh->next) {
fprintf(stderr, "%s:\t\t%s\n", sh->name,
(sh->not_time_yet? "Not time yet" : (sh->succeeded ? "Succeeded" : "FAILED")));
}
time(&l_final);
l_diff = l_final - l_init;
printf("propagation finished, %d:%02d:%02d elapsed\n",
l_diff / 3600, (l_diff % 3600) / 60, l_diff % 60);
exit(0);
}
Death(s)
char *s;
{
fprintf(stderr, "kprop: ");
perror(s);
exit(1);
}
/* The master -> slave protocol looks like this:
1) 8 byte version string
2) 2 bytes of "transfer mode" (net byte order of course)
3) ticket/authentication send by sendauth
4) 4 bytes of "block" length (u_long)
5) data
4 and 5 repeat til EOF ...
*/
int prop_to_slaves(sl, fd, fslv)
struct slave_host *sl;
int fd;
char *fslv;
{
char buf[KPROP_BUFSIZ];
char obuf[KPROP_BUFSIZ + 64 /* leave room for private msg overhead */ ];
struct servent *sp;
struct sockaddr_in sin, my_sin;
int i, n, s;
struct slave_host *cs; /* current slave */
char path[256], my_host_name[MAXHOSTNAMELEN], *p_my_host_name;
char kprop_service_instance[INST_SZ];
char *pc;
u_long cksum, get_data_checksum();
u_long length, nlength;
long kerror;
KTEXT_ST ticket;
CREDENTIALS cred;
MSG_DAT msg_dat;
static char tkstring[] = "/tmp/kproptktXXXXXX";
Key_schedule session_sched;
(void) mktemp(tkstring);
krb_set_tkt_string(tkstring);
if ((sp = getservbyname("krb_prop", "tcp")) == 0) {
fprintf(stderr, "tcp/krb_prop: service unknown.\n");
exit(1);
}
bzero(&sin, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_port = sp->s_port;
strcpy(path, fslv);
if (pc = rindex(path, '/')) {
pc += 1;
} else {
pc = path;
}
for (i = 0; i < 5; i++) { /* try each slave five times max */
for (cs = sl; cs; cs = cs->next) {
if (!cs->succeeded) {
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("kprop: socket");
exit(1);
}
bcopy(&cs->net_addr, &sin.sin_addr,
sizeof cs->net_addr);
if (connect(s, (struct sockaddr *) &sin, sizeof sin) < 0) {
fprintf(stderr, "%s: ", cs->name);
perror("connect");
close(s);
continue; /*** NEXT SLAVE ***/
}
/* for krb_mk_{priv, safe} */
bzero (&my_sin, sizeof my_sin);
n = sizeof my_sin;
if (getsockname (s, (struct sockaddr *) &my_sin, &n) != 0) {
fprintf (stderr, "kprop: can't get socketname.");
perror ("getsockname");
close (s);
continue; /*** NEXT SLAVE ***/
}
if (n != sizeof (my_sin)) {
fprintf (stderr, "kprop: can't get socketname. len");
close (s);
continue; /*** NEXT SLAVE ***/
}
/* Get ticket */
kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME,
cs->instance, cs->realm, (u_long) 0);
/* if ticket has expired try to get a new one, but
* first get a TGT ...
*/
if (kerror != MK_AP_OK) {
if (gethostname (my_host_name, sizeof(my_host_name)) != 0) {
fprintf (stderr, "%s:", cs->name);
perror ("getting my hostname");
close (s);
break; /* next one can't work either! */
}
/* get canonical kerberos service instance name */
p_my_host_name = krb_get_phost (my_host_name);
/* copy it to make sure gethostbyname static doesn't
* screw us. */
strcpy (kprop_service_instance, p_my_host_name);
kerror = krb_get_svc_in_tkt (KPROP_SERVICE_NAME,
#if 0
kprop_service_instance,
#else
KRB_MASTER,
#endif
my_realm,
TGT_SERVICE_NAME,
my_realm,
96,
KPROP_SRVTAB);
if (kerror != INTK_OK) {
fprintf (stderr,
"%s: %s. While getting initial ticket\n",
cs->name, krb_err_txt[kerror]);
close (s);
goto punt;
}
kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME,
cs->instance, cs->realm, (u_long) 0);
}
if (kerror != MK_AP_OK) {
fprintf (stderr, "%s: %s. Calling krb_mk_req.",
cs->name, krb_err_txt[kerror]);
close (s);
continue; /*** NEXT SLAVE ***/
}
if (write(s, kprop_version, sizeof(kprop_version))
!= sizeof(kprop_version)) {
fprintf (stderr, "%s: ", cs->name);
perror ("write (version) error");
close (s);
continue; /*** NEXT SLAVE ***/
}
net_transfer_mode = htons (transfer_mode);
if (write(s, &net_transfer_mode, sizeof(net_transfer_mode))
!= sizeof(net_transfer_mode)) {
fprintf (stderr, "%s: ", cs->name);
perror ("write (transfer_mode) error");
close (s);
continue; /*** NEXT SLAVE ***/
}
kerror = krb_get_cred (KPROP_SERVICE_NAME, cs->instance,
cs->realm, &cred);
if (kerror != KSUCCESS) {
fprintf (stderr, "%s: %s. Getting session key.",
cs->name, krb_err_txt[kerror]);
close (s);
continue; /*** NEXT SLAVE ***/
}
#ifdef NOENCRYPTION
bzero((char *)session_sched, sizeof(session_sched));
#else
if (key_sched (cred.session, session_sched)) {
fprintf (stderr, "%s: can't make key schedule.",
cs->name);
close (s);
continue; /*** NEXT SLAVE ***/
}
#endif
/* SAFE (quad_cksum) and CLEAR are just not good enough */
cksum = 0;
#ifdef not_working_yet
if (transfer_mode != KPROP_TRANSFER_PRIVATE) {
cksum = get_data_checksum(fd, session_sched);
lseek(fd, 0L, 0);
}
else
#endif
{
struct stat st;
fstat (fd, &st);
cksum = st.st_size;
}
kerror = krb_sendauth(KOPT_DO_MUTUAL,
s,
&ticket,
KPROP_SERVICE_NAME,
cs->instance,
cs->realm,
cksum,
&msg_dat,
&cred,
session_sched,
&my_sin,
&sin,
KPROP_PROT_VERSION);
if (kerror != KSUCCESS) {
fprintf (stderr, "%s: %s. Calling krb_sendauth.",
cs->name, krb_err_txt[kerror]);
close (s);
continue; /*** NEXT SLAVE ***/
}
while (n = read(fd, buf, sizeof buf)) {
if (n < 0) {
perror("input file read error");
exit(1);
}
switch (transfer_mode) {
case KPROP_TRANSFER_PRIVATE:
case KPROP_TRANSFER_SAFE:
if (transfer_mode == KPROP_TRANSFER_PRIVATE)
length = krb_mk_priv (buf, obuf, n,
session_sched, cred.session,
&my_sin, &sin);
else
length = krb_mk_safe (buf, obuf, n,
cred.session,
&my_sin, &sin);
if (length == -1) {
fprintf (stderr, "%s: %s failed.",
cs->name,
(transfer_mode == KPROP_TRANSFER_PRIVATE)
? "krb_rd_priv" : "krb_rd_safe");
close (s);
continue; /*** NEXT SLAVE ***/
}
nlength = htonl(length);
if (write(s, &nlength, sizeof nlength)
!= sizeof nlength) {
fprintf (stderr, "%s: ", cs->name);
perror ("write error");
close (s);
continue; /*** NEXT SLAVE ***/
}
if (write(s, obuf, length) != length) {
fprintf(stderr, "%s: ", cs->name);
perror("write error");
close(s);
continue; /*** NEXT SLAVE ***/
}
break;
case KPROP_TRANSFER_CLEAR:
if (write(s, buf, n) != n) {
fprintf(stderr, "%s: ", cs->name);
perror("write error");
close(s);
continue; /*** NEXT SLAVE ***/
}
break;
}
}
close(s);
cs->succeeded = 1;
fprintf(stderr, "%s: success.\n", cs->name);
strcat(strcpy(pc, cs->name), "-last-prop");
close(creat(path, 0600));
}
}
}
punt:
dest_tkt();
for (cs = sl; cs; cs = cs->next) {
if (!cs->succeeded)
return (0); /* didn't get this slave */
}
return (1);
}
int get_slaves(psl, file, ok_mtime)
struct slave_host **psl;
char *file;
time_t ok_mtime;
{
FILE *fin;
char namebuf[128], *inst;
char *pc;
struct hostent *host;
struct slave_host **th;
char path[256];
char *ppath;
struct stat stbuf;
if ((fin = fopen(file, "r")) == NULL) {
fprintf(stderr, "Can't open slave host file, '%s'.\n", file);
exit(-1);
}
strcpy(path, file);
if (ppath = rindex(path, '/')) {
ppath += 1;
} else {
ppath = path;
}
for (th = psl; fgets(namebuf, sizeof namebuf, fin); th = &(*th)->next) {
if (pc = index(namebuf, '\n')) {
*pc = '\0';
} else {
fprintf(stderr, "Host name too long (>= %d chars) in '%s'.\n",
sizeof namebuf, file);
exit(-1);
}
host = gethostbyname(namebuf);
if (host == NULL) {
fprintf(stderr, "Unknown host '%s' in '%s'.\n", namebuf, file);
exit(-1);
}
(*th) = (struct slave_host *) malloc(sizeof(struct slave_host));
if (!*th) {
fprintf(stderr, "No memory reading host list from '%s'.\n",
file);
exit(-1);
}
(*th)->name = malloc(strlen(namebuf) + 1);
if (!(*th)->name) {
fprintf(stderr, "No memory reading host list from '%s'.\n",
file);
exit(-1);
}
/* get kerberos cannonical instance name */
strcpy((*th)->name, namebuf);
inst = krb_get_phost ((*th)->name);
(*th)->instance = malloc(strlen(inst) + 1);
if (!(*th)->instance) {
fprintf(stderr, "No memory reading host list from '%s'.\n",
file);
exit(-1);
}
strcpy((*th)->instance, inst);
/* what a concept, slave servers in different realms! */
(*th)->realm = my_realm;
(*th)->net_addr = *(u_long *) host->h_addr;
(*th)->succeeded = 0;
(*th)->next = NULL;
strcat(strcpy(ppath, (*th)->name), "-last-prop");
if (!force_flag && !stat(path, &stbuf) && stbuf.st_mtime > ok_mtime) {
(*th)->not_time_yet = 1;
(*th)->succeeded = 1; /* no change since last success */
}
}
fclose(fin);
return (1);
}
#ifdef doesnt_work_yet
u_long get_data_checksum(fd, key_sched)
int fd;
Key_schedule key_sched;
{
unsigned long cksum = 0;
unsigned long cbc_cksum();
int n;
char buf[BUFSIZ];
long obuf[2];
while (n = read(fd, buf, sizeof buf)) {
if (n < 0) {
fprintf(stderr, "Input data file read error: ");
perror("read");
exit(1);
}
cksum = cbc_cksum(buf, obuf, n, key_sched, key_sched);
}
return cksum;
}
#endif

View File

@ -0,0 +1,33 @@
/*
* Copyright 1987 by the Massachusetts Institute of Technology.
*
* For copying and distribution information,
* please see the file <mit-copyright.h>.
*
* $Revision: 4.1 $
* $Date: 92/10/23 15:45:13 $
* $State: Exp $
* $Source: /afs/net.mit.edu/project/krb4/src/slave/RCS/kprop.h,v $
* $Author: tytso $
* $Locker: $
*
* $Log: kprop.h,v $
* Revision 4.1 92/10/23 15:45:13 tytso
* Change the location of KPROP_KDBUTIL to be /kerberos/bin/kdb_util.
*
* Revision 4.0 89/01/24 18:44:46 wesommer
* Original version; programmer: wesommer
* auditor: jon
*
*/
#define KPROP_SERVICE_NAME "rcmd"
#define KPROP_SRVTAB "/etc/kerberosIV/srvtab"
#define TGT_SERVICE_NAME "krbtgt"
#define KPROP_PROT_VERSION_LEN 8
#define KPROP_PROT_VERSION "kprop01"
#define KPROP_TRANSFER_PRIVATE 1
#define KPROP_TRANSFER_SAFE 2
#define KPROP_TRANSFER_CLEAR 3
#define KPROP_BUFSIZ 32768
#define KPROP_KDB_UTIL "/usr/sbin/kdb_util"