]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - server/realm.c
cff976ca31fca04df872c69e693cf1542783fbb9
[1ts-debian.git] / 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 /*
11  * External Routines:
12  *
13  * Realm *realm_which_realm(struct sockaddr_in *who)
14  * figures out if this packet came from another realm's server
15  *
16  * Realm *realm_get_realm_by_pid(int pid)
17  * figures out which realm a child handler was for
18  *
19  * void kill_realm_pids()
20  * kills all ticket getting childen
21  *
22  * char *realm_expand_realm(char *realmname)
23  * figures out what an abbreviated realm expands to
24  *
25  * Code_t realm_send_realms()
26  * loops through all realms for a brain dump
27  *
28  * int realm_bound_for_realm(char *realm, char *recip)
29  * figures out if recip is in realm, expanding recip's realm
30  *
31  * int realm_sender_in_realm(char *realm, char *sender)
32  * figures out if sender is in realm
33  * 
34  * Realm *realm_get_realm_by_name(char *name)
35  * finds a realm struct from the realm array by name, tries expansion
36  *
37  * Code_t realm_dispatch(ZNotice_t *notice, int auth, struct sockaddr_in *who,
38  *                       Server *server)
39  * dispatches a message from a foreign realm
40  *
41  * void realm_init()
42  * sets up the realm module
43  * 
44  * void realm_deathgram()
45  * tells other realms this server is going down
46  * 
47  * void realm_wakeup()
48  * tells other realms to resend their idea of their subs to us
49  *
50  * Code_t realm_control_dispatch(ZNotice_t *notice, int auth,
51  *                               struct sockaddr_in *who, Server *server,
52  *                               Realm *realm)
53  * dispatches a foreign realm control message
54  *
55  * void realm_handoff(ZNotice_t *notice, int auth, struct sockaddr_in *who,
56  *                    Realm *realm, int ack_to_sender)
57  * hands off a message to another realm
58  *
59  * void realm_dump_realms(File *fp)
60  * do a database dump of foreign realm info
61  *
62  */
63 static void realm_sendit __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, Realm *realm, int ack_to_sender));
64 static void realm_sendit_auth __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, Realm *realm, int ack_to_sender));
65 static void rlm_ack __P((ZNotice_t *notice, Unacked *nacked));
66 static void rlm_nack_cancel __P((ZNotice_t *notice, struct sockaddr_in *who));
67 static void rlm_new_ticket __P(());
68 static void rlm_rexmit __P((void *arg));
69 static Code_t realm_ulocate_dispatch __P((ZNotice_t *notice,int auth,struct sockaddr_in *who,Server *server,Realm *realm));
70 static Code_t realm_new_server __P((struct sockaddr_in *, ZNotice_t *, Realm *));
71 static Code_t realm_set_server __P((struct sockaddr_in *, Realm *));
72 #ifdef HAVE_KRB4
73 static Code_t ticket_retrieve __P((Realm *realm));
74 static int ticket_lookup __P((char *realm));
75 static int ticket_expired __P((CREDENTIALS *cred));
76 #endif
77
78 static int
79 realm_get_idx_by_addr(realm, who) 
80     Realm *realm;
81     struct sockaddr_in *who;
82 {
83     struct sockaddr_in *addr;
84     int a, b;
85
86     /* loop through the realms */
87     for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
88         if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
89             return(b);
90     
91     return 0;
92 }
93
94 char *
95 realm_expand_realm(realmname)
96 char *realmname;
97 {
98     Realm *realm;
99     int a;
100
101     /* First, look for an exact match (case insensitive) */
102 #ifdef HAVE_KRB4
103     if (!strcasecmp(ZGetRealm(), realmname))
104         return(ZGetRealm());
105 #endif
106
107     for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
108       if (!strcasecmp(realm->name, realmname))
109         return(realm->name);
110
111     /* No exact match. See if there's a partial match */
112 #ifdef HAVE_KRB4
113     if (!strncasecmp(ZGetRealm(), realmname, strlen(realmname)))
114         return(ZGetRealm());
115 #endif
116
117     for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
118         if (!strncasecmp(realm->name, realmname, strlen(realmname)))
119             return(realm->name);
120     return(realmname);
121 }
122
123 Realm *
124 realm_get_realm_by_pid(pid)
125      int pid;
126 {
127     Realm *realm;
128     int a;
129
130     for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
131         if (realm->child_pid == pid)
132             return(realm);
133    
134     return 0;
135 }
136
137 void
138 kill_realm_pids()
139 {
140     Realm *realm;
141     int a;
142
143     for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
144         if (realm->child_pid != 0)
145             kill(realm->child_pid, 9);
146    
147     return;
148 }
149
150 Realmname *
151 get_realm_lists(file)
152     char *file;
153 {
154     Realmname *rlm_list, *rlm;
155     int ii, nused, ntotal;
156     FILE *fp;
157     char buf[REALM_SZ + MAXHOSTNAMELEN + 1]; /* one for newline */
158     char realm[REALM_SZ], server[MAXHOSTNAMELEN + 1];
159   
160     nused = 0;
161     if (!(fp = fopen(file, "r")))
162         return((Realmname *)0);
163   
164     /* start with 16, realloc if necessary */
165     ntotal = 16;
166     rlm_list = (Realmname *)malloc(ntotal * sizeof(Realmname));
167     if (!rlm_list) {
168         syslog(LOG_CRIT, "get_realm_lists malloc");
169         abort();
170     }
171
172     while (fgets(buf, REALM_SZ + MAXHOSTNAMELEN + 1, fp)) {
173         if (sscanf(buf, "%s %s", realm, server) != 2) {
174             syslog(LOG_CRIT, "bad format in %s", file);
175             abort();
176         }
177         for (ii = 0; ii < nused; ii++) {
178             /* look for this realm */
179             if (!strcmp(rlm_list[ii].name, realm))
180                 break;
181         }
182         if (ii < nused) {
183             rlm = &rlm_list[ii];
184             if (rlm->nused +1 >= rlm->nservers) {
185                 /* make more space */
186                 rlm->servers = (char **)realloc((char *)rlm->servers, 
187                                                 (unsigned)rlm->nservers * 2 * 
188                                                 sizeof(char *));
189                 if (!rlm->servers) {
190                     syslog(LOG_CRIT, "get_realm_lists realloc");
191                     abort();
192                 }
193                 rlm->nservers *= 2;
194             }
195             rlm->servers[rlm->nused++] = strsave(server);
196         } else {
197             /* new realm */
198             if (nused + 1 >= ntotal) {
199                 /* make more space */
200                 rlm_list = (Realmname *)realloc((char *)rlm_list,
201                                                 (unsigned)ntotal * 2 * 
202                                                 sizeof(Realmname));
203                 if (!rlm_list) {
204                     syslog(LOG_CRIT, "get_realm_lists realloc");
205                     abort();
206                 }
207                 ntotal *= 2;
208             }
209             rlm = &rlm_list[nused++];
210             strcpy(rlm->name, realm);
211             rlm->nused = 0;
212             rlm->nservers = 16;
213             rlm->servers = (char **)malloc(rlm->nservers * sizeof(char *));
214             if (!rlm->servers) {
215                 syslog(LOG_CRIT, "get_realm_lists malloc");
216                 abort();
217             }
218             rlm->servers[rlm->nused++] = strsave(server);
219         }
220     }
221     if (nused + 1 >= ntotal) {
222         rlm_list = (Realmname *)realloc((char *)rlm_list,
223                                         (unsigned)(ntotal + 1) * 
224                                         sizeof(Realmname));
225         if (!rlm_list) {
226             syslog(LOG_CRIT, "get_realm_lists realloc");
227             abort();
228         }
229     }
230     *rlm_list[nused].name = '\0';
231   
232     return(rlm_list);
233 }
234
235 Code_t 
236 realm_send_realms()
237 {
238     int cnt, retval;
239     for (cnt = 0; cnt < nrealms; cnt++) {
240         if (retval = (subscr_send_realm_subs(&otherrealms[cnt])) != ZERR_NONE)
241             return(retval);
242     }
243 }
244
245 int
246 realm_bound_for_realm(realm, recip)
247      char *realm;
248      char *recip;
249 {
250     char *rlm = NULL;
251     int remote = strcmp(ZGetRealm(), realm);
252     
253     if (recip)
254       rlm = strchr(recip, '@');
255     
256     if (!rlm && !remote) 
257         return 1;
258
259     if (rlm && strcmp(realm_expand_realm(rlm + 1), realm) == 0)
260         return 1;
261
262     return 0;
263 }
264
265 int
266 realm_sender_in_realm(realm, sender)
267      char *realm;
268      char *sender;
269 {
270     char *rlm = NULL;
271     int remote = strcmp(ZGetRealm(), realm);
272
273     if (sender)
274         rlm = strchr(sender, '@');
275
276     if (!rlm && !remote)
277         return 1;
278
279     if (rlm && strcmp((rlm + 1), realm) == 0)
280         return 1;
281
282     return 0;
283 }
284
285 sender_in_realm(notice)
286     ZNotice_t *notice;
287 {
288   char *realm;
289
290   realm = strchr(notice->z_sender, '@');
291
292   if (!realm || !strcmp(realm + 1, ZGetRealm()))
293     return 1;
294
295   return 0;
296 }
297
298 Realm *
299 realm_which_realm(who)
300     struct sockaddr_in *who;
301 {
302     Realm *realm;
303     struct sockaddr_in *addr;
304     int a, b;
305
306     if (who->sin_port != srv_addr.sin_port)
307         return 0;
308
309     /* loop through the realms */
310     for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
311         /* loop through the addresses for the realm */
312         for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
313             if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
314                 return(realm);
315   
316     return 0;
317 }
318
319 Realm *
320 realm_get_realm_by_name(name)
321     char *name;
322 {
323     int a;
324     Realm *realm;
325
326     /* First, look for an exact match (case insensitive) */
327     for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
328         if (!strcasecmp(realm->name, name))
329             return(realm);
330
331     /* Failing that, look for an inexact match */
332     for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
333         if (!strncasecmp(realm->name, name, strlen(name)))
334             return(realm);
335
336     return 0;
337 }
338
339 static void
340 rlm_nack_cancel(notice, who)
341     register ZNotice_t *notice;
342     struct sockaddr_in *who;
343 {
344     register Realm *which = realm_which_realm(who);
345     register Unacked *nacked, *next;
346     ZPacket_t retval;
347   
348 #if 1
349     zdbug((LOG_DEBUG, "rlm_nack_cancel: %s:%08X,%08X",
350            inet_ntoa(notice->z_uid.zuid_addr),
351            notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
352 #endif
353     if (!which) {
354         syslog(LOG_ERR, "non-realm ack?");
355         return;
356     }
357
358     for (nacked = rlm_nacklist; nacked; nacked = nacked->next) {
359         if (&otherrealms[nacked->dest.rlm.rlm_idx] == which) {
360             /* First, note the realm appears to be up */
361             which->state = REALM_UP;
362             if (ZCompareUID(&nacked->uid, &notice->z_uid)) {
363                 timer_reset(nacked->timer);
364         
365                 if (nacked->ack_addr.sin_addr.s_addr)
366                     rlm_ack(notice, nacked);
367         
368                 /* free the data */
369                 free(nacked->packet);
370                 LIST_DELETE(nacked);
371                 free(nacked);
372                 return;
373             }
374         }
375     }
376 #if 0
377     zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X",
378            inet_ntoa (notice->z_uid.zuid_addr),
379            notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
380 #endif
381     return;
382 }
383
384 static void
385 rlm_ack(notice, nacked)
386     ZNotice_t *notice;
387     Unacked *nacked;
388 {
389     ZNotice_t acknotice;
390     ZPacket_t ackpack;
391     int packlen;
392     Code_t retval;
393   
394     /* tell the original sender the result */
395     acknotice = *notice;
396     acknotice.z_message_len = strlen(acknotice.z_message) + 1;
397   
398     packlen = sizeof(ackpack);
399   
400     if ((retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen)) 
401         != ZERR_NONE) {
402         syslog(LOG_ERR, "rlm_ack format: %s",
403                error_message(retval));
404         return;
405     }
406     zdbug((LOG_DEBUG, "rlm_ack sending to %s/%d",
407            inet_ntoa(nacked->ack_addr.sin_addr),
408            ntohs(nacked->ack_addr.sin_port)));
409     if ((retval = ZSetDestAddr(&nacked->ack_addr)) != ZERR_NONE) {
410         syslog(LOG_WARNING, "rlm_ack set addr: %s",
411                error_message(retval));
412         return;
413     }
414     if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) {
415         syslog(LOG_WARNING, "rlm_ack xmit: %s", error_message(retval));
416         return;
417     }
418 }
419
420 Code_t
421 realm_dispatch(notice, auth, who, server)
422     ZNotice_t *notice;
423     int auth;
424     struct sockaddr_in *who;
425     Server *server;
426 {
427     Realm *realm;
428     struct sockaddr_in newwho;
429     Code_t status = ZERR_NONE;
430     char rlm_recipient[REALM_SZ + 1];
431     int external = 0;
432     String *notice_class;
433
434     if (notice->z_kind == SERVACK || notice->z_kind == SERVNAK) {
435         rlm_nack_cancel(notice, who);
436         return(ZERR_NONE);
437     }
438     /* set up a who for the real origin */
439     memset((caddr_t) &newwho, 0, sizeof(newwho));
440     newwho.sin_family = AF_INET;
441     newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr;
442     newwho.sin_port = hm_port;
443     
444     /* check if it's a control message */
445     realm = realm_which_realm(who);
446
447     notice_class = make_string(notice->z_class,1);
448     
449     if (class_is_admin(notice_class)) {
450         syslog(LOG_WARNING, "%s sending admin opcode %s",
451                realm->name, notice->z_opcode);
452     } else if (class_is_hm(notice_class)) {
453         syslog(LOG_WARNING, "%s sending hm opcode %s",
454                realm->name, notice->z_opcode);
455     } else if (class_is_control(notice_class)) {
456         status = realm_control_dispatch(notice, auth, who,
457                                         server, realm);
458     } else if (class_is_ulogin(notice_class)) {
459         /* don't need to forward this */
460         if (server == me_server) {
461             sprintf(rlm_recipient, "@%s", realm->name);
462             notice->z_recipient = rlm_recipient;
463
464             sendit(notice, 1, who, 0);
465         }
466     } else if (class_is_ulocate(notice_class)) {
467         status = realm_ulocate_dispatch(notice, auth, who, server, realm);
468     } else {
469         /* redo the recipient */
470         if (*notice->z_recipient == '\0') {
471             sprintf(rlm_recipient, "@%s", realm->name);
472             notice->z_recipient = rlm_recipient;
473             external = 0;
474         } else if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient)
475                    && *notice->z_recipient == '@') 
476         {
477             /* we're responsible for getting this message out */
478             external = 1;
479             notice->z_recipient = "";
480         }
481           
482         /* otherwise, send to local subscribers */
483         sendit(notice, auth, who, external);
484     }
485         
486     return(status);
487 }
488
489 void
490 realm_init()
491 {
492     Client *client;
493     Realmname *rlmnames;
494     Realm *rlm;
495     int ii, jj, found;
496     struct in_addr *addresses;
497     struct hostent *hp;
498     char list_file[128];
499     char rlmprinc[ANAME_SZ+INST_SZ+REALM_SZ+3];
500
501     sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, REALM_LIST_FILE);
502     rlmnames = get_realm_lists(list_file);
503     if (!rlmnames) {
504         zdbug((LOG_DEBUG, "No other realms"));
505         nrealms = 0;
506         return;
507     }
508     
509     for (nrealms = 0; *rlmnames[nrealms].name; nrealms++);
510     
511     otherrealms = (Realm *)malloc(nrealms * sizeof(Realm));
512     if (!otherrealms) {
513         syslog(LOG_CRIT, "malloc failed in realm_init");
514         abort();
515     }
516
517     for (ii = 0; ii < nrealms; ii++) {
518         rlm = &otherrealms[ii];
519         strcpy(rlm->name, rlmnames[ii].name);
520         
521         addresses = (struct in_addr *)malloc(rlmnames[ii].nused * 
522                                              sizeof(struct in_addr));
523         if (!addresses) {
524             syslog(LOG_CRIT, "malloc failed in realm_init");
525             abort();
526         }
527         /* convert names to addresses */
528         found = 0;
529         for (jj = 0; jj < rlmnames[ii].nused; jj++) {
530             hp = gethostbyname(rlmnames[ii].servers[jj]);
531             if (hp) {
532                 memmove((caddr_t) &addresses[found], (caddr_t)hp->h_addr, 
533                         sizeof(struct in_addr));
534                 found++;
535             } else
536                 syslog(LOG_WARNING, "hostname failed, %s", 
537                        rlmnames[ii].servers[jj]);
538             /* free the hostname */
539             free(rlmnames[ii].servers[jj]);
540         }
541         rlm->count = found;
542         rlm->addrs = (struct sockaddr_in *)malloc(found * 
543                                                   sizeof (struct sockaddr_in));
544         if (!rlm->addrs) {
545             syslog(LOG_CRIT, "malloc failed in realm_init");
546             abort();
547         }
548         for (jj = 0; jj < rlm->count; jj++) {
549             rlm->addrs[jj].sin_family = AF_INET;
550             /* use the server port */
551             rlm->addrs[jj].sin_port = srv_addr.sin_port;
552             rlm->addrs[jj].sin_addr = addresses[jj];
553         }
554         client = (Client *) malloc(sizeof(Client));
555         if (!client) {
556             syslog(LOG_CRIT, "malloc failed in realm_init");
557             abort();
558         }
559         memset(&client->addr, 0, sizeof(struct sockaddr_in));
560 #ifdef HAVE_KRB4
561         memset(&client->session_key, 0, sizeof(client->session_key));
562 #endif
563         sprintf(rlmprinc, "%s.%s@%s", SERVER_SERVICE, SERVER_INSTANCE, 
564                 rlm->name);
565         client->principal = make_string(rlmprinc, 0);
566         client->last_send = 0;
567         client->last_ack = NOW;
568         client->subs = NULL;
569         client->realm = rlm;
570         client->addr.sin_family = 0;
571         client->addr.sin_port = 0;
572         client->addr.sin_addr.s_addr = 0;
573     
574         rlm->client = client;
575         rlm->idx = (rlm->count) ? random() % rlm->count : 0;
576         rlm->subs = NULL;
577         rlm->remsubs = NULL;
578         rlm->child_pid = 0;
579         /* Assume the best */
580         rlm->state = REALM_TARDY;
581         rlm->have_tkt = 1;
582         free(rlmnames[ii].servers);
583         free(addresses);
584     }
585     free(rlmnames);
586 }
587
588 void
589 realm_deathgram(server)
590     Server *server;
591 {
592     Realm *realm;
593     char rlm_recipient[REALM_SZ + 1];
594     int jj = 0;
595
596     /* Get it out once, and assume foreign servers will share */
597     for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
598         ZNotice_t snotice;
599         char *pack;
600         char rlm_recipient[REALM_SZ + 1];
601         int packlen, retval;
602     
603         memset (&snotice, 0, sizeof (snotice));
604
605         snotice.z_kind = ACKED;
606         snotice.z_port = srv_addr.sin_port;
607         snotice.z_class = ZEPHYR_CTL_CLASS;
608         snotice.z_class_inst = ZEPHYR_CTL_REALM;
609         snotice.z_opcode = SERVER_SHUTDOWN;
610         snotice.z_sender = myname; /* my host name */
611         sprintf(rlm_recipient, "@%s", realm->name);
612         snotice.z_recipient = rlm_recipient;
613         snotice.z_default_format = "";
614         snotice.z_num_other_fields = 0;
615         snotice.z_default_format = "";
616         snotice.z_message = (server) ? server->addr_str : NULL;
617         snotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0;
618
619         zdbug((LOG_DEBUG, "rlm_deathgram: suggesting %s to %s", 
620                (server) ? server->addr_str : "nothing", realm->name));
621
622 #ifdef HAVE_KRB4
623         if (!ticket_lookup(realm->name))
624             if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
625                 syslog(LOG_WARNING, "rlm_deathgram failed: %s", 
626                        error_message(retval));
627                 return;
628             }
629 #endif
630
631         if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH)) 
632             != ZERR_NONE) 
633         {
634             syslog(LOG_WARNING, "rlm_deathgram format: %s",
635                    error_message(retval));
636             return;
637         }
638         if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
639             syslog(LOG_WARNING, "rlm_deathgram parse: %s",
640                    error_message(retval));
641             free(pack);
642             return;
643         }
644
645         realm_handoff(&snotice, 1, NULL, realm, 0);
646         free(pack);
647     }
648 }
649
650 void
651 realm_wakeup()
652 {
653     int jj, found = 0;
654     Realm *realm;
655     char rlm_recipient[REALM_SZ + 1];
656     
657     for (jj = 1; jj < nservers; jj++) {    /* skip limbo server */
658         if (jj != me_server_idx && otherservers[jj].state == SERV_UP)
659             found++;
660     }
661   
662     if (nservers < 2 || !found) {
663         /* if we're the only server up, send a REALM_BOOT to one of their 
664            servers here */
665         for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
666             ZNotice_t snotice;
667             char *pack;
668             char rlm_recipient[REALM_SZ + 1];
669             int packlen, retval;
670             
671             memset (&snotice, 0, sizeof (snotice));
672
673             snotice.z_opcode = REALM_BOOT;
674             snotice.z_port = srv_addr.sin_port;
675             snotice.z_class_inst = ZEPHYR_CTL_REALM;
676             snotice.z_class = ZEPHYR_CTL_CLASS;
677             snotice.z_recipient = "";
678             snotice.z_kind = ACKED;
679             snotice.z_num_other_fields = 0;
680             snotice.z_default_format = "";
681             snotice.z_sender = myname; /* my host name */
682             sprintf(rlm_recipient, "@%s", realm->name);
683             snotice.z_recipient = rlm_recipient;
684             snotice.z_default_format = "";
685             snotice.z_message = NULL;
686             snotice.z_message_len = 0;
687
688 #ifdef HAVE_KRB4
689             if (!ticket_lookup(realm->name))
690                 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
691                     syslog(LOG_WARNING, "rlm_wakeup failed: %s", 
692                            error_message(retval));
693                     continue;
694                 }
695 #endif
696
697             if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH)) 
698                 != ZERR_NONE) 
699             {
700                 syslog(LOG_WARNING, "rlm_wakeup format: %s",
701                        error_message(retval));
702                 return;
703             }
704             if ((retval = ZParseNotice(pack, packlen, &snotice)) 
705                 != ZERR_NONE) {
706                 syslog(LOG_WARNING, "rlm_wakeup parse: %s",
707                        error_message(retval));
708                 free(pack);
709                 return;
710             }
711
712             realm_handoff(&snotice, 1, NULL, realm, 0);
713             free(pack);
714         }      
715     }
716 }
717
718 static Code_t
719 realm_ulocate_dispatch(notice, auth, who, server, realm)
720     ZNotice_t *notice;
721     int auth;
722     struct sockaddr_in *who;
723     Server *server;
724     Realm *realm;
725 {
726     register char *opcode = notice->z_opcode;
727     Code_t status;
728   
729     if (!auth) {
730         syslog(LOG_WARNING, "unauth locate msg from %s (%s/%s/%s)",
731                inet_ntoa(who->sin_addr), 
732                notice->z_class, notice->z_class_inst, 
733                notice->z_opcode); /* XXX */
734 #if 0
735         syslog(LOG_WARNING, "unauth locate msg from %s",
736                inet_ntoa(who->sin_addr));
737 #endif
738         clt_ack(notice, who, AUTH_FAILED);
739         return(ZERR_NONE);
740     }
741     
742     if (!strcmp(opcode, REALM_REQ_LOCATE)) {
743         ack(notice, who);
744         ulogin_realm_locate(notice, who, realm);
745     } else if (!strcmp(opcode, REALM_ANS_LOCATE)) {
746         ack(notice, who);
747         ulogin_relay_locate(notice, who);
748     } else {
749         syslog(LOG_WARNING, "%s unknown/illegal loc opcode %s",
750                realm->name, opcode);
751         nack(notice, who);
752     }
753     
754     return(ZERR_NONE);
755 }
756
757
758 Code_t
759 realm_control_dispatch(notice, auth, who, server, realm)
760     ZNotice_t *notice;
761     int auth;
762     struct sockaddr_in *who;
763     Server *server;
764     Realm *realm;
765 {
766     register char *opcode = notice->z_opcode;
767     Code_t status;
768
769     if (!auth) {
770         syslog(LOG_WARNING, "unauth ctl msg from %s (%s/%s/%s)",
771                inet_ntoa(who->sin_addr), 
772                notice->z_class, notice->z_class_inst, 
773                notice->z_opcode); /* XXX */
774 #if 0
775         syslog(LOG_WARNING, "unauth ctl msg from %s",
776                inet_ntoa(who->sin_addr));
777 #endif
778         if (server == me_server)
779             clt_ack(notice, who, AUTH_FAILED);
780         return(ZERR_NONE);
781     }
782
783     if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM)) {
784         syslog(LOG_WARNING, "Invalid rlm_dispatch instance %s",
785                notice->z_class_inst);
786         return(ZERR_NONE);
787     }
788
789     if (!strcmp(opcode, REALM_REQ_SUBSCRIBE) || !strcmp(opcode, REALM_ADD_SUBSCRIBE)) {
790         /* try to add subscriptions */
791         /* attempts to get defaults are ignored */
792         if ((status = subscr_foreign_user(notice, who, server, realm)) != ZERR_NONE) {
793             clt_ack(notice, who, AUTH_FAILED);
794         } else if (server == me_server) {
795             server_forward(notice, auth, who);
796             ack(notice, who);
797         }
798     } else if (!strcmp(opcode, REALM_UNSUBSCRIBE)) {
799         /* try to remove subscriptions */
800         if ((status = subscr_realm_cancel(who, notice, realm)) != ZERR_NONE) {
801             clt_ack(notice, who, NOT_FOUND);
802         } else if (server == me_server) {
803             server_forward(notice, auth, who);
804             ack(notice, who);
805         }
806     } else if (!strcmp(opcode, REALM_BOOT)) {
807         zdbug((LOG_DEBUG, "got a REALM_BOOT from %d (me %d)", server, me_server));
808         realm->state = REALM_STARTING;
809         realm_set_server(who, realm);
810 #ifdef REALM_MGMT
811         /* resend subscriptions but only if this was to us */
812         if (server == me_server) {
813             if ((status = subscr_realm_subs(realm)) != ZERR_NONE) {
814                 clt_ack(notice, who, NOT_FOUND);
815             } else {
816                 /* do forward the hint in case it ever matters */
817                 server_forward(notice, auth, who);
818                 ack(notice, who);
819             }
820         }
821 #endif
822     } else if (!strcmp(opcode, SERVER_SHUTDOWN)) {
823         /* try to remove subscriptions */
824         if ((status = realm_new_server(who, notice, realm)) != ZERR_NONE) {
825             clt_ack(notice, who, NOT_FOUND);
826         } else if (server == me_server) {
827             server_forward(notice, auth, who);
828             ack(notice, who);
829         }
830     } else {
831         syslog(LOG_WARNING, "%s unknown/illegal ctl opcode %s",
832                realm->name, opcode);
833         if (server == me_server)
834             nack(notice, who);
835         return(ZERR_NONE);
836     }
837     return(ZERR_NONE);
838 }
839
840 static Code_t
841 realm_new_server(sin, notice, realm)
842     struct sockaddr_in *sin;
843     ZNotice_t *notice;
844     Realm *realm;
845 {
846     struct hostent *hp;
847     char suggested_server[MAXHOSTNAMELEN];
848     unsigned long addr;
849     Realm *rlm;
850     struct sockaddr_in sinaddr;
851     int srvidx;
852
853     if (!realm)
854         return ZSRV_NORLM;
855
856     srvidx = realm_get_idx_by_addr(realm, sin);
857     zdbug((LOG_DEBUG, "rlm_new_srv: message from %d in %s (%s)", 
858            srvidx, realm->name, inet_ntoa(sin->sin_addr)));
859     if (realm->idx == srvidx) {
860         if (notice->z_message_len) {
861             addr = inet_addr(notice->z_message);
862             sinaddr.sin_addr.s_addr = addr;
863             rlm = realm_which_realm(&sinaddr);
864             /* Not exactly */
865             if (!rlm || (rlm != realm))
866                 return ZSRV_NORLM;
867             realm->idx = realm_get_idx_by_addr(realm, &sinaddr);
868         } else {
869             realm->idx = (realm->idx + 1) % realm->count;
870         } 
871         zdbug((LOG_DEBUG, "rlm_new_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
872     } else {
873       zdbug((LOG_DEBUG, "rlm_new_srv: not switching servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
874     }
875 }
876
877 static Code_t
878 realm_set_server(sin, realm)
879     struct sockaddr_in *sin;
880     Realm *realm;
881 {
882     Realm *rlm;
883
884     rlm = realm_which_realm(sin);
885     /* Not exactly */
886     if (!rlm || (rlm != realm))
887         return ZSRV_NORLM;
888     realm->idx = realm_get_idx_by_addr(realm, sin);
889     zdbug((LOG_DEBUG, "rlm_pick_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
890 }
891
892 void
893 realm_handoff(notice, auth, who, realm, ack_to_sender)
894     ZNotice_t *notice;
895     int auth;
896     struct sockaddr_in *who;
897     Realm *realm;
898     int ack_to_sender;
899 {
900 #ifdef HAVE_KRB4
901     Code_t retval;
902
903     if (!auth) {
904         zdbug((LOG_DEBUG, "realm_sendit unauthentic to realm %s", 
905                realm->name));
906         realm_sendit(notice, who, auth, realm, ack_to_sender);
907         return;
908     }
909   
910     if (!ticket_lookup(realm->name))
911         if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
912             syslog(LOG_WARNING, "rlm_handoff failed: %s", 
913                    error_message(retval));
914             realm_sendit(notice, who, auth, realm, ack_to_sender);
915             return;
916         }
917     
918     zdbug((LOG_DEBUG, "realm_sendit to realm %s auth %d", realm->name, auth)); 
919     /* valid ticket available now, send the message */
920     realm_sendit_auth(notice, who, auth, realm, ack_to_sender);
921 #else /* HAVE_KRB4 */
922     realm_sendit(notice, who, auth, realm, ack_to_sender);
923 #endif /* HAVE_KRB4 */
924 }
925
926 static void
927 realm_sendit(notice, who, auth, realm, ack_to_sender)
928     ZNotice_t *notice;
929     struct sockaddr_in *who;
930     int auth;
931     Realm *realm;
932     int ack_to_sender;
933 {
934     caddr_t pack;
935     int packlen;
936     Code_t retval;
937     Unacked *nacked;
938
939     notice->z_auth = auth;
940   
941     /* format the notice */
942     if ((retval = ZFormatRawNotice(notice, &pack, &packlen)) != ZERR_NONE) {
943         syslog(LOG_WARNING, "rlm_sendit format: %s",
944                error_message(retval));
945         return;
946     }
947   
948     /* now send */
949     if ((retval = ZSetDestAddr(&realm->addrs[realm->idx])) != ZERR_NONE) {
950         syslog(LOG_WARNING, "rlm_sendit set addr: %s",
951                error_message(retval));
952         free(pack);
953         return;
954     }
955     if ((retval = ZSendPacket(pack, packlen, 0)) != ZERR_NONE) {
956         syslog(LOG_WARNING, "rlm_sendit xmit: %s", error_message(retval));
957         free(pack);
958         return;
959     }
960     
961     /* now we've sent it, mark it as not ack'ed */
962   
963     if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
964         /* no space: just punt */
965         syslog(LOG_ERR, "rlm_sendit nack malloc");
966         free(pack);
967         return;
968     }
969
970     nacked->client = NULL;
971     nacked->rexmits = 0;
972     nacked->packet = pack;
973     nacked->dest.rlm.rlm_idx = realm - otherrealms;
974     nacked->dest.rlm.rlm_srv_idx = realm->idx;
975     nacked->packsz = packlen;
976     nacked->uid = notice->z_uid;
977     if (ack_to_sender)
978         nacked->ack_addr = *who;
979     else
980         nacked->ack_addr.sin_addr.s_addr = 0;
981
982     /* set a timer to retransmit */
983     nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
984     /* chain in */
985     LIST_INSERT(&rlm_nacklist, nacked);
986     return;
987 }
988
989 static void
990 packet_ctl_nack(nackpacket)
991     Unacked *nackpacket;
992 {
993     ZNotice_t notice;
994
995     /* extract the notice */
996     ZParseNotice(nackpacket->packet, nackpacket->packsz, &notice);
997     if (nackpacket->ack_addr.sin_addr.s_addr != 0)
998         nack(&notice, &nackpacket->ack_addr);
999 #if 1
1000     else
1001         syslog(LOG_WARNING, "would have acked nobody (%s/%s/%s)",
1002                notice.z_class, notice.z_class_inst, notice.z_opcode); /* XXX */
1003 #endif
1004 }
1005
1006 static void
1007 rlm_rexmit(arg)
1008     void *arg;
1009 {
1010     Unacked *nackpacket = (Unacked *) arg;
1011     Code_t retval;
1012     register Realm *realm;
1013     int new_srv_idx;
1014
1015     zdbug((LOG_DEBUG,"rlm_rexmit"));
1016
1017     realm = &otherrealms[nackpacket->dest.rlm.rlm_idx];
1018
1019     zdbug((LOG_DEBUG, "rlm_rexmit: sending to %s:%d (%d)",
1020            realm->name, realm->idx, nackpacket->rexmits));
1021
1022     if (realm->count == 0)
1023         return;
1024
1025     /* Check to see if we've retransmitted as many times as we can */
1026     if (nackpacket->rexmits >= (NUM_REXMIT_TIMES * realm->count)) {
1027         /* give a server ack that the packet is lost/realm dead */
1028         packet_ctl_nack(nackpacket);
1029         LIST_DELETE(nackpacket);
1030         
1031         zdbug((LOG_DEBUG, "rlm_rexmit: %s appears dead", realm->name));
1032         realm->state = REALM_DEAD;
1033
1034         free(nackpacket->packet);
1035         free(nackpacket);
1036         return;
1037     }
1038
1039     /* if we've reached our limit, move on to the next server */
1040     if ((realm->state == REALM_TARDY) || 
1041         (nackpacket->rexmits && 
1042          !((nackpacket->rexmits+1) % (NUM_REXMIT_TIMES/3)))) 
1043     {
1044         realm->idx = (realm->idx + 1) % realm->count;
1045         zdbug((LOG_DEBUG, "rlm_rexmit: %s switching servers:%d (%s)", 
1046                realm->name, realm->idx, 
1047                inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1048     }
1049
1050     /* throttle back if it looks like the realm is down */
1051     if ((realm->state != REALM_DEAD) || 
1052         ((nackpacket->rexmits % (realm->count+1)) == 1)) {
1053         /* do the retransmit */
1054         retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1055         if (retval != ZERR_NONE) {
1056             syslog(LOG_WARNING, "rlm_rexmit set addr: %s", 
1057                    error_message(retval));
1058         } else {
1059             retval = ZSendPacket(nackpacket->packet, nackpacket->packsz, 0);
1060             if (retval != ZERR_NONE)
1061                 syslog(LOG_WARNING, "rlm_rexmit xmit: %s",
1062                        error_message(retval));
1063         }
1064         /* no per-server nack queues for foreign realms yet, doesn't matter */
1065         nackpacket->dest.rlm.rlm_srv_idx = realm->idx;
1066         zdbug((LOG_DEBUG, "rlm_rexmit(%s): send to %s", realm->name,
1067                inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1068     } else {
1069         zdbug((LOG_DEBUG, "rlm_rexmit(%s): not sending to %s", realm->name,
1070                inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1071     }
1072
1073     /* reset the timer */
1074     nackpacket->rexmits++;
1075     nackpacket->timer = 
1076         timer_set_rel(rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES], 
1077                       rlm_rexmit, nackpacket);
1078     if (rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES] == -1)
1079         zdbug((LOG_DEBUG, "rlm_rexmit(%s): would send at -1 to %s", 
1080                realm->name, inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1081     
1082     return;
1083 }
1084
1085 void
1086 realm_dump_realms(fp)
1087     FILE *fp;
1088 {
1089     register int ii, jj;
1090   
1091     for (ii = 0; ii < nrealms; ii++) {
1092         (void) fprintf(fp, "%d:%s\n", ii, otherrealms[ii].name);
1093         for (jj = 0; jj < otherrealms[ii].count; jj++) {
1094             (void) fprintf(fp, "\t%s\n",
1095                            inet_ntoa(otherrealms[ii].addrs[jj].sin_addr));
1096         }
1097         /* dump the subs */
1098         subscr_dump_subs(fp, otherrealms[ii].subs);
1099     }
1100 }
1101
1102 #ifdef HAVE_KRB4
1103 static void
1104 realm_sendit_auth(notice, who, auth, realm, ack_to_sender)
1105     ZNotice_t *notice;
1106     int auth;
1107     struct sockaddr_in *who;
1108     Realm *realm;
1109     int ack_to_sender;
1110 {
1111     char *buffer, *ptr;
1112     caddr_t pack;
1113     int buffer_len, hdrlen, offset, fragsize, ret_len, message_len;
1114     int origoffset, origlen;
1115     Code_t retval;
1116     Unacked *nacked;
1117     char buf[1024], multi[64];
1118     CREDENTIALS cred;
1119     KTEXT_ST authent;
1120     ZNotice_t partnotice, newnotice;
1121
1122     offset = 0;
1123
1124     /* build an authent. first, make sure we have the ticket available */
1125     retval = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, realm->name, &cred);
1126     if (retval != GC_OK) {
1127         syslog(LOG_WARNING, "rlm_sendit_auth get_cred: %s",
1128                error_message(retval+krb_err_base));
1129         return;
1130     }
1131
1132     retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE, 
1133                         realm->name, 1);
1134     if (retval != MK_AP_OK) {
1135         syslog(LOG_WARNING, "rlm_sendit_auth mk_req: %s",
1136                error_message(retval+krb_err_base));
1137         return;
1138     }
1139
1140     retval = ZMakeAscii(buf, sizeof(buf), authent.dat, authent.length);
1141     if (retval != ZERR_NONE) {
1142         syslog(LOG_WARNING, "rlm_sendit_auth mk_ascii: %s",
1143                error_message(retval));
1144         return;
1145     }
1146
1147     /* set the dest addr */
1148     retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1149     if (retval != ZERR_NONE) {
1150         syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s", 
1151                error_message(retval));
1152         return;
1153     }
1154
1155     /* now format the notice, refragmenting if needed */
1156     newnotice = *notice;
1157     newnotice.z_auth = 1;
1158     newnotice.z_ascii_authent = buf;
1159     newnotice.z_authent_len = authent.length;
1160     
1161     buffer = (char *) malloc(sizeof(ZPacket_t));
1162     if (!buffer) {
1163         syslog(LOG_ERR, "realm_sendit_auth malloc");
1164         return;                 /* DON'T put on nack list */
1165     }
1166     
1167     buffer_len = sizeof(ZPacket_t);
1168     
1169     retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, &hdrlen, &ptr, 
1170                                NULL);
1171     if (retval != ZERR_NONE) {
1172         syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
1173         free(buffer);
1174         return;
1175     }
1176
1177 #ifdef NOENCRYPTION
1178     newnotice.z_checksum = 0;
1179 #else
1180     newnotice.z_checksum =
1181         (ZChecksum_t)des_quad_cksum(buffer, NULL, ptr - buffer, 0, 
1182                                     cred.session);
1183 #endif
1184
1185     retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, &hdrlen, 
1186                                NULL, NULL);
1187     if (retval != ZERR_NONE) {
1188         syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
1189         free(buffer);
1190         return;
1191     }
1192   
1193     /* This is not terribly pretty, but it does do its job. 
1194      * If a packet we get that needs to get sent off to another realm is
1195      * too big after we slap on our authent, we refragment it further,
1196      * a la Z_SendFragmentedNotice. This obviates the need for what
1197      * used to be done in ZFormatAuthenticRealmNotice, as we do it here.
1198      * At some point it should be pulled back out into its own function,
1199      * but only the server uses it.
1200      */ 
1201
1202     if ((newnotice.z_message_len+hdrlen > buffer_len) || 
1203         (newnotice.z_message_len+hdrlen > Z_MAXPKTLEN)) {
1204         /* Deallocate buffer, use a local one */
1205         free(buffer);
1206     
1207         partnotice = *notice;
1208
1209         partnotice.z_auth = 1;
1210         partnotice.z_ascii_authent = buf;
1211         partnotice.z_authent_len = authent.length;
1212
1213         origoffset = 0;
1214         origlen = notice->z_message_len;
1215
1216         if (notice->z_multinotice && strcmp(notice->z_multinotice, ""))
1217             if (sscanf(notice->z_multinotice, "%d/%d", &origoffset, 
1218                        &origlen) != 2) {
1219                 syslog(LOG_WARNING, "rlm_sendit_auth frag: parse failed");
1220                 return;
1221             }
1222
1223 #if 0
1224         zdbug((LOG_DEBUG,"rlm_send_auth: orig: %d-%d/%d", origoffset, 
1225                notice->z_message_len, origlen));
1226 #endif
1227
1228         fragsize = Z_MAXPKTLEN-hdrlen-Z_FRAGFUDGE;
1229
1230         while (offset < notice->z_message_len || !notice->z_message_len) {
1231             (void) sprintf(multi, "%d/%d", offset+origoffset, origlen);
1232             partnotice.z_multinotice = multi;
1233             if (offset > 0) {
1234                 (void) gettimeofday(&partnotice.z_uid.tv, 
1235                                     (struct timezone *)0);
1236                 partnotice.z_uid.tv.tv_sec = htonl((u_long) 
1237                                                    partnotice.z_uid.tv.tv_sec);
1238                 partnotice.z_uid.tv.tv_usec = 
1239                     htonl((u_long) partnotice.z_uid.tv.tv_usec);
1240                 (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, 
1241                               sizeof(__My_addr));
1242             }
1243             message_len = min(notice->z_message_len-offset, fragsize);
1244             partnotice.z_message = notice->z_message+offset;
1245             partnotice.z_message_len = message_len;
1246
1247 #if 0
1248             zdbug((LOG_DEBUG,"rlm_send_auth: new: %d-%d/%d", 
1249                    origoffset+offset, message_len, origlen));
1250 #endif
1251
1252             buffer = (char *) malloc(sizeof(ZPacket_t));
1253             if (!buffer) {
1254                 syslog(LOG_ERR, "realm_sendit_auth malloc");
1255                 return;                 /* DON'T put on nack list */
1256             }
1257             
1258             retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len, 
1259                                        &hdrlen, &ptr, NULL);
1260             if (retval != ZERR_NONE) {
1261                 syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", 
1262                        error_message(retval));
1263                 free(buffer);
1264                 return;
1265             }
1266
1267 #ifdef NOENCRYPTION
1268             partnotice.z_checksum = 0;
1269 #else
1270             partnotice.z_checksum =
1271                 (ZChecksum_t)des_quad_cksum(buffer, NULL, ptr - buffer, 0, 
1272                                             cred.session);
1273 #endif
1274
1275             retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len, 
1276                                        &hdrlen, NULL, NULL);
1277             if (retval != ZERR_NONE) {
1278                 syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", 
1279                        error_message(retval));
1280                 free(buffer);
1281                 return;
1282             }
1283
1284             ptr = buffer+hdrlen;
1285
1286             (void) memcpy(ptr, partnotice.z_message, partnotice.z_message_len);
1287
1288             buffer_len = hdrlen+partnotice.z_message_len;
1289
1290             /* now send */
1291             if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
1292                 syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s", 
1293                        error_message(retval));
1294                 free(buffer);
1295                 return;
1296             }
1297
1298             if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
1299                 /* no space: just punt */
1300                 syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
1301                 free(buffer);
1302                 return;
1303             }
1304
1305             nacked->rexmits = 0;
1306             nacked->packet = buffer;
1307             nacked->dest.rlm.rlm_idx = realm - otherrealms;
1308             nacked->dest.rlm.rlm_srv_idx = realm->idx;
1309             nacked->packsz = buffer_len;
1310             nacked->uid = partnotice.z_uid;
1311
1312             /* Do the ack for the last frag, below */
1313             if (ack_to_sender)
1314                 nacked->ack_addr = *who;
1315             else
1316                 nacked->ack_addr.sin_addr.s_addr = 0;
1317
1318             /* set a timer to retransmit */
1319             nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
1320
1321             /* chain in */
1322             LIST_INSERT(&rlm_nacklist, nacked);
1323
1324             offset += fragsize;
1325             
1326             if (!notice->z_message_len)
1327                 break;
1328         }
1329 #if 0
1330         zdbug((LOG_DEBUG, "rlm_sendit_auth frag message sent"));
1331 #endif
1332     } else {
1333         /* This is easy, no further fragmentation needed */
1334         ptr = buffer+hdrlen;
1335
1336         (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len);
1337
1338         buffer_len = hdrlen+newnotice.z_message_len;
1339     
1340         /* now send */
1341         if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
1342             syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s", 
1343                    error_message(retval));
1344             free(buffer);
1345             return;
1346         }
1347
1348 #if 0
1349         zdbug((LOG_DEBUG, "rlm_sendit_auth message sent"));
1350 #endif
1351         /* now we've sent it, mark it as not ack'ed */
1352     
1353         if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
1354             /* no space: just punt */
1355             syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
1356             free(buffer);
1357             return;
1358         }
1359
1360         nacked->rexmits = 0;
1361         nacked->packet = buffer;
1362         nacked->dest.rlm.rlm_idx = realm - otherrealms;
1363         nacked->dest.rlm.rlm_srv_idx = realm->idx;
1364         nacked->packsz = buffer_len;
1365         nacked->uid = notice->z_uid;
1366         
1367         /* Do the ack for the last frag, below */
1368         if (ack_to_sender)
1369             nacked->ack_addr = *who;
1370         else
1371             nacked->ack_addr.sin_addr.s_addr = 0;
1372     
1373         /* set a timer to retransmit */
1374         nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
1375         /* chain in */
1376         LIST_INSERT(&rlm_nacklist, nacked);
1377     }
1378     return;
1379 }
1380
1381 static int
1382 ticket_expired(cred)
1383 CREDENTIALS *cred;
1384 {
1385 #ifdef HAVE_KRB_LIFE_TO_TIME
1386     return (krb_life_to_time(cred->issue_date, cred->lifetime) < NOW);
1387 #else /* HAVE_KRB_LIFE_TO_TIME */
1388     return (cred->issue_date + cred->lifetime*5*60 < NOW);
1389 #endif /* HAVE_KRB_LIFE_TO_TIME */
1390 }
1391
1392 static int
1393 ticket_lookup(realm)
1394 char *realm;
1395 {
1396     CREDENTIALS cred;
1397     KTEXT_ST authent;
1398     int retval;
1399
1400     retval = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, realm, &cred);
1401     if (retval == GC_OK && !ticket_expired(&cred))
1402         /* good ticket */
1403         return(1);
1404
1405     return (0);
1406 }
1407
1408 static Code_t
1409 ticket_retrieve(realm)
1410     Realm *realm;
1411 {
1412     int pid, retval = 0;
1413     KTEXT_ST authent;
1414     
1415     get_tgt();
1416
1417     if (realm->child_pid) 
1418         /* Right idea. Basically, we haven't gotten it yet */
1419         return KRBET_KDC_AUTH_EXP;
1420
1421     /* For Putrify */
1422     memset(&authent.dat,0,MAX_KTXT_LEN);
1423     authent.mbz=0;
1424
1425     if (realm->have_tkt) {
1426         retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
1427                             realm->name, 0);
1428         if (retval == KSUCCESS) {
1429             return retval;
1430         }
1431     } else {
1432         syslog(LOG_ERR, "tkt_rtrv: don't have ticket, but have no child");
1433     }
1434  
1435     pid = fork();
1436     if (pid < 0) {
1437         syslog(LOG_ERR, "tkt_rtrv: can't fork");
1438         return KRBET_KDC_AUTH_EXP;
1439     }
1440     else if (pid == 0) {
1441 #ifdef _POSIX_VERSION
1442         struct sigaction action;
1443
1444         action.sa_flags = 0;
1445         sigemptyset(&action.sa_mask);
1446         action.sa_handler = 0;
1447         sigaction(SIGCHLD, &action, NULL);
1448         sigaction(SIGINT, &action, NULL);
1449         sigaction(SIGTERM, &action, NULL);
1450         sigaction(SIGUSR1, &action, NULL);
1451         sigaction(SIGUSR2, &action, NULL);
1452         sigaction(SIGFPE, &action, NULL);
1453         sigaction(SIGHUP, &action, NULL);
1454 #ifdef SIGEMT
1455         sigaction(SIGEMT, &action, NULL);
1456 #endif
1457 #else
1458         signal(SIGCHLD, SIG_DFL);
1459         signal(SIGINT, SIG_DFL);
1460         signal(SIGTERM, SIG_DFL);
1461         signal(SIGUSR1, SIG_DFL);
1462         signal(SIGUSR2, SIG_DFL);
1463         signal(SIGFPE, SIG_DFL);
1464         signal(SIGHUP, SIG_DFL);
1465 #ifdef SIGEMT
1466         signal(SIGEMT, SIG_DFL);
1467 #endif
1468 #endif
1469
1470         while (1) {
1471             retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
1472                                 realm->name, 0);
1473             if (retval == KSUCCESS)
1474                 exit(0);
1475       
1476             /* Sleep a little while before retrying */
1477             sleep(30);
1478         }
1479     } else {
1480         realm->child_pid = pid;
1481         realm->have_tkt = 0;
1482         
1483         syslog(LOG_WARNING, "tkt_rtrv: %s: %s", realm->name,
1484                krb_err_txt[retval]);
1485         return (retval+krb_err_base);
1486     }
1487 }
1488 #endif /* HAVE_KRB4 */
1489