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);
65 static Code_t realm_sendit_auth(ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender);
67 static void rlm_ack(ZNotice_t *notice, Unacked *nacked);
68 static void rlm_nack_cancel(ZNotice_t *notice, struct sockaddr_in *who);
69 static void rlm_rexmit(void *arg);
70 static Code_t realm_ulocate_dispatch(ZNotice_t *notice,int auth,struct sockaddr_in *who,Server *server,ZRealm *realm);
71 static Code_t realm_new_server(struct sockaddr_in *, ZNotice_t *, ZRealm *);
72 static Code_t realm_set_server(struct sockaddr_in *, ZRealm *);
74 static Code_t ticket_retrieve(ZRealm *realm);
75 static int ticket_lookup(char *realm);
79 realm_get_idx_by_addr(ZRealm *realm,
80 struct sockaddr_in *who)
82 struct sockaddr_in *addr;
85 /* loop through the realms */
86 for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
87 if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
94 realm_expand_realm(char *realmname)
99 /* First, look for an exact match (case insensitive) */
100 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
101 if (!strcasecmp(ZGetRealm(), realmname))
105 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
106 if (!strcasecmp(realm->name, realmname))
109 /* No exact match. See if there's a partial match */
110 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
111 if (!strncasecmp(ZGetRealm(), realmname, strlen(realmname)))
115 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
116 if (!strncasecmp(realm->name, realmname, strlen(realmname)))
122 realm_get_realm_by_pid(int pid)
127 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
128 if (realm->child_pid == pid)
135 kill_realm_pids(void)
140 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
141 if (realm->child_pid != 0)
142 kill(realm->child_pid, 9);
148 get_realm_lists(char *file)
150 ZRealmname *rlm_list, *rlm;
151 int ii, nused, ntotal;
153 char buf[REALM_SZ + NS_MAXDNAME + 1]; /* one for newline */
154 char realm[REALM_SZ], server[NS_MAXDNAME + 1];
157 if (!(fp = fopen(file, "r")))
158 return((ZRealmname *)0);
160 /* start with 16, realloc if necessary */
162 rlm_list = (ZRealmname *)malloc(ntotal * sizeof(ZRealmname));
164 syslog(LOG_CRIT, "get_realm_lists malloc");
168 while (fgets(buf, sizeof(buf), fp)) {
169 if (sscanf(buf, "%s %s", realm, server) != 2) {
170 syslog(LOG_CRIT, "bad format in %s", file);
173 for (ii = 0; ii < nused; ii++) {
174 /* look for this realm */
175 if (!strcmp(rlm_list[ii].name, realm))
180 if (rlm->nused +1 >= rlm->nservers) {
181 /* make more space */
182 rlm->servers = (char **)realloc((char *)rlm->servers,
183 (unsigned)rlm->nservers * 2 *
186 syslog(LOG_CRIT, "get_realm_lists realloc");
191 rlm->servers[rlm->nused++] = strsave(server);
194 if (nused + 1 >= ntotal) {
195 /* make more space */
196 rlm_list = (ZRealmname *)realloc((char *)rlm_list,
197 (unsigned)ntotal * 2 *
200 syslog(LOG_CRIT, "get_realm_lists realloc");
205 rlm = &rlm_list[nused++];
206 strcpy(rlm->name, realm);
209 rlm->servers = (char **)malloc(rlm->nservers * sizeof(char *));
211 syslog(LOG_CRIT, "get_realm_lists malloc");
214 rlm->servers[rlm->nused++] = strsave(server);
217 if (nused + 1 >= ntotal) {
218 rlm_list = (ZRealmname *)realloc((char *)rlm_list,
219 (unsigned)(ntotal + 1) *
222 syslog(LOG_CRIT, "get_realm_lists realloc");
226 *rlm_list[nused].name = '\0';
233 realm_send_realms(void)
236 for (cnt = 0; cnt < nrealms; cnt++) {
237 retval = subscr_send_realm_subs(&otherrealms[cnt]);
238 if (retval != ZERR_NONE)
245 realm_bound_for_realm(const char *realm, char *recip)
248 int remote = strcmp(ZGetRealm(), realm);
251 rlm = strchr(recip, '@');
256 if (rlm && strcmp(realm_expand_realm(rlm + 1), realm) == 0)
263 realm_sender_in_realm(const char *realm, char *sender)
266 int remote = strcmp(ZGetRealm(), realm);
269 rlm = strchr(sender, '@');
274 if (rlm && strcmp((rlm + 1), realm) == 0)
280 int sender_in_realm(ZNotice_t *notice)
284 realm = strchr(notice->z_sender, '@');
286 if (!realm || !strcmp(realm + 1, ZGetRealm()))
293 realm_which_realm(struct sockaddr_in *who)
296 struct sockaddr_in *addr;
299 if (who->sin_port != srv_addr.sin_port)
302 /* loop through the realms */
303 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
304 /* loop through the addresses for the realm */
305 for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
306 if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
313 realm_get_realm_by_name(char *name)
318 /* First, look for an exact match (case insensitive) */
319 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
320 if (!strcasecmp(realm->name, name))
323 /* Failing that, look for an inexact match */
324 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
325 if (!strncasecmp(realm->name, name, strlen(name)))
332 rlm_nack_cancel(register ZNotice_t *notice,
333 struct sockaddr_in *who)
335 register ZRealm *which = realm_which_realm(who);
336 register Unacked *nacked;
338 zdbug((LOG_DEBUG, "rlm_nack_cancel: %s:%08X,%08X",
339 inet_ntoa(notice->z_uid.zuid_addr),
340 notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
343 syslog(LOG_ERR, "non-realm ack?");
347 for (nacked = rlm_nacklist; nacked; nacked = nacked->next) {
348 if (&otherrealms[nacked->dest.rlm.rlm_idx] == which) {
349 /* First, note the realm appears to be up */
350 which->state = REALM_UP;
351 if (ZCompareUID(&nacked->uid, ¬ice->z_uid)) {
352 timer_reset(nacked->timer);
354 if (nacked->ack_addr.sin_addr.s_addr)
355 rlm_ack(notice, nacked);
358 free(nacked->packet);
359 Unacked_delete(nacked);
369 rlm_ack(ZNotice_t *notice,
377 /* tell the original sender the result */
379 acknotice.z_message_len = strlen(acknotice.z_message) + 1;
381 packlen = sizeof(ackpack);
383 if ((retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen))
385 syslog(LOG_ERR, "rlm_ack format: %s",
386 error_message(retval));
389 zdbug((LOG_DEBUG, "rlm_ack sending to %s/%d",
390 inet_ntoa(nacked->ack_addr.sin_addr),
391 ntohs(nacked->ack_addr.sin_port)));
392 if ((retval = ZSetDestAddr(&nacked->ack_addr)) != ZERR_NONE) {
393 syslog(LOG_WARNING, "rlm_ack set addr: %s",
394 error_message(retval));
397 if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) {
398 syslog(LOG_WARNING, "rlm_ack xmit: %s", error_message(retval));
404 realm_dispatch(ZNotice_t *notice,
406 struct sockaddr_in *who,
410 Code_t status = ZERR_NONE;
411 char rlm_recipient[REALM_SZ + 1];
413 String *notice_class;
415 if (notice->z_kind == SERVACK || notice->z_kind == SERVNAK) {
416 rlm_nack_cancel(notice, who);
420 /* check if it's a control message */
421 realm = realm_which_realm(who);
423 notice_class = make_string(notice->z_class,1);
425 if (class_is_admin(notice_class)) {
426 syslog(LOG_WARNING, "%s sending admin opcode %s",
427 realm->name, notice->z_opcode);
428 } else if (class_is_hm(notice_class)) {
429 syslog(LOG_WARNING, "%s sending hm opcode %s",
430 realm->name, notice->z_opcode);
431 } else if (class_is_control(notice_class)) {
432 status = realm_control_dispatch(notice, auth, who,
434 } else if (class_is_ulogin(notice_class)) {
435 /* don't need to forward this */
436 if (server == me_server) {
437 sprintf(rlm_recipient, "@%s", realm->name);
438 notice->z_recipient = rlm_recipient;
440 sendit(notice, 1, who, 0);
442 } else if (class_is_ulocate(notice_class)) {
443 status = realm_ulocate_dispatch(notice, auth, who, server, realm);
445 /* redo the recipient */
446 if (*notice->z_recipient == '\0') {
447 sprintf(rlm_recipient, "@%s", realm->name);
448 notice->z_recipient = rlm_recipient;
450 } else if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient)
451 && *notice->z_recipient == '@')
453 /* we're responsible for getting this message out */
455 notice->z_recipient = "";
458 /* otherwise, send to local subscribers */
459 sendit(notice, auth, who, external);
469 ZRealmname *rlmnames;
472 struct in_addr *addresses;
475 char rlmprinc[MAX_PRINCIPAL_SIZE];
477 sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, REALM_LIST_FILE);
478 rlmnames = get_realm_lists(list_file);
480 zdbug((LOG_DEBUG, "No other realms"));
485 for (nrealms = 0; *rlmnames[nrealms].name; nrealms++);
487 otherrealms = (ZRealm *)malloc(nrealms * sizeof(ZRealm));
489 syslog(LOG_CRIT, "malloc failed in realm_init");
493 for (ii = 0; ii < nrealms; ii++) {
494 rlm = &otherrealms[ii];
495 strcpy(rlm->name, rlmnames[ii].name);
497 addresses = (struct in_addr *)malloc(rlmnames[ii].nused *
498 sizeof(struct in_addr));
500 syslog(LOG_CRIT, "malloc failed in realm_init");
503 /* convert names to addresses */
505 for (jj = 0; jj < rlmnames[ii].nused; jj++) {
506 hp = gethostbyname(rlmnames[ii].servers[jj]);
508 memmove(&addresses[found], hp->h_addr,
509 sizeof(struct in_addr));
512 syslog(LOG_WARNING, "hostname failed, %s",
513 rlmnames[ii].servers[jj]);
514 /* free the hostname */
515 free(rlmnames[ii].servers[jj]);
518 rlm->addrs = (struct sockaddr_in *)malloc(found *
519 sizeof (struct sockaddr_in));
521 syslog(LOG_CRIT, "malloc failed in realm_init");
524 for (jj = 0; jj < rlm->count; jj++) {
525 rlm->addrs[jj].sin_family = AF_INET;
526 /* use the server port */
527 rlm->addrs[jj].sin_port = srv_addr.sin_port;
528 rlm->addrs[jj].sin_addr = addresses[jj];
530 client = (Client *) malloc(sizeof(Client));
532 syslog(LOG_CRIT, "malloc failed in realm_init");
535 memset(&client->addr, 0, sizeof(struct sockaddr_in));
537 client->session_keyblock = NULL;
540 memset(&client->session_key, 0, sizeof(client->session_key));
543 snprintf(rlmprinc, MAX_PRINCIPAL_SIZE, "%s.%s@%s", SERVER_SERVICE, SERVER_INSTANCE,
545 client->principal = make_string(rlmprinc, 0);
546 client->last_send = 0;
547 client->last_ack = NOW;
550 client->addr.sin_family = 0;
551 client->addr.sin_port = 0;
552 client->addr.sin_addr.s_addr = 0;
554 rlm->client = client;
555 rlm->idx = (rlm->count) ? random() % rlm->count : 0;
559 /* Assume the best */
560 rlm->state = REALM_TARDY;
562 free(rlmnames[ii].servers);
569 realm_deathgram(Server *server)
574 /* Get it out once, and assume foreign servers will share */
575 for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
578 char rlm_recipient[REALM_SZ + 1];
581 memset (&snotice, 0, sizeof (snotice));
583 snotice.z_kind = ACKED;
584 snotice.z_port = srv_addr.sin_port;
585 snotice.z_class = ZEPHYR_CTL_CLASS;
586 snotice.z_class_inst = ZEPHYR_CTL_REALM;
587 snotice.z_opcode = SERVER_SHUTDOWN;
588 snotice.z_sender = myname; /* my host name */
589 sprintf(rlm_recipient, "@%s", realm->name);
590 snotice.z_recipient = rlm_recipient;
591 snotice.z_default_format = "";
592 snotice.z_num_other_fields = 0;
593 snotice.z_default_format = "";
594 snotice.z_message = (server) ? server->addr_str : NULL;
595 snotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0;
597 zdbug((LOG_DEBUG, "rlm_deathgram: suggesting %s to %s",
598 (server) ? server->addr_str : "nothing", realm->name));
601 if (!ticket_lookup(realm->name))
602 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
603 syslog(LOG_WARNING, "rlm_deathgram failed: %s",
604 error_message(retval));
609 if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZCAUTH))
612 syslog(LOG_WARNING, "rlm_deathgram format: %s",
613 error_message(retval));
616 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
617 syslog(LOG_WARNING, "rlm_deathgram parse: %s",
618 error_message(retval));
623 realm_handoff(&snotice, 1, NULL, realm, 0);
634 for (jj = 1; jj < nservers; jj++) { /* skip limbo server */
635 if (jj != me_server_idx && otherservers[jj].state == SERV_UP)
639 if (nservers < 2 || !found) {
640 /* if we're the only server up, send a REALM_BOOT to one of their
642 for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
645 char rlm_recipient[REALM_SZ + 1];
648 memset (&snotice, 0, sizeof (snotice));
650 snotice.z_opcode = REALM_BOOT;
651 snotice.z_port = srv_addr.sin_port;
652 snotice.z_class_inst = ZEPHYR_CTL_REALM;
653 snotice.z_class = ZEPHYR_CTL_CLASS;
654 snotice.z_recipient = "";
655 snotice.z_kind = ACKED;
656 snotice.z_num_other_fields = 0;
657 snotice.z_default_format = "";
658 snotice.z_sender = myname; /* my host name */
659 sprintf(rlm_recipient, "@%s", realm->name);
660 snotice.z_recipient = rlm_recipient;
661 snotice.z_default_format = "";
662 snotice.z_message = NULL;
663 snotice.z_message_len = 0;
666 if (!ticket_lookup(realm->name))
667 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
668 syslog(LOG_WARNING, "rlm_wakeup failed: %s",
669 error_message(retval));
674 if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH))
677 syslog(LOG_WARNING, "rlm_wakeup format: %s",
678 error_message(retval));
681 if ((retval = ZParseNotice(pack, packlen, &snotice))
683 syslog(LOG_WARNING, "rlm_wakeup parse: %s",
684 error_message(retval));
689 realm_handoff(&snotice, 1, NULL, realm, 0);
696 realm_ulocate_dispatch(ZNotice_t *notice,
698 struct sockaddr_in *who,
702 register char *opcode = notice->z_opcode;
705 syslog(LOG_WARNING, "unauth locate msg from %s (%s/%s/%s)",
706 inet_ntoa(who->sin_addr),
707 notice->z_class, notice->z_class_inst,
708 notice->z_opcode); /* XXX */
709 clt_ack(notice, who, AUTH_FAILED);
713 if (!strcmp(opcode, REALM_REQ_LOCATE)) {
715 ulogin_realm_locate(notice, who, realm);
716 } else if (!strcmp(opcode, REALM_ANS_LOCATE)) {
718 ulogin_relay_locate(notice, who);
720 syslog(LOG_WARNING, "%s unknown/illegal loc opcode %s",
721 realm->name, opcode);
730 realm_control_dispatch(ZNotice_t *notice,
732 struct sockaddr_in *who,
736 register char *opcode = notice->z_opcode;
740 syslog(LOG_WARNING, "unauth ctl msg from %s (%s/%s/%s)",
741 inet_ntoa(who->sin_addr),
742 notice->z_class, notice->z_class_inst,
743 notice->z_opcode); /* XXX */
744 if (server == me_server)
745 clt_ack(notice, who, AUTH_FAILED);
749 if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM)) {
750 syslog(LOG_WARNING, "Invalid rlm_dispatch instance %s",
751 notice->z_class_inst);
755 if (!strcmp(opcode, REALM_REQ_SUBSCRIBE) || !strcmp(opcode, REALM_ADD_SUBSCRIBE)) {
756 /* try to add subscriptions */
757 /* attempts to get defaults are ignored */
758 if ((status = subscr_foreign_user(notice, who, server, realm)) != ZERR_NONE) {
759 clt_ack(notice, who, AUTH_FAILED);
760 } else if (server == me_server) {
761 server_forward(notice, auth, who);
764 } else if (!strcmp(opcode, REALM_UNSUBSCRIBE)) {
765 /* try to remove subscriptions */
766 if ((status = subscr_realm_cancel(who, notice, realm)) != ZERR_NONE) {
767 clt_ack(notice, who, NOT_FOUND);
768 } else if (server == me_server) {
769 server_forward(notice, auth, who);
772 } else if (!strcmp(opcode, REALM_BOOT)) {
773 zdbug((LOG_DEBUG, "got a REALM_BOOT from %d (me %d)", server, me_server));
774 realm->state = REALM_STARTING;
775 realm_set_server(who, realm);
777 /* resend subscriptions but only if this was to us */
778 if (server == me_server) {
779 if ((status = subscr_realm_subs(realm)) != ZERR_NONE) {
780 clt_ack(notice, who, NOT_FOUND);
782 /* do forward the hint in case it ever matters */
783 server_forward(notice, auth, who);
788 } else if (!strcmp(opcode, SERVER_SHUTDOWN)) {
789 /* try to remove subscriptions */
790 if ((status = realm_new_server(who, notice, realm)) != ZERR_NONE) {
791 clt_ack(notice, who, NOT_FOUND);
792 } else if (server == me_server) {
793 server_forward(notice, auth, who);
797 syslog(LOG_WARNING, "%s unknown/illegal ctl opcode %s",
798 realm->name, opcode);
799 if (server == me_server)
807 realm_new_server(struct sockaddr_in *sin,
813 struct sockaddr_in sinaddr;
819 srvidx = realm_get_idx_by_addr(realm, sin);
820 zdbug((LOG_DEBUG, "rlm_new_srv: message from %d in %s (%s)",
821 srvidx, realm->name, inet_ntoa(sin->sin_addr)));
822 if (realm->idx == srvidx) {
823 if (notice->z_message_len) {
824 addr = inet_addr(notice->z_message);
825 sinaddr.sin_addr.s_addr = addr;
826 rlm = realm_which_realm(&sinaddr);
828 if (!rlm || (rlm != realm))
830 realm->idx = realm_get_idx_by_addr(realm, &sinaddr);
832 realm->idx = (realm->idx + 1) % realm->count;
834 zdbug((LOG_DEBUG, "rlm_new_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
836 zdbug((LOG_DEBUG, "rlm_new_srv: not switching servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
842 realm_set_server(struct sockaddr_in *sin,
847 rlm = realm_which_realm(sin);
849 if (!rlm || (rlm != realm))
851 realm->idx = realm_get_idx_by_addr(realm, sin);
852 zdbug((LOG_DEBUG, "rlm_pick_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
858 realm_handoff(ZNotice_t *notice,
860 struct sockaddr_in *who,
868 zdbug((LOG_DEBUG, "realm_sendit unauthentic to realm %s",
870 realm_sendit(notice, who, auth, realm, ack_to_sender);
874 if (!ticket_lookup(realm->name))
875 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
876 syslog(LOG_WARNING, "rlm_handoff failed: %s",
877 error_message(retval));
878 realm_sendit(notice, who, auth, realm, ack_to_sender);
882 zdbug((LOG_DEBUG, "realm_sendit to realm %s auth %d", realm->name, auth));
883 /* valid ticket available now, send the message */
884 retval = realm_sendit_auth(notice, who, auth, realm, ack_to_sender);
885 #else /* HAVE_KRB4 */
886 realm_sendit(notice, who, auth, realm, ack_to_sender);
887 #endif /* HAVE_KRB4 */
891 realm_sendit(ZNotice_t *notice,
892 struct sockaddr_in *who,
902 notice->z_auth = auth;
904 /* format the notice */
905 if ((retval = ZFormatRawNotice(notice, &pack, &packlen)) != ZERR_NONE) {
906 syslog(LOG_WARNING, "rlm_sendit format: %s",
907 error_message(retval));
912 if ((retval = ZSetDestAddr(&realm->addrs[realm->idx])) != ZERR_NONE) {
913 syslog(LOG_WARNING, "rlm_sendit set addr: %s",
914 error_message(retval));
918 if ((retval = ZSendPacket(pack, packlen, 0)) != ZERR_NONE) {
919 syslog(LOG_WARNING, "rlm_sendit xmit: %s", error_message(retval));
924 /* now we've sent it, mark it as not ack'ed */
926 if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
927 /* no space: just punt */
928 syslog(LOG_ERR, "rlm_sendit nack malloc");
933 memset(nacked, 0, sizeof(Unacked));
934 nacked->packet = pack;
935 nacked->dest.rlm.rlm_idx = realm - otherrealms;
936 nacked->dest.rlm.rlm_srv_idx = realm->idx;
937 nacked->packsz = packlen;
938 nacked->uid = notice->z_uid;
940 nacked->ack_addr = *who;
942 nacked->ack_addr.sin_addr.s_addr = 0;
944 /* set a timer to retransmit */
945 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
947 Unacked_insert(&rlm_nacklist, nacked);
952 packet_ctl_nack(Unacked *nackpacket)
956 /* extract the notice */
957 ZParseNotice(nackpacket->packet, nackpacket->packsz, ¬ice);
958 if (nackpacket->ack_addr.sin_addr.s_addr != 0)
959 nack(¬ice, &nackpacket->ack_addr);
961 syslog(LOG_WARNING, "would have acked nobody (%s/%s/%s)",
962 notice.z_class, notice.z_class_inst, notice.z_opcode); /* XXX */
966 rlm_rexmit(void *arg)
968 Unacked *nackpacket = (Unacked *) arg;
970 register ZRealm *realm;
972 zdbug((LOG_DEBUG,"rlm_rexmit"));
974 realm = &otherrealms[nackpacket->dest.rlm.rlm_idx];
976 zdbug((LOG_DEBUG, "rlm_rexmit: sending to %s:%d (%d)",
977 realm->name, realm->idx, nackpacket->rexmits));
979 if (realm->count == 0)
982 /* Check to see if we've retransmitted as many times as we can */
983 if (nackpacket->rexmits >= (NUM_REXMIT_TIMES * realm->count)) {
984 /* give a server ack that the packet is lost/realm dead */
985 packet_ctl_nack(nackpacket);
986 Unacked_delete(nackpacket);
988 zdbug((LOG_DEBUG, "rlm_rexmit: %s appears dead", realm->name));
989 realm->state = REALM_DEAD;
991 free(nackpacket->packet);
996 /* if we've reached our limit, move on to the next server */
997 if ((realm->state == REALM_TARDY) ||
998 (nackpacket->rexmits &&
999 !((nackpacket->rexmits+1) % (NUM_REXMIT_TIMES/3))))
1001 realm->idx = (realm->idx + 1) % realm->count;
1002 zdbug((LOG_DEBUG, "rlm_rexmit: %s switching servers:%d (%s)",
1003 realm->name, realm->idx,
1004 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1007 /* throttle back if it looks like the realm is down */
1008 if ((realm->state != REALM_DEAD) ||
1009 ((nackpacket->rexmits % (realm->count+1)) == 1)) {
1010 /* do the retransmit */
1011 retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1012 if (retval != ZERR_NONE) {
1013 syslog(LOG_WARNING, "rlm_rexmit set addr: %s",
1014 error_message(retval));
1016 retval = ZSendPacket(nackpacket->packet, nackpacket->packsz, 0);
1017 if (retval != ZERR_NONE)
1018 syslog(LOG_WARNING, "rlm_rexmit xmit: %s",
1019 error_message(retval));
1021 /* no per-server nack queues for foreign realms yet, doesn't matter */
1022 nackpacket->dest.rlm.rlm_srv_idx = realm->idx;
1023 zdbug((LOG_DEBUG, "rlm_rexmit(%s): send to %s", realm->name,
1024 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1026 zdbug((LOG_DEBUG, "rlm_rexmit(%s): not sending to %s", realm->name,
1027 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1030 /* reset the timer */
1031 nackpacket->rexmits++;
1033 timer_set_rel(rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES],
1034 rlm_rexmit, nackpacket);
1035 if (rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES] == -1)
1036 zdbug((LOG_DEBUG, "rlm_rexmit(%s): would send at -1 to %s",
1037 realm->name, inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1043 realm_dump_realms(FILE *fp)
1045 register int ii, jj;
1047 for (ii = 0; ii < nrealms; ii++) {
1048 (void) fprintf(fp, "%d:%s\n", ii, otherrealms[ii].name);
1049 for (jj = 0; jj < otherrealms[ii].count; jj++) {
1050 (void) fprintf(fp, "\t%s\n",
1051 inet_ntoa(otherrealms[ii].addrs[jj].sin_addr));
1054 subscr_dump_subs(fp, otherrealms[ii].subs);
1061 realm_auth_sendit_nacked(char *buffer, int packlen, ZRealm *realm,
1062 ZUnique_Id_t uid, int ack_to_sender,
1063 struct sockaddr_in *who)
1067 nacked = (Unacked *) malloc(sizeof(Unacked));
1071 memset(nacked, 0, sizeof(Unacked));
1072 nacked->packet = buffer;
1073 nacked->dest.rlm.rlm_idx = realm - otherrealms;
1074 nacked->dest.rlm.rlm_srv_idx = realm->idx;
1075 nacked->packsz = packlen;
1078 /* Do the ack for the last frag, below */
1080 nacked->ack_addr = *who;
1082 nacked->ack_addr.sin_addr.s_addr = 0;
1084 /* set a timer to retransmit */
1085 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
1088 Unacked_insert(&rlm_nacklist, nacked);
1094 realm_sendit_auth(ZNotice_t *notice,
1095 struct sockaddr_in *who,
1100 char *buffer = NULL;
1101 int hdrlen, offset, fragsize, message_len;
1102 int origoffset, origlen;
1105 ZNotice_t partnotice, newnotice;
1109 buffer = (char *)malloc(sizeof(ZPacket_t));
1111 syslog(LOG_ERR, "realm_sendit_auth malloc");
1112 return ENOMEM; /* DON'T put on nack list */
1115 newnotice = *notice;
1118 retval = ZMakeZcodeRealmAuthentication(&newnotice, buffer, sizeof(ZPacket_t),
1119 &hdrlen, realm->name);
1122 "rlm_sendit_auth: ZMakeZcodeRealmAuthentication: %s",
1123 error_message(retval));
1126 retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1128 syslog(LOG_WARNING, "rlm_sendit_auth: ZSetDestAddr: %s",
1129 error_message(retval));
1132 /* This is not terribly pretty, but it does do its job.
1133 * If a packet we get that needs to get sent off to another realm is
1134 * too big after we slap on our authent, we refragment it further,
1135 * a la Z_SendFragmentedNotice. This obviates the need for what
1136 * used to be done in ZFormatAuthenticRealmNotice, as we do it here.
1137 * At some point it should be pulled back out into its own function,
1138 * but only the server uses it.
1142 ((notice->z_message_len+hdrlen > sizeof(ZPacket_t)) ||
1143 (notice->z_message_len+hdrlen > Z_MAXPKTLEN))) {
1145 /* Reallocate buffers inside the refragmenter */
1149 partnotice = *notice;
1152 origlen = notice->z_message_len;
1154 if (notice->z_multinotice && strcmp(notice->z_multinotice, "")) {
1155 if (sscanf(notice->z_multinotice, "%d/%d", &origoffset,
1158 "rlm_sendit_auth frag: multinotice parse failed");
1159 retval = ZERR_BADFIELD;
1163 fragsize = Z_MAXPKTLEN - hdrlen - Z_FRAGFUDGE;
1166 retval = ZERR_HEADERLEN;
1169 (offset < notice->z_message_len || !notice->z_message_len)) {
1170 (void)sprintf(multi, "%d/%d", offset+origoffset, origlen);
1171 partnotice.z_multinotice = multi;
1173 (void)Z_gettimeofday(&partnotice.z_uid.tv,
1174 (struct timezone *)0);
1175 partnotice.z_uid.tv.tv_sec = htonl((u_long)
1176 partnotice.z_uid.tv.tv_sec);
1177 partnotice.z_uid.tv.tv_usec =
1178 htonl((u_long) partnotice.z_uid.tv.tv_usec);
1179 (void)memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
1181 partnotice.z_sender_sockaddr.ip4.sin_family = AF_INET; /* XXX */
1182 (void)memcpy((char *)&partnotice.z_sender_sockaddr.ip4.sin_addr,
1183 &__My_addr, sizeof(__My_addr));
1185 message_len = min(notice->z_message_len-offset, fragsize);
1186 partnotice.z_message = notice->z_message+offset;
1187 partnotice.z_message_len = message_len;
1189 buffer = (char *)malloc(sizeof(ZPacket_t));
1191 syslog(LOG_ERR, "realm_sendit_auth malloc");
1192 retval = ENOMEM; /* DON'T put on nack list */
1196 retval = ZMakeZcodeRealmAuthentication(&partnotice, buffer,
1200 if (retval != ZERR_NONE)
1201 syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s",
1202 error_message(retval));
1206 (void) memcpy(buffer + hdrlen, partnotice.z_message,
1207 partnotice.z_message_len);
1209 retval = ZSendPacket(buffer,
1210 hdrlen + partnotice.z_message_len, 0);
1212 syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
1213 error_message(retval));
1217 retval = realm_auth_sendit_nacked(buffer, hdrlen +
1218 partnotice.z_message_len,realm,
1220 ack_to_sender, who);
1221 if (retval) /* no space: just punt */
1223 "rlm_sendit_auth: realm_auth_sendit_nacked: %s",
1224 error_message(retval));
1230 if (!notice->z_message_len)
1233 } else if (!retval) {
1234 /* This is easy, no further fragmentation needed */
1235 (void)memcpy(buffer + hdrlen, newnotice.z_message,
1236 newnotice.z_message_len);
1238 retval = ZSendPacket(buffer, hdrlen + newnotice.z_message_len, 0);
1240 syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
1241 error_message(retval));
1243 retval = realm_auth_sendit_nacked(buffer,
1244 hdrlen + newnotice.z_message_len,
1245 realm, newnotice.z_uid,
1246 ack_to_sender, who);
1247 if (retval) /* no space: just punt */
1248 syslog(LOG_ERR, "rlm_sendit_auth: realm_auth_sendit_nacked: %s",
1249 error_message(retval));
1253 if (retval && buffer != NULL)
1259 ticket_lookup(char *realm)
1261 krb5_error_code result;
1264 krb5_creds creds_in, *creds;
1266 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1270 memset(&creds_in, 0, sizeof(creds_in));
1272 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1274 krb5_cc_close(Z_krb5_ctx, ccache);
1278 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1281 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1284 krb5_cc_close(Z_krb5_ctx, ccache);
1288 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1290 krb5_cc_close(Z_krb5_ctx, ccache);
1293 krb5_timeofday (Z_krb5_ctx, &sec);
1294 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1295 if ((result == 0) && (sec < creds->times.endtime)) {
1296 krb5_free_creds(Z_krb5_ctx, creds);
1299 if (!result) krb5_free_creds(Z_krb5_ctx, creds);
1305 ticket_retrieve(ZRealm *realm)
1309 krb5_error_code result;
1310 krb5_creds creds_in, *creds;
1314 if (realm->child_pid)
1315 /* Right idea. Basically, we haven't gotten it yet */
1316 return KRB5KRB_AP_ERR_TKT_EXPIRED;
1318 if (realm->have_tkt) {
1319 /* Get a pointer to the default ccache. We don't need to free this. */
1320 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1322 /* GRRR. There's no allocator or constructor for krb5_creds */
1323 /* GRRR. It would be nice if this API were documented at all */
1324 memset(&creds_in, 0, sizeof(creds_in));
1327 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1328 /* construct the service principal */
1330 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1331 strlen(realm->name), realm->name,
1332 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1335 /* HOLDING: creds_in.server */
1337 /* look up or get the credentials we need */
1339 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1341 krb5_cc_close(Z_krb5_ctx, ccache);
1342 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1344 krb5_free_creds(Z_krb5_ctx, creds);
1348 syslog(LOG_ERR, "tkt_rtrv: don't have ticket, but have no child");
1349 result = KRB5KRB_AP_ERR_TKT_EXPIRED;
1354 syslog(LOG_ERR, "tkt_rtrv: can't fork");
1357 else if (pid == 0) {
1358 #ifdef _POSIX_VERSION
1359 struct sigaction action;
1361 action.sa_flags = 0;
1362 sigemptyset(&action.sa_mask);
1363 action.sa_handler = 0;
1364 sigaction(SIGCHLD, &action, NULL);
1365 sigaction(SIGINT, &action, NULL);
1366 sigaction(SIGTERM, &action, NULL);
1367 sigaction(SIGUSR1, &action, NULL);
1368 sigaction(SIGUSR2, &action, NULL);
1369 sigaction(SIGFPE, &action, NULL);
1370 sigaction(SIGHUP, &action, NULL);
1372 sigaction(SIGEMT, &action, NULL);
1375 signal(SIGCHLD, SIG_DFL);
1376 signal(SIGINT, SIG_DFL);
1377 signal(SIGTERM, SIG_DFL);
1378 signal(SIGUSR1, SIG_DFL);
1379 signal(SIGUSR2, SIG_DFL);
1380 signal(SIGFPE, SIG_DFL);
1381 signal(SIGHUP, SIG_DFL);
1383 signal(SIGEMT, SIG_DFL);
1387 syslog(LOG_INFO, "tkt_rtrv running for %s", realm->name);
1389 /* Get a pointer to the default ccache.
1390 We don't need to free this. */
1391 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1393 /* GRRR. There's no allocator or constructor for krb5_creds */
1394 /* GRRR. It would be nice if this API were documented at all */
1395 memset(&creds_in, 0, sizeof(creds_in));
1398 result = krb5_cc_get_principal(Z_krb5_ctx, ccache,
1400 /* construct the service principal */
1402 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1403 strlen(realm->name), realm->name,
1404 SERVER_KRB5_SERVICE,
1408 /* HOLDING: creds_in.server */
1410 /* look up or get the credentials we need */
1412 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1414 krb5_cc_close(Z_krb5_ctx, ccache);
1415 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1417 krb5_free_creds(Z_krb5_ctx, creds);
1418 syslog(LOG_INFO, "tkt_rtrv succeeded for %s", realm->name);
1422 /* Sleep a little while before retrying */
1426 realm->child_pid = pid;
1427 realm->have_tkt = 0;
1429 syslog(LOG_WARNING, "tkt_rtrv: %s: %d", realm->name,
1434 #endif /* HAVE_KRB5 */