2 #include <sys/socket.h>
4 Unacked *rlm_nacklist = NULL; /* not acked list for realm-realm
6 ZRealm *otherrealms; /* points to an array of the known
8 int nrealms = 0; /* number of other realms */
13 * ZRealm *realm_which_realm(struct sockaddr_in *who)
14 * figures out if this packet came from another realm's server
16 * ZRealm *realm_get_realm_by_pid(int pid)
17 * figures out which realm a child handler was for
19 * void kill_realm_pids()
20 * kills all ticket getting childen
22 * char *realm_expand_realm(char *realmname)
23 * figures out what an abbreviated realm expands to
25 * Code_t realm_send_realms()
26 * loops through all realms for a brain dump
28 * int realm_bound_for_realm(char *realm, char *recip)
29 * figures out if recip is in realm, expanding recip's realm
31 * int realm_sender_in_realm(char *realm, char *sender)
32 * figures out if sender is in realm
34 * ZRealm *realm_get_realm_by_name(char *name)
35 * finds a realm struct from the realm array by name, tries expansion
37 * Code_t realm_dispatch(ZNotice_t *notice, int auth, struct sockaddr_in *who,
39 * dispatches a message from a foreign realm
42 * sets up the realm module
44 * void realm_deathgram()
45 * tells other realms this server is going down
48 * tells other realms to resend their idea of their subs to us
50 * Code_t realm_control_dispatch(ZNotice_t *notice, int auth,
51 * struct sockaddr_in *who, Server *server,
53 * dispatches a foreign realm control message
55 * void realm_handoff(ZNotice_t *notice, int auth, struct sockaddr_in *who,
56 * ZRealm *realm, int ack_to_sender)
57 * hands off a message to another realm
59 * void realm_dump_realms(File *fp)
60 * do a database dump of foreign realm info
63 static void realm_sendit(ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender);
64 static Code_t realm_sendit_auth(ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender);
65 static void rlm_ack(ZNotice_t *notice, Unacked *nacked);
66 static void rlm_nack_cancel(ZNotice_t *notice, struct sockaddr_in *who);
67 static void rlm_rexmit(void *arg);
68 static Code_t realm_ulocate_dispatch(ZNotice_t *notice,int auth,struct sockaddr_in *who,Server *server,ZRealm *realm);
69 static Code_t realm_new_server(struct sockaddr_in *, ZNotice_t *, ZRealm *);
70 static Code_t realm_set_server(struct sockaddr_in *, ZRealm *);
72 static Code_t ticket_retrieve(ZRealm *realm);
73 static int ticket_lookup(char *realm);
77 realm_get_idx_by_addr(ZRealm *realm,
78 struct sockaddr_in *who)
80 struct sockaddr_in *addr;
83 /* loop through the realms */
84 for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
85 if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
92 realm_expand_realm(char *realmname)
97 /* First, look for an exact match (case insensitive) */
99 if (!strcasecmp(ZGetRealm(), realmname))
103 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
104 if (!strcasecmp(realm->name, realmname))
107 /* No exact match. See if there's a partial match */
109 if (!strncasecmp(ZGetRealm(), realmname, strlen(realmname)))
113 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
114 if (!strncasecmp(realm->name, realmname, strlen(realmname)))
120 realm_get_realm_by_pid(int pid)
125 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
126 if (realm->child_pid == pid)
133 kill_realm_pids(void)
138 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
139 if (realm->child_pid != 0)
140 kill(realm->child_pid, 9);
146 get_realm_lists(char *file)
148 ZRealmname *rlm_list, *rlm;
149 int ii, nused, ntotal;
151 char buf[REALM_SZ + MAXHOSTNAMELEN + 1]; /* one for newline */
152 char realm[REALM_SZ], server[MAXHOSTNAMELEN + 1];
155 if (!(fp = fopen(file, "r")))
156 return((ZRealmname *)0);
158 /* start with 16, realloc if necessary */
160 rlm_list = (ZRealmname *)malloc(ntotal * sizeof(ZRealmname));
162 syslog(LOG_CRIT, "get_realm_lists malloc");
166 while (fgets(buf, REALM_SZ + MAXHOSTNAMELEN + 1, fp)) {
167 if (sscanf(buf, "%s %s", realm, server) != 2) {
168 syslog(LOG_CRIT, "bad format in %s", file);
171 for (ii = 0; ii < nused; ii++) {
172 /* look for this realm */
173 if (!strcmp(rlm_list[ii].name, realm))
178 if (rlm->nused +1 >= rlm->nservers) {
179 /* make more space */
180 rlm->servers = (char **)realloc((char *)rlm->servers,
181 (unsigned)rlm->nservers * 2 *
184 syslog(LOG_CRIT, "get_realm_lists realloc");
189 rlm->servers[rlm->nused++] = strsave(server);
192 if (nused + 1 >= ntotal) {
193 /* make more space */
194 rlm_list = (ZRealmname *)realloc((char *)rlm_list,
195 (unsigned)ntotal * 2 *
198 syslog(LOG_CRIT, "get_realm_lists realloc");
203 rlm = &rlm_list[nused++];
204 strcpy(rlm->name, realm);
207 rlm->servers = (char **)malloc(rlm->nservers * sizeof(char *));
209 syslog(LOG_CRIT, "get_realm_lists malloc");
212 rlm->servers[rlm->nused++] = strsave(server);
215 if (nused + 1 >= ntotal) {
216 rlm_list = (ZRealmname *)realloc((char *)rlm_list,
217 (unsigned)(ntotal + 1) *
220 syslog(LOG_CRIT, "get_realm_lists realloc");
224 *rlm_list[nused].name = '\0';
231 realm_send_realms(void)
234 for (cnt = 0; cnt < nrealms; cnt++) {
235 if (retval = (subscr_send_realm_subs(&otherrealms[cnt])) != ZERR_NONE)
242 realm_bound_for_realm(char *realm, char *recip)
245 int remote = strcmp(ZGetRealm(), realm);
248 rlm = strchr(recip, '@');
253 if (rlm && strcmp(realm_expand_realm(rlm + 1), realm) == 0)
260 realm_sender_in_realm(char *realm, char *sender)
263 int remote = strcmp(ZGetRealm(), realm);
266 rlm = strchr(sender, '@');
271 if (rlm && strcmp((rlm + 1), realm) == 0)
277 int sender_in_realm(ZNotice_t *notice)
281 realm = strchr(notice->z_sender, '@');
283 if (!realm || !strcmp(realm + 1, ZGetRealm()))
290 realm_which_realm(struct sockaddr_in *who)
293 struct sockaddr_in *addr;
296 if (who->sin_port != srv_addr.sin_port)
299 /* loop through the realms */
300 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
301 /* loop through the addresses for the realm */
302 for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
303 if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
310 realm_get_realm_by_name(char *name)
315 /* First, look for an exact match (case insensitive) */
316 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
317 if (!strcasecmp(realm->name, name))
320 /* Failing that, look for an inexact match */
321 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
322 if (!strncasecmp(realm->name, name, strlen(name)))
329 rlm_nack_cancel(register ZNotice_t *notice,
330 struct sockaddr_in *who)
332 register ZRealm *which = realm_which_realm(who);
333 register Unacked *nacked, *next;
337 zdbug((LOG_DEBUG, "rlm_nack_cancel: %s:%08X,%08X",
338 inet_ntoa(notice->z_uid.zuid_addr),
339 notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
342 syslog(LOG_ERR, "non-realm ack?");
346 for (nacked = rlm_nacklist; nacked; nacked = nacked->next) {
347 if (&otherrealms[nacked->dest.rlm.rlm_idx] == which) {
348 /* First, note the realm appears to be up */
349 which->state = REALM_UP;
350 if (ZCompareUID(&nacked->uid, ¬ice->z_uid)) {
351 timer_reset(nacked->timer);
353 if (nacked->ack_addr.sin_addr.s_addr)
354 rlm_ack(notice, nacked);
357 free(nacked->packet);
365 zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X",
366 inet_ntoa (notice->z_uid.zuid_addr),
367 notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
373 rlm_ack(ZNotice_t *notice,
381 /* tell the original sender the result */
383 acknotice.z_message_len = strlen(acknotice.z_message) + 1;
385 packlen = sizeof(ackpack);
387 if ((retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen))
389 syslog(LOG_ERR, "rlm_ack format: %s",
390 error_message(retval));
393 zdbug((LOG_DEBUG, "rlm_ack sending to %s/%d",
394 inet_ntoa(nacked->ack_addr.sin_addr),
395 ntohs(nacked->ack_addr.sin_port)));
396 if ((retval = ZSetDestAddr(&nacked->ack_addr)) != ZERR_NONE) {
397 syslog(LOG_WARNING, "rlm_ack set addr: %s",
398 error_message(retval));
401 if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) {
402 syslog(LOG_WARNING, "rlm_ack xmit: %s", error_message(retval));
408 realm_dispatch(ZNotice_t *notice,
410 struct sockaddr_in *who,
414 struct sockaddr_in newwho;
415 Code_t status = ZERR_NONE;
416 char rlm_recipient[REALM_SZ + 1];
418 String *notice_class;
420 if (notice->z_kind == SERVACK || notice->z_kind == SERVNAK) {
421 rlm_nack_cancel(notice, who);
424 /* set up a who for the real origin */
425 memset((caddr_t) &newwho, 0, sizeof(newwho));
426 newwho.sin_family = AF_INET;
427 newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr;
428 newwho.sin_port = hm_port;
430 /* check if it's a control message */
431 realm = realm_which_realm(who);
433 notice_class = make_string(notice->z_class,1);
435 if (class_is_admin(notice_class)) {
436 syslog(LOG_WARNING, "%s sending admin opcode %s",
437 realm->name, notice->z_opcode);
438 } else if (class_is_hm(notice_class)) {
439 syslog(LOG_WARNING, "%s sending hm opcode %s",
440 realm->name, notice->z_opcode);
441 } else if (class_is_control(notice_class)) {
442 status = realm_control_dispatch(notice, auth, who,
444 } else if (class_is_ulogin(notice_class)) {
445 /* don't need to forward this */
446 if (server == me_server) {
447 sprintf(rlm_recipient, "@%s", realm->name);
448 notice->z_recipient = rlm_recipient;
450 sendit(notice, 1, who, 0);
452 } else if (class_is_ulocate(notice_class)) {
453 status = realm_ulocate_dispatch(notice, auth, who, server, realm);
455 /* redo the recipient */
456 if (*notice->z_recipient == '\0') {
457 sprintf(rlm_recipient, "@%s", realm->name);
458 notice->z_recipient = rlm_recipient;
460 } else if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient)
461 && *notice->z_recipient == '@')
463 /* we're responsible for getting this message out */
465 notice->z_recipient = "";
468 /* otherwise, send to local subscribers */
469 sendit(notice, auth, who, external);
479 ZRealmname *rlmnames;
482 struct in_addr *addresses;
485 char rlmprinc[ANAME_SZ+INST_SZ+REALM_SZ+3];
487 sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, REALM_LIST_FILE);
488 rlmnames = get_realm_lists(list_file);
490 zdbug((LOG_DEBUG, "No other realms"));
495 for (nrealms = 0; *rlmnames[nrealms].name; nrealms++);
497 otherrealms = (ZRealm *)malloc(nrealms * sizeof(ZRealm));
499 syslog(LOG_CRIT, "malloc failed in realm_init");
503 for (ii = 0; ii < nrealms; ii++) {
504 rlm = &otherrealms[ii];
505 strcpy(rlm->name, rlmnames[ii].name);
507 addresses = (struct in_addr *)malloc(rlmnames[ii].nused *
508 sizeof(struct in_addr));
510 syslog(LOG_CRIT, "malloc failed in realm_init");
513 /* convert names to addresses */
515 for (jj = 0; jj < rlmnames[ii].nused; jj++) {
516 hp = gethostbyname(rlmnames[ii].servers[jj]);
518 memmove((caddr_t) &addresses[found], (caddr_t)hp->h_addr,
519 sizeof(struct in_addr));
522 syslog(LOG_WARNING, "hostname failed, %s",
523 rlmnames[ii].servers[jj]);
524 /* free the hostname */
525 free(rlmnames[ii].servers[jj]);
528 rlm->addrs = (struct sockaddr_in *)malloc(found *
529 sizeof (struct sockaddr_in));
531 syslog(LOG_CRIT, "malloc failed in realm_init");
534 for (jj = 0; jj < rlm->count; jj++) {
535 rlm->addrs[jj].sin_family = AF_INET;
536 /* use the server port */
537 rlm->addrs[jj].sin_port = srv_addr.sin_port;
538 rlm->addrs[jj].sin_addr = addresses[jj];
540 client = (Client *) malloc(sizeof(Client));
542 syslog(LOG_CRIT, "malloc failed in realm_init");
545 memset(&client->addr, 0, sizeof(struct sockaddr_in));
547 client->session_keyblock = NULL;
550 memset(&client->session_key, 0, sizeof(client->session_key));
553 sprintf(rlmprinc, "%s.%s@%s", SERVER_SERVICE, SERVER_INSTANCE,
555 client->principal = make_string(rlmprinc, 0);
556 client->last_send = 0;
557 client->last_ack = NOW;
560 client->addr.sin_family = 0;
561 client->addr.sin_port = 0;
562 client->addr.sin_addr.s_addr = 0;
564 rlm->client = client;
565 rlm->idx = (rlm->count) ? random() % rlm->count : 0;
569 /* Assume the best */
570 rlm->state = REALM_TARDY;
572 free(rlmnames[ii].servers);
579 realm_deathgram(Server *server)
582 char rlm_recipient[REALM_SZ + 1];
585 /* Get it out once, and assume foreign servers will share */
586 for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
589 char rlm_recipient[REALM_SZ + 1];
592 memset (&snotice, 0, sizeof (snotice));
594 snotice.z_kind = ACKED;
595 snotice.z_port = srv_addr.sin_port;
596 snotice.z_class = ZEPHYR_CTL_CLASS;
597 snotice.z_class_inst = ZEPHYR_CTL_REALM;
598 snotice.z_opcode = SERVER_SHUTDOWN;
599 snotice.z_sender = myname; /* my host name */
600 sprintf(rlm_recipient, "@%s", realm->name);
601 snotice.z_recipient = rlm_recipient;
602 snotice.z_default_format = "";
603 snotice.z_num_other_fields = 0;
604 snotice.z_default_format = "";
605 snotice.z_message = (server) ? server->addr_str : NULL;
606 snotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0;
608 zdbug((LOG_DEBUG, "rlm_deathgram: suggesting %s to %s",
609 (server) ? server->addr_str : "nothing", realm->name));
612 if (!ticket_lookup(realm->name))
613 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
614 syslog(LOG_WARNING, "rlm_deathgram failed: %s",
615 error_message(retval));
620 if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZCAUTH))
623 syslog(LOG_WARNING, "rlm_deathgram format: %s",
624 error_message(retval));
627 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
628 syslog(LOG_WARNING, "rlm_deathgram parse: %s",
629 error_message(retval));
634 realm_handoff(&snotice, 1, NULL, realm, 0);
644 char rlm_recipient[REALM_SZ + 1];
646 for (jj = 1; jj < nservers; jj++) { /* skip limbo server */
647 if (jj != me_server_idx && otherservers[jj].state == SERV_UP)
651 if (nservers < 2 || !found) {
652 /* if we're the only server up, send a REALM_BOOT to one of their
654 for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
657 char rlm_recipient[REALM_SZ + 1];
660 memset (&snotice, 0, sizeof (snotice));
662 snotice.z_opcode = REALM_BOOT;
663 snotice.z_port = srv_addr.sin_port;
664 snotice.z_class_inst = ZEPHYR_CTL_REALM;
665 snotice.z_class = ZEPHYR_CTL_CLASS;
666 snotice.z_recipient = "";
667 snotice.z_kind = ACKED;
668 snotice.z_num_other_fields = 0;
669 snotice.z_default_format = "";
670 snotice.z_sender = myname; /* my host name */
671 sprintf(rlm_recipient, "@%s", realm->name);
672 snotice.z_recipient = rlm_recipient;
673 snotice.z_default_format = "";
674 snotice.z_message = NULL;
675 snotice.z_message_len = 0;
678 if (!ticket_lookup(realm->name))
679 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
680 syslog(LOG_WARNING, "rlm_wakeup failed: %s",
681 error_message(retval));
686 if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH))
689 syslog(LOG_WARNING, "rlm_wakeup format: %s",
690 error_message(retval));
693 if ((retval = ZParseNotice(pack, packlen, &snotice))
695 syslog(LOG_WARNING, "rlm_wakeup parse: %s",
696 error_message(retval));
701 realm_handoff(&snotice, 1, NULL, realm, 0);
708 realm_ulocate_dispatch(ZNotice_t *notice,
710 struct sockaddr_in *who,
714 register char *opcode = notice->z_opcode;
718 syslog(LOG_WARNING, "unauth locate msg from %s (%s/%s/%s)",
719 inet_ntoa(who->sin_addr),
720 notice->z_class, notice->z_class_inst,
721 notice->z_opcode); /* XXX */
723 syslog(LOG_WARNING, "unauth locate msg from %s",
724 inet_ntoa(who->sin_addr));
726 clt_ack(notice, who, AUTH_FAILED);
730 if (!strcmp(opcode, REALM_REQ_LOCATE)) {
732 ulogin_realm_locate(notice, who, realm);
733 } else if (!strcmp(opcode, REALM_ANS_LOCATE)) {
735 ulogin_relay_locate(notice, who);
737 syslog(LOG_WARNING, "%s unknown/illegal loc opcode %s",
738 realm->name, opcode);
747 realm_control_dispatch(ZNotice_t *notice,
749 struct sockaddr_in *who,
753 register char *opcode = notice->z_opcode;
757 syslog(LOG_WARNING, "unauth ctl msg from %s (%s/%s/%s)",
758 inet_ntoa(who->sin_addr),
759 notice->z_class, notice->z_class_inst,
760 notice->z_opcode); /* XXX */
762 syslog(LOG_WARNING, "unauth ctl msg from %s",
763 inet_ntoa(who->sin_addr));
765 if (server == me_server)
766 clt_ack(notice, who, AUTH_FAILED);
770 if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM)) {
771 syslog(LOG_WARNING, "Invalid rlm_dispatch instance %s",
772 notice->z_class_inst);
776 if (!strcmp(opcode, REALM_REQ_SUBSCRIBE) || !strcmp(opcode, REALM_ADD_SUBSCRIBE)) {
777 /* try to add subscriptions */
778 /* attempts to get defaults are ignored */
779 if ((status = subscr_foreign_user(notice, who, server, realm)) != ZERR_NONE) {
780 clt_ack(notice, who, AUTH_FAILED);
781 } else if (server == me_server) {
782 server_forward(notice, auth, who);
785 } else if (!strcmp(opcode, REALM_UNSUBSCRIBE)) {
786 /* try to remove subscriptions */
787 if ((status = subscr_realm_cancel(who, notice, realm)) != ZERR_NONE) {
788 clt_ack(notice, who, NOT_FOUND);
789 } else if (server == me_server) {
790 server_forward(notice, auth, who);
793 } else if (!strcmp(opcode, REALM_BOOT)) {
794 zdbug((LOG_DEBUG, "got a REALM_BOOT from %d (me %d)", server, me_server));
795 realm->state = REALM_STARTING;
796 realm_set_server(who, realm);
798 /* resend subscriptions but only if this was to us */
799 if (server == me_server) {
800 if ((status = subscr_realm_subs(realm)) != ZERR_NONE) {
801 clt_ack(notice, who, NOT_FOUND);
803 /* do forward the hint in case it ever matters */
804 server_forward(notice, auth, who);
809 } else if (!strcmp(opcode, SERVER_SHUTDOWN)) {
810 /* try to remove subscriptions */
811 if ((status = realm_new_server(who, notice, realm)) != ZERR_NONE) {
812 clt_ack(notice, who, NOT_FOUND);
813 } else if (server == me_server) {
814 server_forward(notice, auth, who);
818 syslog(LOG_WARNING, "%s unknown/illegal ctl opcode %s",
819 realm->name, opcode);
820 if (server == me_server)
828 realm_new_server(struct sockaddr_in *sin,
833 char suggested_server[MAXHOSTNAMELEN];
836 struct sockaddr_in sinaddr;
842 srvidx = realm_get_idx_by_addr(realm, sin);
843 zdbug((LOG_DEBUG, "rlm_new_srv: message from %d in %s (%s)",
844 srvidx, realm->name, inet_ntoa(sin->sin_addr)));
845 if (realm->idx == srvidx) {
846 if (notice->z_message_len) {
847 addr = inet_addr(notice->z_message);
848 sinaddr.sin_addr.s_addr = addr;
849 rlm = realm_which_realm(&sinaddr);
851 if (!rlm || (rlm != realm))
853 realm->idx = realm_get_idx_by_addr(realm, &sinaddr);
855 realm->idx = (realm->idx + 1) % realm->count;
857 zdbug((LOG_DEBUG, "rlm_new_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
859 zdbug((LOG_DEBUG, "rlm_new_srv: not switching servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
864 realm_set_server(struct sockaddr_in *sin,
869 rlm = realm_which_realm(sin);
871 if (!rlm || (rlm != realm))
873 realm->idx = realm_get_idx_by_addr(realm, sin);
874 zdbug((LOG_DEBUG, "rlm_pick_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
878 realm_handoff(ZNotice_t *notice,
880 struct sockaddr_in *who,
888 zdbug((LOG_DEBUG, "realm_sendit unauthentic to realm %s",
890 realm_sendit(notice, who, auth, realm, ack_to_sender);
894 if (!ticket_lookup(realm->name))
895 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
896 syslog(LOG_WARNING, "rlm_handoff failed: %s",
897 error_message(retval));
898 realm_sendit(notice, who, auth, realm, ack_to_sender);
902 zdbug((LOG_DEBUG, "realm_sendit to realm %s auth %d", realm->name, auth));
903 /* valid ticket available now, send the message */
904 retval = realm_sendit_auth(notice, who, auth, realm, ack_to_sender);
905 #else /* HAVE_KRB4 */
906 realm_sendit(notice, who, auth, realm, ack_to_sender);
907 #endif /* HAVE_KRB4 */
911 realm_sendit(ZNotice_t *notice,
912 struct sockaddr_in *who,
922 notice->z_auth = auth;
924 /* format the notice */
925 if ((retval = ZFormatRawNotice(notice, &pack, &packlen)) != ZERR_NONE) {
926 syslog(LOG_WARNING, "rlm_sendit format: %s",
927 error_message(retval));
932 if ((retval = ZSetDestAddr(&realm->addrs[realm->idx])) != ZERR_NONE) {
933 syslog(LOG_WARNING, "rlm_sendit set addr: %s",
934 error_message(retval));
938 if ((retval = ZSendPacket(pack, packlen, 0)) != ZERR_NONE) {
939 syslog(LOG_WARNING, "rlm_sendit xmit: %s", error_message(retval));
944 /* now we've sent it, mark it as not ack'ed */
946 if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
947 /* no space: just punt */
948 syslog(LOG_ERR, "rlm_sendit nack malloc");
953 nacked->client = NULL;
955 nacked->packet = pack;
956 nacked->dest.rlm.rlm_idx = realm - otherrealms;
957 nacked->dest.rlm.rlm_srv_idx = realm->idx;
958 nacked->packsz = packlen;
959 nacked->uid = notice->z_uid;
961 nacked->ack_addr = *who;
963 nacked->ack_addr.sin_addr.s_addr = 0;
965 /* set a timer to retransmit */
966 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
968 LIST_INSERT(&rlm_nacklist, nacked);
973 packet_ctl_nack(Unacked *nackpacket)
977 /* extract the notice */
978 ZParseNotice(nackpacket->packet, nackpacket->packsz, ¬ice);
979 if (nackpacket->ack_addr.sin_addr.s_addr != 0)
980 nack(¬ice, &nackpacket->ack_addr);
983 syslog(LOG_WARNING, "would have acked nobody (%s/%s/%s)",
984 notice.z_class, notice.z_class_inst, notice.z_opcode); /* XXX */
989 rlm_rexmit(void *arg)
991 Unacked *nackpacket = (Unacked *) arg;
993 register ZRealm *realm;
996 zdbug((LOG_DEBUG,"rlm_rexmit"));
998 realm = &otherrealms[nackpacket->dest.rlm.rlm_idx];
1000 zdbug((LOG_DEBUG, "rlm_rexmit: sending to %s:%d (%d)",
1001 realm->name, realm->idx, nackpacket->rexmits));
1003 if (realm->count == 0)
1006 /* Check to see if we've retransmitted as many times as we can */
1007 if (nackpacket->rexmits >= (NUM_REXMIT_TIMES * realm->count)) {
1008 /* give a server ack that the packet is lost/realm dead */
1009 packet_ctl_nack(nackpacket);
1010 LIST_DELETE(nackpacket);
1012 zdbug((LOG_DEBUG, "rlm_rexmit: %s appears dead", realm->name));
1013 realm->state = REALM_DEAD;
1015 free(nackpacket->packet);
1020 /* if we've reached our limit, move on to the next server */
1021 if ((realm->state == REALM_TARDY) ||
1022 (nackpacket->rexmits &&
1023 !((nackpacket->rexmits+1) % (NUM_REXMIT_TIMES/3))))
1025 realm->idx = (realm->idx + 1) % realm->count;
1026 zdbug((LOG_DEBUG, "rlm_rexmit: %s switching servers:%d (%s)",
1027 realm->name, realm->idx,
1028 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1031 /* throttle back if it looks like the realm is down */
1032 if ((realm->state != REALM_DEAD) ||
1033 ((nackpacket->rexmits % (realm->count+1)) == 1)) {
1034 /* do the retransmit */
1035 retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1036 if (retval != ZERR_NONE) {
1037 syslog(LOG_WARNING, "rlm_rexmit set addr: %s",
1038 error_message(retval));
1040 retval = ZSendPacket(nackpacket->packet, nackpacket->packsz, 0);
1041 if (retval != ZERR_NONE)
1042 syslog(LOG_WARNING, "rlm_rexmit xmit: %s",
1043 error_message(retval));
1045 /* no per-server nack queues for foreign realms yet, doesn't matter */
1046 nackpacket->dest.rlm.rlm_srv_idx = realm->idx;
1047 zdbug((LOG_DEBUG, "rlm_rexmit(%s): send to %s", realm->name,
1048 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1050 zdbug((LOG_DEBUG, "rlm_rexmit(%s): not sending to %s", realm->name,
1051 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1054 /* reset the timer */
1055 nackpacket->rexmits++;
1057 timer_set_rel(rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES],
1058 rlm_rexmit, nackpacket);
1059 if (rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES] == -1)
1060 zdbug((LOG_DEBUG, "rlm_rexmit(%s): would send at -1 to %s",
1061 realm->name, inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1067 realm_dump_realms(FILE *fp)
1069 register int ii, jj;
1071 for (ii = 0; ii < nrealms; ii++) {
1072 (void) fprintf(fp, "%d:%s\n", ii, otherrealms[ii].name);
1073 for (jj = 0; jj < otherrealms[ii].count; jj++) {
1074 (void) fprintf(fp, "\t%s\n",
1075 inet_ntoa(otherrealms[ii].addrs[jj].sin_addr));
1078 subscr_dump_subs(fp, otherrealms[ii].subs);
1084 realm_sendit_auth(ZNotice_t *notice,
1085 struct sockaddr_in *who,
1092 int buffer_len, hdrlen, offset, fragsize, ret_len, message_len;
1093 int origoffset, origlen;
1096 char buf[1024], multi[64];
1097 ZNotice_t partnotice, newnotice;
1101 buffer = (char *) malloc(sizeof(ZPacket_t));
1103 syslog(LOG_ERR, "realm_sendit_auth malloc");
1104 return ENOMEM; /* DON'T put on nack list */
1107 buffer_len = sizeof(ZPacket_t);
1109 newnotice = *notice;
1112 retval = ZMakeZcodeRealmAuthentication(&newnotice, buffer, buffer_len,
1113 &hdrlen, realm->name);
1114 if (retval != ZERR_NONE) {
1115 syslog(LOG_WARNING, "rlm_sendit_auth make zcksum: %s",
1116 error_message(retval));
1120 /* set the dest addr */
1121 retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1122 if (retval != ZERR_NONE) {
1123 syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s",
1124 error_message(retval));
1128 /* This is not terribly pretty, but it does do its job.
1129 * If a packet we get that needs to get sent off to another realm is
1130 * too big after we slap on our authent, we refragment it further,
1131 * a la Z_SendFragmentedNotice. This obviates the need for what
1132 * used to be done in ZFormatAuthenticRealmNotice, as we do it here.
1133 * At some point it should be pulled back out into its own function,
1134 * but only the server uses it.
1137 if ((notice->z_message_len+hdrlen > buffer_len) ||
1138 (notice->z_message_len+hdrlen > Z_MAXPKTLEN)) {
1140 /* Reallocate buffers inside the refragmenter */
1143 partnotice = *notice;
1146 origlen = notice->z_message_len;
1148 if (notice->z_multinotice && strcmp(notice->z_multinotice, ""))
1149 if (sscanf(notice->z_multinotice, "%d/%d", &origoffset,
1151 syslog(LOG_WARNING, "rlm_sendit_auth frag: parse failed");
1152 return ZERR_BADFIELD;
1156 zdbug((LOG_DEBUG,"rlm_send_auth: orig: %d-%d/%d", origoffset,
1157 notice->z_message_len, origlen));
1160 fragsize = Z_MAXPKTLEN-hdrlen-Z_FRAGFUDGE;
1162 while (offset < notice->z_message_len || !notice->z_message_len) {
1163 (void) sprintf(multi, "%d/%d", offset+origoffset, origlen);
1164 partnotice.z_multinotice = multi;
1166 (void) Z_gettimeofday(&partnotice.z_uid.tv,
1167 (struct timezone *)0);
1168 partnotice.z_uid.tv.tv_sec = htonl((u_long)
1169 partnotice.z_uid.tv.tv_sec);
1170 partnotice.z_uid.tv.tv_usec =
1171 htonl((u_long) partnotice.z_uid.tv.tv_usec);
1172 (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
1175 message_len = min(notice->z_message_len-offset, fragsize);
1176 partnotice.z_message = notice->z_message+offset;
1177 partnotice.z_message_len = message_len;
1180 zdbug((LOG_DEBUG,"rlm_send_auth: new: %d-%d/%d",
1181 origoffset+offset, message_len, origlen));
1184 buffer = (char *) malloc(sizeof(ZPacket_t));
1186 syslog(LOG_ERR, "realm_sendit_auth malloc");
1187 return ENOMEM; /* DON'T put on nack list */
1190 buffer_len = sizeof(ZPacket_t);
1192 retval = ZMakeZcodeRealmAuthentication(&partnotice, buffer,
1193 buffer_len, &hdrlen,
1195 if (retval != ZERR_NONE) {
1196 syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s",
1197 error_message(retval));
1202 ptr = buffer+hdrlen;
1204 (void) memcpy(ptr, partnotice.z_message, partnotice.z_message_len);
1206 buffer_len = hdrlen+partnotice.z_message_len;
1209 if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
1210 syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
1211 error_message(retval));
1216 if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
1217 /* no space: just punt */
1218 syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
1223 nacked->rexmits = 0;
1224 nacked->packet = buffer;
1225 nacked->dest.rlm.rlm_idx = realm - otherrealms;
1226 nacked->dest.rlm.rlm_srv_idx = realm->idx;
1227 nacked->packsz = buffer_len;
1228 nacked->uid = partnotice.z_uid;
1230 /* Do the ack for the last frag, below */
1232 nacked->ack_addr = *who;
1234 nacked->ack_addr.sin_addr.s_addr = 0;
1236 /* set a timer to retransmit */
1237 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
1240 LIST_INSERT(&rlm_nacklist, nacked);
1244 if (!notice->z_message_len)
1249 /* This is easy, no further fragmentation needed */
1250 ptr = buffer+hdrlen;
1252 (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len);
1254 buffer_len = hdrlen+newnotice.z_message_len;
1257 if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
1258 syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
1259 error_message(retval));
1264 /* now we've sent it, mark it as not ack'ed */
1266 if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
1267 /* no space: just punt */
1268 syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
1273 nacked->rexmits = 0;
1274 nacked->packet = buffer;
1275 nacked->dest.rlm.rlm_idx = realm - otherrealms;
1276 nacked->dest.rlm.rlm_srv_idx = realm->idx;
1277 nacked->packsz = buffer_len;
1278 nacked->uid = notice->z_uid;
1280 /* Do the ack for the last frag, below */
1282 nacked->ack_addr = *who;
1284 nacked->ack_addr.sin_addr.s_addr = 0;
1286 /* set a timer to retransmit */
1287 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
1289 LIST_INSERT(&rlm_nacklist, nacked);
1295 ticket_lookup(char *realm)
1297 krb5_error_code result;
1300 krb5_creds creds_in, *creds;
1302 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1306 memset(&creds_in, 0, sizeof(creds_in));
1308 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1310 krb5_cc_close(Z_krb5_ctx, ccache);
1314 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1317 SERVER_KRB5_SERVICE, SERVER_INSTANCE, 0);
1319 krb5_cc_close(Z_krb5_ctx, ccache);
1323 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1325 krb5_cc_close(Z_krb5_ctx, ccache);
1328 krb5_timeofday (Z_krb5_ctx, &sec);
1329 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1330 if ((result == 0) && (sec < creds->times.endtime)) {
1331 krb5_free_creds(Z_krb5_ctx, creds);
1334 if (!result) krb5_free_creds(Z_krb5_ctx, creds);
1340 ticket_retrieve(ZRealm *realm)
1344 krb5_error_code result;
1345 krb5_auth_context authctx;
1346 krb5_creds creds_in, *creds;
1350 if (realm->child_pid)
1351 /* Right idea. Basically, we haven't gotten it yet */
1352 return KRB5KRB_AP_ERR_TKT_EXPIRED;
1354 if (realm->have_tkt) {
1355 /* Get a pointer to the default ccache. We don't need to free this. */
1356 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1358 /* GRRR. There's no allocator or constructor for krb5_creds */
1359 /* GRRR. It would be nice if this API were documented at all */
1360 memset(&creds_in, 0, sizeof(creds_in));
1363 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1364 /* construct the service principal */
1366 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1367 strlen(realm->name), realm->name,
1368 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1371 /* HOLDING: creds_in.server */
1373 /* look up or get the credentials we need */
1375 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1377 krb5_cc_close(Z_krb5_ctx, ccache);
1378 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1380 krb5_free_creds(Z_krb5_ctx, creds);
1384 syslog(LOG_ERR, "tkt_rtrv: don't have ticket, but have no child");
1385 result = KRB5KRB_AP_ERR_TKT_EXPIRED;
1390 syslog(LOG_ERR, "tkt_rtrv: can't fork");
1391 return KRBET_KDC_AUTH_EXP;
1393 else if (pid == 0) {
1394 #ifdef _POSIX_VERSION
1395 struct sigaction action;
1397 action.sa_flags = 0;
1398 sigemptyset(&action.sa_mask);
1399 action.sa_handler = 0;
1400 sigaction(SIGCHLD, &action, NULL);
1401 sigaction(SIGINT, &action, NULL);
1402 sigaction(SIGTERM, &action, NULL);
1403 sigaction(SIGUSR1, &action, NULL);
1404 sigaction(SIGUSR2, &action, NULL);
1405 sigaction(SIGFPE, &action, NULL);
1406 sigaction(SIGHUP, &action, NULL);
1408 sigaction(SIGEMT, &action, NULL);
1411 signal(SIGCHLD, SIG_DFL);
1412 signal(SIGINT, SIG_DFL);
1413 signal(SIGTERM, SIG_DFL);
1414 signal(SIGUSR1, SIG_DFL);
1415 signal(SIGUSR2, SIG_DFL);
1416 signal(SIGFPE, SIG_DFL);
1417 signal(SIGHUP, SIG_DFL);
1419 signal(SIGEMT, SIG_DFL);
1423 syslog(LOG_INFO, "tkt_rtrv running for %s", realm->name);
1425 /* Get a pointer to the default ccache. We don't need to free this. */
1426 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1428 /* GRRR. There's no allocator or constructor for krb5_creds */
1429 /* GRRR. It would be nice if this API were documented at all */
1430 memset(&creds_in, 0, sizeof(creds_in));
1433 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1434 /* construct the service principal */
1436 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1437 strlen(realm->name), realm->name,
1438 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1441 /* HOLDING: creds_in.server */
1443 /* look up or get the credentials we need */
1445 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1447 krb5_cc_close(Z_krb5_ctx, ccache);
1448 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1450 krb5_free_creds(Z_krb5_ctx, creds);
1451 syslog(LOG_INFO, "tkt_rtrv succeeded for %s", realm->name);
1455 /* Sleep a little while before retrying */
1459 realm->child_pid = pid;
1460 realm->have_tkt = 0;
1462 syslog(LOG_WARNING, "tkt_rtrv: %s: %d", realm->name,
1467 #endif /* HAVE_KRB5 */