3 Copyright 1987, 1988 by the Student Information Processing Board
4 of the Massachusetts Institute of Technology
6 Permission to use, copy, modify, and distribute this software
7 and its documentation for any purpose and without fee is
8 hereby granted, provided that the above copyright notice
9 appear in all copies and that both that copyright notice and
10 this permission notice appear in supporting documentation,
11 and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
12 used in advertising or publicity pertaining to distribution
13 of the software without specific, written prior permission.
14 M.I.T. and the M.I.T. S.I.P.B. make no representations about
15 the suitability of this software for any purpose. It is
16 provided "as is" without express or implied warranty.
20 #include "slav_locl.h"
22 RCSID("$Id: kprop.c,v 1.37 1999/09/16 20:41:59 assar Exp $");
26 static char kprop_version[KPROP_PROT_VERSION_LEN] = KPROP_PROT_VERSION;
30 char my_realm[REALM_SZ];
31 int princ_data_size = 3 * sizeof(int32_t) + 3 * sizeof(unsigned char);
32 short transfer_mode, net_transfer_mode;
34 static char ok[] = ".dump_ok";
43 struct slave_host *next;
47 get_slaves(struct slave_host **psl,
53 char namebuf[128], *inst;
56 struct slave_host **th;
60 if ((fin = fopen(file, "r")) == NULL)
61 err (1, "open(%s)", file);
64 while(fgets(namebuf, sizeof(namebuf), fin)){
65 if ((pc = strchr(namebuf, '\n'))) {
68 if(strlen(namebuf) == sizeof(namebuf) - 1){
69 warnx ("Hostname too long (>= %d chars) in '%s'.",
70 (int) sizeof(namebuf), file);
72 if(fgets(namebuf, sizeof(namebuf), fin) == NULL)
74 }while(strchr(namebuf, '\n') == NULL);
78 if(namebuf[0] == 0 || namebuf[0] == '#')
80 host = gethostbyname(namebuf);
82 warnx ("Ignoring host '%s' in '%s': %s",
87 (*th) = (struct slave_host *) malloc(sizeof(struct slave_host));
89 errx (1, "No memory reading host list from '%s'.",
91 memset(*th, 0, sizeof(struct slave_host));
92 (*th)->name = strdup(namebuf);
93 if ((*th)->name == NULL)
94 errx (1, "No memory reading host list from '%s'.",
96 /* get kerberos cannonical instance name */
97 inst = krb_get_phost ((*th)->name);
98 (*th)->instance = strdup(inst);
99 if ((*th)->instance == NULL)
100 errx (1, "No memory reading host list from '%s'.",
102 /* what a concept, slave servers in different realms! */
103 (*th)->realm = my_realm;
104 memcpy(&(*th)->net_addr, host->h_addr, sizeof((*th)->net_addr));
105 (*th)->not_time_yet = 0;
106 (*th)->succeeded = 0;
108 asprintf(&last_prop_path, "%s%s-last-prop", dir_path, (*th)->name);
109 if (last_prop_path == NULL)
110 errx (1, "malloc failed");
112 && !stat(last_prop_path, &stbuf)
113 && stbuf.st_mtime > ok_mtime) {
114 (*th)->not_time_yet = 1;
115 (*th)->succeeded = 1; /* no change since last success */
117 free(last_prop_path);
124 /* The master -> slave protocol looks like this:
125 1) 8 byte version string
126 2) 2 bytes of "transfer mode" (net byte order of course)
127 3) ticket/authentication send by sendauth
128 4) 4 bytes of "block" length (u_int32_t)
131 4 and 5 repeat til EOF ...
135 prop_to_slaves(struct slave_host *sl,
137 const char *dir_path,
140 u_char buf[KPROP_BUFSIZ];
141 u_char obuf[KPROP_BUFSIZ + 64]; /* leave room for private msg overhead */
142 struct sockaddr_in sin, my_sin;
144 struct slave_host *cs; /* current slave */
145 char my_host_name[MaxHostNameLen], *p_my_host_name;
146 char kprop_service_instance[INST_SZ];
148 u_int32_t length, nlength;
153 static char tkstring[] = "/tmp/kproptktXXXXXX";
154 des_key_schedule session_sched;
155 char *last_prop_path;
157 close(mkstemp(tkstring));
158 krb_set_tkt_string(tkstring);
160 memset(&sin, 0, sizeof sin);
161 sin.sin_family = AF_INET;
162 sin.sin_port = k_getportbyname ("krb_prop", "tcp", htons(KPROP_PORT));
163 sin.sin_addr.s_addr = INADDR_ANY;
165 for (i = 0; i < 5; i++) { /* try each slave five times max */
166 for (cs = sl; cs; cs = cs->next) {
167 if (!cs->succeeded) {
168 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
170 memcpy(&sin.sin_addr, &cs->net_addr,
171 sizeof cs->net_addr);
173 if (connect(s, (struct sockaddr *) &sin, sizeof sin) < 0) {
174 warn ("connect(%s)", cs->name);
176 continue; /*** NEXT SLAVE ***/
179 /* for krb_mk_{priv, safe} */
180 memset(&my_sin, 0, sizeof my_sin);
182 if (getsockname (s, (struct sockaddr *) &my_sin, &n) != 0) {
183 warn ("getsockname(%s)", cs->name);
185 continue; /*** NEXT SLAVE ***/
187 if (n != sizeof (my_sin)) {
188 warnx ("can't get socketname %s length", cs->name);
190 continue; /*** NEXT SLAVE ***/
194 kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME,
195 cs->instance, cs->realm, (u_int32_t) 0);
196 /* if ticket has expired try to get a new one, but
197 * first get a TGT ...
199 if (kerror != MK_AP_OK) {
200 if (gethostname (my_host_name, sizeof(my_host_name)) != 0) {
201 warnx ("gethostname(%s): %s",
205 break; /* next one can't work either! */
207 /* get canonical kerberos service instance name */
208 p_my_host_name = krb_get_phost (my_host_name);
209 /* copy it to make sure gethostbyname static doesn't
211 strlcpy (kprop_service_instance,
214 kerror = krb_get_svc_in_tkt (KPROP_SERVICE_NAME,
216 kprop_service_instance,
221 KRB_TICKET_GRANTING_TICKET,
225 if (kerror != INTK_OK) {
226 warnx ("%s: %s. While getting initial ticket\n",
227 cs->name, krb_get_err_text(kerror));
231 kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME,
232 cs->instance, cs->realm,
235 if (kerror != MK_AP_OK) {
236 warnx ("%s: krb_mk_req: %s",
237 cs->name, krb_get_err_text(kerror));
239 continue; /*** NEXT SLAVE ***/
242 if (write(s, kprop_version, sizeof(kprop_version))
243 != sizeof(kprop_version)) {
244 warn ("%s", cs->name);
246 continue; /*** NEXT SLAVE ***/
249 net_transfer_mode = htons (transfer_mode);
250 if (write(s, &net_transfer_mode, sizeof(net_transfer_mode))
251 != sizeof(net_transfer_mode)) {
252 warn ("write(%s)", cs->name);
254 continue; /*** NEXT SLAVE ***/
257 kerror = krb_get_cred (KPROP_SERVICE_NAME, cs->instance,
259 if (kerror != KSUCCESS) {
260 warnx ("%s: %s. Getting session key.",
261 cs->name, krb_get_err_text(kerror));
263 continue; /*** NEXT SLAVE ***/
266 memset(session_sched, 0, sizeof(session_sched));
268 if (des_key_sched (&cred.session, session_sched)) {
269 warnx ("%s: can't make key schedule.",
272 continue; /*** NEXT SLAVE ***/
275 /* SAFE (quad_cksum) and CLEAR are just not good enough */
277 #ifdef not_working_yet
278 if (transfer_mode != KPROP_TRANSFER_PRIVATE) {
279 cksum = get_data_checksum(fd, session_sched);
289 kerror = krb_sendauth(KOPT_DO_MUTUAL,
302 if (kerror != KSUCCESS) {
303 warnx ("%s: krb_sendauth: %s.",
304 cs->name, krb_get_err_text(kerror));
306 continue; /*** NEXT SLAVE ***/
309 lseek(fd, 0L, SEEK_SET); /* Rewind file before rereading it. */
310 while ((n = read(fd, buf, sizeof buf))) {
313 switch (transfer_mode) {
314 case KPROP_TRANSFER_PRIVATE:
315 case KPROP_TRANSFER_SAFE:
316 if (transfer_mode == KPROP_TRANSFER_PRIVATE)
317 length = krb_mk_priv (buf, obuf, n,
318 session_sched, &cred.session,
321 length = krb_mk_safe (buf, obuf, n,
325 warnx ("%s: %s failed.",
327 (transfer_mode == KPROP_TRANSFER_PRIVATE)
328 ? "krb_rd_priv" : "krb_rd_safe");
330 continue; /*** NEXT SLAVE ***/
332 nlength = htonl(length);
333 if (write(s, &nlength, sizeof nlength)
335 warn ("write(%s)", cs->name);
337 continue; /*** NEXT SLAVE ***/
339 if (write(s, obuf, length) != length) {
340 warn ("write(%s)", cs->name);
342 continue; /*** NEXT SLAVE ***/
345 case KPROP_TRANSFER_CLEAR:
346 if (write(s, buf, n) != n) {
347 warn ("write(%s)", cs->name);
349 continue; /*** NEXT SLAVE ***/
356 printf("%s: success.\n", cs->name);
358 asprintf(&last_prop_path,
362 if (last_prop_path == NULL)
363 errx (1, "malloc failed");
365 unlink(last_prop_path);
366 close(creat(last_prop_path, 0600));
373 for (cs = sl; cs; cs = cs->next) {
375 return (0); /* didn't get this slave */
383 /* already got floc and fslv, what is this? */
385 "\nUsage: kprop [-force] [-realm realm] [-private"
389 "] [data_file [slaves_file]]\n\n");
395 main(int argc, char **argv)
398 char *floc, *floc_ok;
401 struct stat stbuf, stbuf_ok;
402 time_t l_init, l_final;
405 static struct slave_host *slave_host_list = NULL;
406 struct slave_host *sh;
408 set_progname (argv[0]);
410 transfer_mode = KPROP_TRANSFER_PRIVATE;
414 pc[strlen(pc) - 1] = '\0';
415 printf("\nStart slave propagation: %s\n", pc);
420 if (krb_get_lrealm(my_realm,1) != KSUCCESS)
421 errx (1, "Getting my kerberos realm. Check krb.conf");
423 for (i = 1; i < argc; i++)
424 switch (argv[i][0]) {
426 if (strcmp (argv[i], "-private") == 0)
427 transfer_mode = KPROP_TRANSFER_PRIVATE;
429 else if (strcmp (argv[i], "-safe") == 0)
430 transfer_mode = KPROP_TRANSFER_SAFE;
431 else if (strcmp (argv[i], "-clear") == 0)
432 transfer_mode = KPROP_TRANSFER_CLEAR;
434 else if (strcmp (argv[i], "-realm") == 0) {
437 strlcpy(my_realm, argv[i], REALM_SZ);
440 } else if (strcmp (argv[i], "-force") == 0)
443 warnx("unknown control argument %s.", argv[i]);
448 /* positional arguments are marginal at best ... */
459 floc = DB_DIR "/slave_dump";
461 fslv = DB_DIR "/slaves";
463 asprintf (&floc_ok, "%s%s", floc, ok);
465 errx (1, "out of memory in copying %s", floc);
467 dir_path = strdup(fslv);
469 errx (1, "malloc failed");
470 pc = strrchr(dir_path, '/');
477 if ((fd = open(floc, O_RDONLY)) < 0)
478 err (1, "open(%s)", floc);
479 if (flock(fd, LOCK_SH | LOCK_NB))
480 err (1, "flock(%s)", floc);
481 if (stat(floc, &stbuf))
482 err (1, "stat(%s)", floc);
483 if (stat(floc_ok, &stbuf_ok))
484 err (1, "stat(%s)", floc_ok);
485 if (stbuf.st_mtime > stbuf_ok.st_mtime)
486 errx (1, "'%s' more recent than '%s'.", floc, floc_ok);
487 if (!get_slaves(&slave_host_list, dir_path, fslv, stbuf_ok.st_mtime))
488 errx (1, "can't read slave host file '%s'.", fslv);
491 struct slave_host *sh;
493 fprintf(stderr, "\n\n");
495 for (sh = slave_host_list; sh; sh = sh->next) {
496 fprintf(stderr, "slave %d: %s, %s", i++, sh->name,
497 inet_ntoa(sh->net_addr));
501 #endif /* KPROP_DBG */
503 if (!prop_to_slaves(slave_host_list, fd, dir_path, fslv))
504 errx (1, "propagation failed.");
505 if (flock(fd, LOCK_UN))
506 err (1, "flock(%s, LOCK_UN)", floc);
508 for (sh = slave_host_list; sh; sh = sh->next) {
509 if (sh->not_time_yet)
510 printf( "%s:\t\tNot time yet\n", sh->name);
511 else if (sh->succeeded)
512 printf( "%s:\t\tSucceeded\n", sh->name);
514 fprintf(stderr, "%s:\t\tFAILED\n", sh->name);
519 l_diff = l_final - l_init;
520 printf("propagation finished, %d:%02d:%02d elapsed\n",
521 l_diff / 3600, (l_diff % 3600) / 60, l_diff % 60);
526 #ifdef doesnt_work_yet
527 u_long get_data_checksum(fd, key_sched)
529 des_key_schedule key_sched;
536 while (n = read(fd, buf, sizeof buf)) {
539 cksum = cbc_cksum(buf, obuf, n, key_sched, key_sched);