]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/realm.c
Initial revision
[1ts-debian.git] / zephyr / server / realm.c
1 #include "zserver.h"
2 #include <sys/socket.h>
3
4 Unacked *rlm_nacklist = NULL;   /* not acked list for realm-realm
5                                    packets */
6 Realm *otherrealms;             /* points to an array of the known
7                                    servers */
8 int nrealms = 0;                /* number of other realms */
9
10 static void get_realm_addrs __P(());
11 static void realm_sendit __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, Realm *realm, int ack_to_sender));
12 static void realm_sendit_auth __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, Realm *realm, int ack_to_sender));
13 static void rlm_ack __P((ZNotice_t *notice, Unacked *nacked));
14 static void rlm_nack_cancel __P((ZNotice_t *notice, struct sockaddr_in *who));
15 static void rlm_new_ticket __P(());
16 static void rlm_rexmit __P((void *arg));
17 static Code_t realm_ulocate_dispatch __P((ZNotice_t *notice,int auth,struct sockaddr_in *who,Server *server,Realm *realm));
18 #ifdef HAVE_KRB4
19 static Code_t ticket_retrieve __P((Realm *realm));
20 #endif
21
22 char *
23 realm_expand_realm(realmname)
24 char *realmname;
25 {
26         static char expand[REALM_SZ];
27         static char krb_realm[REALM_SZ+1];
28         char *cp1, *cp2;
29         int retval;
30         FILE *rlm_file;
31         char list_file[128];
32         char linebuf[BUFSIZ];
33         char scratch[128];
34
35         /* upcase what we got */
36         cp2 = realmname;
37         cp1 = expand;
38         while (*cp2) {
39                 *cp1++ = toupper(*cp2++);
40         }
41         *cp1 = '\0';
42
43         sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, REALM_LIST_FILE);
44
45         if ((rlm_file = fopen(list_file, "r")) == (FILE *) 0) {
46                 return(expand);
47         }
48
49         if (fgets(linebuf, BUFSIZ, rlm_file) == NULL) {
50                 /* error reading */
51                 (void) fclose(rlm_file);
52                 return(expand);
53         }
54
55         while (1) {
56                 /* run through the file, looking for admin host */
57                 if (fgets(linebuf, BUFSIZ, rlm_file) == NULL) {
58                         (void) fclose(rlm_file);
59                         return(expand);
60                 }
61
62                 if (sscanf(linebuf, "%s %s", krb_realm, scratch) < 2)
63                         continue;
64                 if (!strncmp(krb_realm, expand, strlen(expand))) {
65                         (void) fclose(rlm_file);
66                         return(krb_realm);
67                 }
68         }
69 #ifdef KERBEROS
70         if (!strncmp(my_realm, expand, strlen(expand)))
71             return(my_realm);
72 #endif
73         return(expand);
74 }
75
76 Realmname *
77 get_realm_lists(file)
78     char *file;
79 {
80   Realmname *rlm_list, *rlm;
81   int ii, nused, ntotal;
82   FILE *fp;
83   char buf[REALM_SZ + MAXHOSTNAMELEN + 1]; /* one for newline */
84   char realm[REALM_SZ], server[MAXHOSTNAMELEN + 1];
85   
86   nused = 0;
87   if (!(fp = fopen(file, "r")))
88     return((Realmname *)0);
89   
90   /* start with 16, realloc if necessary */
91   ntotal = 16;
92   rlm_list = (Realmname *)malloc(ntotal * sizeof(Realmname));
93   if (!rlm_list) {
94     syslog(LOG_CRIT, "get_realm_lists malloc");
95     abort();
96   }
97
98   while (fgets(buf, REALM_SZ + MAXHOSTNAMELEN + 1, fp)) {
99     if (sscanf(buf, "%s %s", realm, server) != 2) {
100       syslog(LOG_CRIT, "bad format in %s", file);
101       abort();
102     }
103     for (ii = 0; ii < nused; ii++) {
104       /* look for this realm */
105       if (!strcmp(rlm_list[ii].name, realm))
106         break;
107     }
108     if (ii < nused) {
109       rlm = &rlm_list[ii];
110       if (rlm->nused +1 >= rlm->nservers) {
111         /* make more space */
112         rlm->servers = (char **)realloc((char *)rlm->servers, 
113                                         (unsigned)rlm->nservers * 2 * 
114                                         sizeof(char *));
115         if (!rlm->servers) {
116           syslog(LOG_CRIT, "get_realm_lists realloc");
117           abort();
118         }
119         rlm->nservers *= 2;
120       }
121       rlm->servers[rlm->nused++] = strsave(server);
122     } else {
123       /* new realm */
124       if (nused + 1 >= ntotal) {
125         /* make more space */
126         rlm_list = (Realmname *)realloc((char *)rlm_list,
127                                                (unsigned)ntotal * 2 * 
128                                                sizeof(Realmname));
129         if (!rlm_list) {
130           syslog(LOG_CRIT, "get_realm_lists realloc");
131           abort();
132         }
133         ntotal *= 2;
134       }
135       rlm = &rlm_list[nused++];
136       strcpy(rlm->name, realm);
137       rlm->nused = 0;
138       rlm->nservers = 16;
139       rlm->servers = (char **)malloc(rlm->nservers * sizeof(char *));
140       if (!rlm->servers) {
141         syslog(LOG_CRIT, "get_realm_lists malloc");
142         abort();
143       }
144       rlm->servers[rlm->nused++] = strsave(server);
145     }
146   }
147   if (nused + 1 >= ntotal) {
148     rlm_list = (Realmname *)realloc((char *)rlm_list,
149                                            (unsigned)(ntotal + 1) * 
150                                            sizeof(Realmname));
151     if (!rlm_list) {
152       syslog(LOG_CRIT, "get_realm_lists realloc");
153       abort();
154     }
155   }
156   *rlm_list[nused].name = '\0';
157   
158   return(rlm_list);
159 }
160
161 Code_t 
162 realm_send_realms()
163 {
164   int cnt, retval;
165   for (cnt = 0; cnt < nrealms; cnt++) {
166     if (retval = (subscr_send_realm_subs(&otherrealms[cnt])) != ZERR_NONE)
167       return(retval);
168   }
169   return ZERR_NONE;
170 }
171
172 int
173 bound_for_local_realm(notice)
174     ZNotice_t *notice;
175 {
176   char *realm;
177   
178   realm = strchr(notice->z_recipient, '@');
179   
180   if (!realm || !strcmp(realm_expand_realm(realm + 1), ZGetRealm()))
181     return 1;
182
183   return 0;
184 }
185
186 int
187 sender_in_realm(notice)
188     ZNotice_t *notice;
189 {
190   char *realm;
191
192   realm = strchr(notice->z_sender, '@');
193
194   if (!realm || !strcmp(realm + 1, ZGetRealm()))
195     return 1;
196
197   return 0;
198 }
199
200 Realm *
201 realm_which_realm(who)
202     struct sockaddr_in *who;
203 {
204   Realm *realm;
205   struct sockaddr_in *addr;
206   int a, b;
207
208   /* loop through the realms */
209   for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
210     /* loop through the addresses for the realm */
211     for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
212       if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
213         return(realm);
214   
215   return 0;
216 }
217
218 Realm *
219 realm_get_realm_by_name(name)
220 char *name;
221 {
222   int a;
223   Realm *realm;
224
225   for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
226     if (!strcmp(realm->name, name))
227       return(realm);
228
229   return 0;
230 }
231
232 static void
233 rlm_nack_cancel(notice, who)
234     register ZNotice_t *notice;
235     struct sockaddr_in *who;
236 {
237   register Realm *which = realm_which_realm(who);
238   register Unacked *nacked, *next;
239   ZNotice_t acknotice;
240   ZPacket_t retval;
241   
242 #if 0
243     zdbug((LOG_DEBUG, "rlm_nack_cancel: %s:%08X,%08X",
244            inet_ntoa(notice->z_uid.zuid_addr),
245            notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
246 #endif
247   if (!which) {
248     syslog(LOG_ERR, "non-realm ack?");
249     return;
250   }
251
252   for (nacked = rlm_nacklist; nacked; nacked = nacked->next) {
253     if (&otherrealms[nacked->dest.rlm.rlm_idx] == which) {
254       if (ZCompareUID(&nacked->uid, &notice->z_uid)) {
255         timer_reset(nacked->timer);
256         
257         if (nacked->ack_addr.sin_addr.s_addr)
258           rlm_ack(notice, nacked);
259         
260         /* free the data */
261         free(nacked->packet);
262         LIST_DELETE(nacked);
263         free(nacked);
264         return;
265       }
266     }
267   }
268 #if 0
269     zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X",
270            inet_ntoa (notice->z_uid.zuid_addr),
271            notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
272 #endif
273   return;
274 }
275
276 static void
277 rlm_ack(notice, nacked)
278     ZNotice_t *notice;
279     Unacked *nacked;
280 {
281   ZNotice_t acknotice;
282   ZPacket_t ackpack;
283   int packlen;
284   Code_t retval;
285   
286   /* tell the original sender the result */
287   acknotice = *notice;
288   acknotice.z_message_len = strlen(acknotice.z_message) + 1;
289   
290   packlen = sizeof(ackpack);
291   
292   if ((retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen)) != ZERR_NONE) {
293     syslog(LOG_ERR, "rlm_ack format: %s",
294            error_message(retval));
295     return;
296   }
297   zdbug((LOG_DEBUG, "rlm_ack sending to %s/%d",
298          inet_ntoa(nacked->ack_addr.sin_addr),
299          ntohs(nacked->ack_addr.sin_port)));
300         if ((retval = ZSetDestAddr(&nacked->ack_addr)) != ZERR_NONE) {
301           syslog(LOG_WARNING, "rlm_ack set addr: %s",
302                  error_message(retval));
303           return;
304         }
305   if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) {
306     syslog(LOG_WARNING, "rlm_ack xmit: %s", error_message(retval));
307     return;
308   }
309 }
310
311
312 Code_t
313 realm_dispatch(notice, auth, who, server)
314     ZNotice_t *notice;
315     int auth;
316     struct sockaddr_in *who;
317     Server *server;
318 {
319         Realm *realm;
320         struct sockaddr_in newwho;
321         Code_t status = ZERR_NONE;
322         char rlm_recipient[REALM_SZ + 1];
323         int external = 0;
324         String *notice_class;
325
326         if (notice->z_kind == SERVACK || notice->z_kind == SERVNAK) {
327           rlm_nack_cancel(notice, who);
328           return(ZERR_NONE);
329         }
330         /* set up a who for the real origin */
331         memset((caddr_t) &newwho, 0, sizeof(newwho));
332         newwho.sin_family = AF_INET;
333         newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr;
334         newwho.sin_port = hm_port;
335
336         /* check if it's a control message */
337         realm = realm_which_realm(who);
338
339         notice_class = make_string(notice->z_class,1);
340
341         if (class_is_admin(notice_class)) {
342           syslog(LOG_WARNING, "%s sending admin opcode %s",
343                  realm->name, notice->z_opcode);
344         } else if (class_is_hm(notice_class)) {
345                 syslog(LOG_WARNING, "%s sending hm opcode %s",
346                        realm->name, notice->z_opcode);
347         } else if (class_is_control(notice_class)) {
348                 status = realm_control_dispatch(notice, auth, who,
349                                                 server, realm);
350         } else if (class_is_ulogin(notice_class)) {
351           /* don't need to forward this */
352           if (server == me_server) {
353             sprintf(rlm_recipient, "@%s", realm->name);
354             notice->z_recipient = rlm_recipient;
355
356             sendit(notice, 1, who, 0);
357           }
358         } else if (class_is_ulocate(notice_class)) {
359           status = realm_ulocate_dispatch(notice, auth, who, server, realm);
360         } else {
361           /* redo the recipient */
362           if (*notice->z_recipient == '\0') {
363             sprintf(rlm_recipient, "@%s", realm->name);
364             notice->z_recipient = rlm_recipient;
365             /* only send to our realm */
366             external = 0;
367           } else if (bound_for_local_realm(notice) && *notice->z_recipient 
368                      == '@') 
369             {
370               /* we're responsible for getting this message out */
371               external = 1;
372               notice->z_recipient = "";
373             }
374           
375           /* otherwise, send to local subscribers */
376           sendit(notice, auth, who, external);
377         }
378         
379         return(status);
380 }
381
382 void
383 realm_init()
384 {
385   Client *client;
386   Realmname *rlmnames;
387   Realm *rlm;
388   int ii, jj, found;
389   struct in_addr *addresses;
390   struct hostent *hp;
391   char list_file[128];
392   char rlmprinc[ANAME_SZ+INST_SZ+REALM_SZ+3];
393
394   sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, REALM_LIST_FILE);
395   rlmnames = get_realm_lists(list_file);
396   if (!rlmnames) {
397     zdbug((LOG_DEBUG, "No other realms"));
398     nrealms = 0;
399     return;
400   }
401
402   for (nrealms = 0; *rlmnames[nrealms].name; nrealms++);
403   
404   otherrealms = (Realm *)malloc(nrealms * sizeof(Realm));
405   if (!otherrealms) {
406     syslog(LOG_CRIT, "malloc failed in get_realm_addrs");
407     abort();
408   }
409
410   for (ii = 0; ii < nrealms; ii++) {
411     rlm = &otherrealms[ii];
412     strcpy(rlm->name, rlmnames[ii].name);
413
414     addresses = (struct in_addr *)malloc(rlmnames[ii].nused * sizeof(struct in_addr));
415     if (!addresses) {
416       syslog(LOG_CRIT, "malloc failed in get_realm_addrs");
417       abort();
418     }
419     /* convert names to addresses */
420     found = 0;
421     for (jj = 0; jj < rlmnames[ii].nused; jj++) {
422       hp = gethostbyname(rlmnames[ii].servers[jj]);
423       if (hp) {
424         memmove((caddr_t) &addresses[found], (caddr_t)hp->h_addr, sizeof(struct in_addr));
425         found++;
426       } else
427         syslog(LOG_WARNING, "hostname failed, %s", rlmnames[ii].servers[jj]);
428       /* free the hostname */
429       free(rlmnames[ii].servers[jj]);
430     }
431     rlm->count = found;
432     rlm->addrs = (struct sockaddr_in *)malloc(found * sizeof (struct sockaddr_in));
433     if (!rlm->addrs) {
434       syslog(LOG_CRIT, "malloc failed in get_realm_addrs");
435       abort();
436     }
437     for (jj = 0; jj < rlm->count; jj++) {
438       rlm->addrs[jj].sin_family = AF_INET;
439       /* use the server port */
440       rlm->addrs[jj].sin_port = srv_addr.sin_port;
441       rlm->addrs[jj].sin_addr = addresses[jj];
442     }
443     client = (Client *) malloc(sizeof(Client));
444     if (!client) {
445       syslog(LOG_CRIT, "malloc failed in get_realm_addrs");
446       abort();
447     }
448     memset(&client->addr, 0, sizeof(struct sockaddr_in));
449 #ifdef HAVE_KRB4
450     memset(&client->session_key, 0, sizeof(client->session_key));
451 #endif
452     sprintf(rlmprinc, "%s.%s@%s", SERVER_SERVICE, SERVER_INSTANCE, rlm->name);
453     client->principal = make_string(rlmprinc, 0);
454     client->last_send = 0;
455     client->last_ack = NOW;
456     client->subs = NULL;
457     client->realm = rlm;
458     client->addr.sin_family = 0;
459     client->addr.sin_port = 0;
460     client->addr.sin_addr.s_addr = 0;
461     
462     rlm->client = client;
463     rlm->idx = random() % rlm->count;
464     rlm->subs = NULL;
465     rlm->tkt_try = 0;
466     free(rlmnames[ii].servers);
467     free(addresses);
468   }
469   free(rlmnames);
470 }
471
472 static Code_t
473 realm_ulocate_dispatch(notice, auth, who, server, realm)
474     ZNotice_t *notice;
475     int auth;
476     struct sockaddr_in *who;
477     Server *server;
478     Realm *realm;
479 {
480   register char *opcode = notice->z_opcode;
481   Code_t status;
482   
483   if (!auth) {
484     syslog(LOG_WARNING, "unauth locate msg from %s",
485            inet_ntoa(who->sin_addr));
486     clt_ack(notice, who, AUTH_FAILED);
487     return(ZERR_NONE);
488   }
489
490   if (!strcmp(opcode, REALM_REQ_LOCATE)) {
491     ack(notice, who);
492     ulogin_realm_locate(notice, who, realm);
493   } else if (!strcmp(opcode, REALM_ANS_LOCATE)) {
494     ack(notice, who);
495     ulogin_relay_locate(notice, who);
496   } else {
497     syslog(LOG_WARNING, "%s unknown/illegal loc opcode %s",
498            realm->name, opcode);
499     nack(notice, who);
500   }
501   
502   return(ZERR_NONE);
503 }
504
505
506 Code_t
507 realm_control_dispatch(notice, auth, who, server, realm)
508     ZNotice_t *notice;
509     int auth;
510     struct sockaddr_in *who;
511     Server *server;
512     Realm *realm;
513 {
514   register char *opcode = notice->z_opcode;
515   Code_t status;
516
517   if (!auth) {
518     syslog(LOG_WARNING, "unauth ctl msg from %s",
519            inet_ntoa(who->sin_addr));
520     if (server == me_server)
521       clt_ack(notice, who, AUTH_FAILED);
522     return(ZERR_NONE);
523   }
524
525   if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM)) {
526     syslog(LOG_WARNING, "Invalid rlm_dispatch instance %s",
527            notice->z_class_inst);
528     return(ZERR_NONE);
529   }
530
531   if (!strcmp(opcode, REALM_REQ_SUBSCRIBE) || !strcmp(opcode, REALM_ADD_SUBSCRIBE)) {
532     /* try to add subscriptions */
533     /* attempts to get defaults are ignored */
534     if ((status = subscr_foreign_user(notice, who, realm)) != ZERR_NONE) {
535       clt_ack(notice, who, AUTH_FAILED);
536     } else if (server == me_server) {
537       server_forward(notice, auth, who);
538       ack(notice, who);
539     }
540   } else if (!strcmp(opcode, REALM_UNSUBSCRIBE)) {
541     /* try to remove subscriptions */
542     if ((status = subscr_realm_cancel(who, notice, realm)) != ZERR_NONE) {
543       clt_ack(notice, who, NOT_FOUND);
544     } else if (server == me_server) {
545       server_forward(notice, auth, who);
546       ack(notice, who);
547     }
548   } else {
549     syslog(LOG_WARNING, "%s unknown/illegal ctl opcode %s",
550            realm->name, opcode);
551     if (server == me_server)
552       nack(notice, who);
553     return(ZERR_NONE);
554   }
555   return(ZERR_NONE);
556 }
557
558 void
559 realm_handoff(notice, auth, who, realm, ack_to_sender)
560     ZNotice_t *notice;
561     int auth;
562     struct sockaddr_in *who;
563     Realm *realm;
564     int ack_to_sender;
565 {
566 #ifdef HAVE_KRB4
567   Code_t retval;
568
569   if (!auth) {
570     zdbug((LOG_DEBUG, "realm_sendit unauthentic to realm %s", realm->name)) 
571     realm_sendit(notice, who, auth, realm, ack_to_sender);
572   }
573   
574   if (!ticket_lookup(realm->name))
575     if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
576       syslog(LOG_WARNING, "rlm_handoff failed: %s", error_message(retval));
577       return;
578     }
579   
580   zdbug((LOG_DEBUG, "realm_sendit to realm %s auth %d", realm->name, auth)); 
581   /* valid ticket available now, send the message */
582   realm_sendit_auth(notice, who, auth, realm, ack_to_sender);
583 #else /* HAVE_KRB4 */
584   realm_sendit(notice, who, auth, realm, ack_to_sender);
585 #endif /* HAVE_KRB4 */
586 }
587
588 static void
589 realm_sendit(notice, who, auth, realm, ack_to_sender)
590     ZNotice_t *notice;
591     struct sockaddr_in *who;
592     int auth;
593     Realm *realm;
594     int ack_to_sender;
595 {
596   caddr_t pack;
597   int packlen;
598   Code_t retval;
599   Unacked *nacked;
600
601   notice->z_auth = auth;
602   
603   /* format the notice */
604   if ((retval = ZFormatRawNotice(notice, &pack, &packlen)) != ZERR_NONE) {
605     syslog(LOG_WARNING, "rlm_sendit format: %s",
606            error_message(retval));
607     return;
608   }
609   
610   /* now send */
611   if ((retval = ZSetDestAddr(&realm->addrs[realm->idx])) != ZERR_NONE) {
612     syslog(LOG_WARNING, "rlm_sendit set addr: %s",
613            error_message(retval));
614     free(pack);
615     return;
616   }
617   if ((retval = ZSendPacket(pack, packlen, 0)) != ZERR_NONE) {
618     syslog(LOG_WARNING, "rlm_sendit xmit: %s", error_message(retval));
619     free(pack);
620     return;
621   }
622
623   /* now we've sent it, mark it as not ack'ed */
624   
625   if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
626     /* no space: just punt */
627     syslog(LOG_ERR, "rlm_sendit nack malloc");
628     free(pack);
629     return;
630   }
631
632   nacked->client = NULL;
633   nacked->rexmits = 0;
634   nacked->packet = pack;
635   nacked->dest.rlm.rlm_idx = realm - otherrealms;
636   nacked->dest.rlm.rlm_srv_idx = realm->idx;
637   nacked->packsz = packlen;
638   nacked->uid = notice->z_uid;
639   if (ack_to_sender)
640     nacked->ack_addr = *who;
641   else
642     nacked->ack_addr.sin_addr.s_addr = 0;
643
644   /* set a timer to retransmit */
645   nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
646   /* chain in */
647   LIST_INSERT(&rlm_nacklist, nacked);
648   return;
649 }
650
651 static void
652 packet_ctl_nack(nackpacket)
653     Unacked *nackpacket;
654 {
655   ZNotice_t notice;
656
657   /* extract the notice */
658   ZParseNotice(nackpacket->packet, nackpacket->packsz, &notice);
659   nack(&notice, &nackpacket->ack_addr);
660 }
661
662 static void
663 rlm_rexmit(arg)
664     void *arg;
665 {
666   Unacked *nackpacket = (Unacked *) arg;
667   Code_t retval;
668   register Realm *realm;
669   int new_srv_idx;
670
671         zdbug((LOG_DEBUG,"rlm_rexmit"));
672
673   realm = &otherrealms[nackpacket->dest.rlm.rlm_idx];
674
675   zdbug((LOG_DEBUG, "rlm_rexmit: sending to %s", realm->name));
676
677   if (rexmit_times[(nackpacket->rexmits + 1)/(realm->count)] == -1) {
678     /* give a server ack that the packet is lost/realm dead */
679     packet_ctl_nack(nackpacket);
680     LIST_DELETE(nackpacket);
681     free(nackpacket->packet);
682     free(nackpacket);
683
684     zdbug((LOG_DEBUG, "rlm_rexmit: %s appears dead", realm->name));
685     return;
686   }
687
688   /* retransmit the packet, trying each server in the realm multiple times */
689 #if 0
690   new_srv_idx = ((nackpacket->rexmits / NUM_REXMIT_TIMES)
691                  + nackpacket->rlm.rlm_srv_idx) % realm->count;
692 #else
693   new_srv_idx = nackpacket->rexmits % realm->count;
694 #endif
695   if (new_srv_idx != realm->idx)
696     realm->idx = new_srv_idx;
697
698   retval = ZSetDestAddr(&realm->addrs[realm->idx]);
699   if (retval != ZERR_NONE) {
700     syslog(LOG_WARNING, "rlm_rexmit set addr: %s", error_message(retval));
701   } else {
702     retval = ZSendPacket(nackpacket->packet, nackpacket->packsz, 0);
703     if (retval != ZERR_NONE)
704       syslog(LOG_WARNING, "rlm_rexmit xmit: %s", error_message(retval));
705   }
706   /* reset the timer */
707   if (rexmit_times[(nackpacket->rexmits + 1)/(realm->count)] != -1)
708     nackpacket->rexmits++;
709   
710   nackpacket->timer = timer_set_rel(rexmit_times[(nackpacket->rexmits)/(realm->count)], rlm_rexmit, nackpacket);
711   return;
712 }
713
714 void
715 realm_dump_realms(fp)
716     FILE *fp;
717 {
718   register int ii, jj;
719   
720   for (ii = 0; ii < nrealms; ii++) {
721     (void) fprintf(fp, "%d:%s\n", ii, otherrealms[ii].name);
722     for (jj = 0; jj < otherrealms[ii].count; jj++) {
723       (void) fprintf(fp, "\t%s\n",
724                      inet_ntoa(otherrealms[ii].addrs[jj].sin_addr));
725     }
726     /* dump the subs */
727     subscr_dump_subs(fp, otherrealms[ii].subs);
728   }
729 }
730
731
732 #ifdef HAVE_KRB4
733 static void
734 realm_sendit_auth(notice, who, auth, realm, ack_to_sender)
735     ZNotice_t *notice;
736     int auth;
737     struct sockaddr_in *who;
738     Realm *realm;
739     int ack_to_sender;
740 {
741   char *buffer, *ptr;
742   caddr_t pack;
743   int buffer_len, hdrlen, offset, fragsize, ret_len, message_len;
744   int origoffset, origlen;
745   Code_t retval;
746   Unacked *nacked;
747   char buf[1024], multi[64];
748   CREDENTIALS cred;
749   KTEXT_ST authent;
750   ZNotice_t partnotice, newnotice;
751
752   offset = 0;
753
754   /* first, build an authent */
755   retval = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, realm->name, &cred);
756   if (retval != GC_OK) {
757     syslog(LOG_WARNING, "rlm_sendit_auth get_cred: %s",
758            error_message(retval+krb_err_base));
759     return;
760   }
761
762   retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
763                       realm->name, 1);
764   if (retval != MK_AP_OK) {
765     syslog(LOG_WARNING, "rlm_sendit_auth mk_req: %s",
766            error_message(retval+krb_err_base));
767     return;
768   }
769
770   retval = ZMakeAscii(buf, sizeof(buf), authent.dat, authent.length);
771   if (retval != ZERR_NONE) {
772     syslog(LOG_WARNING, "rlm_sendit_auth mk_ascii: %s",
773            error_message(retval));
774     return;
775   }
776
777   /* set the dest addr */
778   retval = ZSetDestAddr(&realm->addrs[realm->idx]);
779   if (retval != ZERR_NONE) {
780     syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s", error_message(retval));
781     return;
782   }
783
784   /* now format the notice, refragmenting if needed */
785   newnotice = *notice;
786   newnotice.z_auth = 1;
787   newnotice.z_ascii_authent = buf;
788   newnotice.z_authent_len = authent.length;
789
790   buffer = (char *) malloc(sizeof(ZPacket_t));
791   if (!buffer) {
792     syslog(LOG_ERR, "realm_sendit_auth malloc");
793     return;                 /* DON'T put on nack list */
794   }
795
796   buffer_len = sizeof(ZPacket_t);
797
798   retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, &hdrlen, &ptr, 
799                              NULL);
800   if (retval != ZERR_NONE) {
801     syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
802     free(buffer);
803     return;
804   }
805
806 #ifdef NOENCRYPTION
807   newnotice.z_checksum = 0;
808 #else
809   newnotice.z_checksum =
810     (ZChecksum_t)des_quad_cksum(buffer, NULL, ptr - buffer, 0, cred.session);
811 #endif
812
813   retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, &hdrlen, 
814                              NULL, NULL);
815   if (retval != ZERR_NONE) {
816     syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
817     free(buffer);
818     return;
819   }
820   
821   /* This is not terribly pretty, but it does do its job. 
822    * If a packet we get that needs to get sent off to another realm is
823    * too big after we slap on our authent, we refragment it further,
824    * a la Z_SendFragmentedNotice. This obliviates the need for what
825    * used to be done in ZFormatAuthenticRealmNotice, as we do it here.
826    * At some point it should be pulled back out into its own function,
827    * but only the server uses it.
828    */ 
829
830   if ((newnotice.z_message_len+hdrlen > buffer_len) || 
831       (newnotice.z_message_len+hdrlen > Z_MAXPKTLEN)){
832     /* Deallocate buffer, use a local one */
833     free(buffer);
834     
835     partnotice = *notice;
836
837     partnotice.z_auth = 1;
838     partnotice.z_ascii_authent = buf;
839     partnotice.z_authent_len = authent.length;
840
841     origoffset = 0;
842     origlen = notice->z_message_len;
843
844     if (notice->z_multinotice && strcmp(notice->z_multinotice, ""))
845       if (sscanf(notice->z_multinotice, "%d/%d", &origoffset, &origlen) != 2) {
846         syslog(LOG_WARNING, "rlm_sendit_auth frag: parse failed");
847         return;
848       }
849
850 #if 0
851     zdbug((LOG_DEBUG,"rlm_send_auth: orig: %d-%d/%d", origoffset, notice->z_message_len, origlen));
852 #endif
853
854     fragsize = Z_MAXPKTLEN-hdrlen-Z_FRAGFUDGE;
855
856     while (offset < notice->z_message_len || !notice->z_message_len) {
857       (void) sprintf(multi, "%d/%d", offset+origoffset, origlen);
858       partnotice.z_multinotice = multi;
859       if (offset > 0) {
860         (void) gettimeofday(&partnotice.z_uid.tv, (struct timezone *)0);
861         partnotice.z_uid.tv.tv_sec = htonl((u_long) 
862                                            partnotice.z_uid.tv.tv_sec);
863         partnotice.z_uid.tv.tv_usec = htonl((u_long) 
864                                             partnotice.z_uid.tv.tv_usec);
865         (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, 
866                       sizeof(__My_addr));
867       }
868       message_len = min(notice->z_message_len-offset, fragsize);
869       partnotice.z_message = notice->z_message+offset;
870       partnotice.z_message_len = message_len;
871
872 #if 0
873       zdbug((LOG_DEBUG,"rlm_send_auth: new: %d-%d/%d", origoffset+offset, message_len, origlen));
874 #endif
875
876       buffer = (char *) malloc(sizeof(ZPacket_t));
877       if (!buffer) {
878         syslog(LOG_ERR, "realm_sendit_auth malloc");
879         return;                 /* DON'T put on nack list */
880       }
881
882       retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len, &hdrlen, 
883                                  &ptr, NULL);
884       if (retval != ZERR_NONE) {
885         syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
886         free(buffer);
887         return;
888       }
889
890 #ifdef NOENCRYPTION
891       partnotice.z_checksum = 0;
892 #else
893       partnotice.z_checksum =
894         (ZChecksum_t)des_quad_cksum(buffer, NULL, ptr - buffer, 0, 
895                                     cred.session);
896 #endif
897
898       retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len, &hdrlen, 
899                                  NULL, NULL);
900       if (retval != ZERR_NONE) {
901         syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
902         free(buffer);
903         return;
904       }
905
906       ptr = buffer+hdrlen;
907
908       (void) memcpy(ptr, partnotice.z_message, partnotice.z_message_len);
909
910       buffer_len = hdrlen+partnotice.z_message_len;
911
912       /* now send */
913       if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
914         syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s", error_message(retval));
915         free(buffer);
916         return;
917       }
918
919       offset += fragsize;
920
921       if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
922         /* no space: just punt */
923         syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
924         free(buffer);
925         return;
926       }
927
928       nacked->rexmits = 0;
929       nacked->packet = buffer;
930       nacked->dest.rlm.rlm_idx = realm - otherrealms;
931       nacked->dest.rlm.rlm_srv_idx = realm->idx;
932       nacked->packsz = buffer_len;
933       nacked->uid = partnotice.z_uid;
934
935     /* Do the ack for the last frag, below */
936       if (ack_to_sender)
937         nacked->ack_addr = *who;
938       else
939         nacked->ack_addr.sin_addr.s_addr = 0;
940
941       /* set a timer to retransmit */
942       nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
943
944       /* chain in */
945       LIST_INSERT(&rlm_nacklist, nacked);
946
947       if (!notice->z_message_len)
948         break;
949     }
950 #if 0
951     zdbug((LOG_DEBUG, "rlm_sendit_auth frag message sent"));
952 #endif
953   } else {
954     /* This is easy, no further fragmentation needed */
955     ptr = buffer+hdrlen;
956
957     (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len);
958
959     buffer_len = hdrlen+newnotice.z_message_len;
960     
961     /* now send */
962     if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
963       syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s", error_message(retval));
964       free(buffer);
965       return;
966     }
967
968 #if 0
969     zdbug((LOG_DEBUG, "rlm_sendit_auth message sent"));
970 #endif
971     /* now we've sent it, mark it as not ack'ed */
972     
973     if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
974       /* no space: just punt */
975       syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
976       free(buffer);
977       return;
978     }
979
980     nacked->rexmits = 0;
981     nacked->packet = buffer;
982     nacked->dest.rlm.rlm_idx = realm - otherrealms;
983     nacked->dest.rlm.rlm_srv_idx = realm->idx;
984     nacked->packsz = buffer_len;
985     nacked->uid = notice->z_uid;
986
987     /* Do the ack for the last frag, below */
988     if (ack_to_sender)
989       nacked->ack_addr = *who;
990     else
991       nacked->ack_addr.sin_addr.s_addr = 0;
992     
993     /* set a timer to retransmit */
994     nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
995     /* chain in */
996     LIST_INSERT(&rlm_nacklist, nacked);
997   }
998 #if 0
999   if (ack_to_sender)
1000     nacked->ack_addr = *who;
1001 #endif
1002   return;
1003 }
1004
1005 int
1006 ticket_expired(cred)
1007 CREDENTIALS *cred;
1008 {
1009         /* extra 15 minutes for safety margin */
1010 #ifdef AFS_LIFETIMES
1011         return (krb_life_to_time(cred->issue_date, cred->lifetime) < NOW + 15*60);
1012 #else /* AFS_LIFETIMES */
1013         return (cred->issue_date + cred->lifetime*5*60 < NOW + 15*60);
1014 #endif /* AFS_LIFETIMES */
1015 }
1016
1017 int
1018 ticket_lookup(realm)
1019 char *realm;
1020 {
1021   CREDENTIALS cred;
1022   KTEXT_ST authent;
1023   int retval;
1024
1025   retval = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, realm, &cred);
1026   if (retval == GC_OK && !ticket_expired(&cred))
1027     /* good ticket */
1028     return(1);
1029
1030   if (!strcmp(realm, ZGetRealm())) {
1031     get_tgt();
1032     
1033     /* For Putrify */
1034     memset(&authent.dat,0,MAX_KTXT_LEN);
1035     authent.mbz=0;
1036
1037     /* this is local, so try to contact the Kerberos server */
1038     retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
1039                         realm, 0);
1040     if (retval != KSUCCESS) {
1041       syslog(LOG_ERR, "tkt_lookup: local: %s",
1042              krb_err_txt[retval]);
1043       return(0);
1044     } else {
1045       return(1);
1046     }
1047   }
1048   
1049   return (0);
1050 }
1051
1052 static Code_t
1053 ticket_retrieve(realm)
1054     Realm *realm;
1055 {
1056   int pid, retval;
1057   KTEXT_ST authent;
1058   
1059   get_tgt();
1060
1061   /* For Putrify */
1062   memset(&authent.dat,0,MAX_KTXT_LEN);
1063   authent.mbz=0;
1064
1065   /* Don't lose by trying too often. */
1066   if (NOW - realm->tkt_try > 5 * 60) {
1067     retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
1068                         realm->name, 0);
1069     realm->tkt_try = NOW;
1070     if (retval != KSUCCESS) {
1071       syslog(LOG_WARNING, "tkt_rtrv: %s: %s", realm,
1072              krb_err_txt[retval]);
1073       return (retval+krb_err_base);
1074     }
1075     return (0);
1076   } else {
1077     return (1);
1078   }
1079 }
1080 #endif /* HAVE_KRB4 */
1081