diff options
Diffstat (limited to 'kerberosIV/kprop/kprop.c')
-rw-r--r-- | kerberosIV/kprop/kprop.c | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/kerberosIV/kprop/kprop.c b/kerberosIV/kprop/kprop.c new file mode 100644 index 00000000000..426a05afc23 --- /dev/null +++ b/kerberosIV/kprop/kprop.c @@ -0,0 +1,538 @@ +/* $Id: kprop.c,v 1.1 1995/12/14 06:52:49 tholo Exp $ */ + +/*- + * Copyright 1987 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, + * please see the file <mit-copyright.h>. + */ + +#include <slav_locl.h> +#include <kprop.h> +#include <sys/param.h> + +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"; + +struct slave_host { + u_long net_addr; + char *name; + char *instance; + char *realm; + int not_time_yet; + int succeeded; + struct slave_host *next; +}; + +static void +Death(char *s) +{ + fprintf(stderr, "kprop: "); + perror(s); + exit(1); +} + +static +int get_slaves(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 = strrchr(path, '/'))) { + ppath += 1; + } else { + ppath = path; + } + for (th = psl; fgets(namebuf, sizeof namebuf, fin); th = &(*th)->next) { + if ((pc = strchr(namebuf, '\n'))) { + *pc = '\0'; + } else { + fprintf(stderr, "Host name too long (>= %d chars) in '%s'.\n", + (int)(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); + } + bzero( (*th) , (sizeof(struct slave_host)) ); + (*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; + bcopy(host->h_addr, (char *)&(*th)->net_addr, sizeof(host->h_addr)); + (*th)->not_time_yet = 0; + (*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); +} + +/* 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 ... +*/ + +static int +prop_to_slaves(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; + u_long length, nlength; + long kerror; + KTEXT_ST ticket; + CREDENTIALS cred; + MSG_DAT msg_dat; + static char tkstring[] = "/tmp/kproptktXXXXXX"; + + des_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; + sin.sin_addr.s_addr = INADDR_ANY; + + strcpy(path, fslv); + if ((pc = strrchr(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 (des_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 ***/ + } + + lseek(fd, 0L, SEEK_SET); /* Rewind file before rereading it. */ + 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"); + unlink(path); + 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 +main(int argc, char **argv) +{ + int fd, i; + char *floc, *floc_ok; + char *fslv; + struct stat stbuf, stbuf_ok; + time_t l_init, l_final; + char *pc; + int l_diff; + 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); +} + +#ifdef doesnt_work_yet +u_long get_data_checksum(fd, key_sched) + int fd; + des_key_schedule key_sched; +{ + unsigned long cksum = 0; + 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 |