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 __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender));
64 static Code_t realm_sendit_auth __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *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,ZRealm *realm));
70 static Code_t realm_new_server __P((struct sockaddr_in *, ZNotice_t *, ZRealm *));
71 static Code_t realm_set_server __P((struct sockaddr_in *, ZRealm *));
73 static Code_t ticket_retrieve __P((ZRealm *realm));
74 static int ticket_lookup __P((char *realm));
78 realm_get_idx_by_addr(realm, who)
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(realmname)
100 /* First, look for an exact match (case insensitive) */
102 if (!strcasecmp(ZGetRealm(), realmname))
106 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
107 if (!strcasecmp(realm->name, realmname))
110 /* No exact match. See if there's a partial match */
112 if (!strncasecmp(ZGetRealm(), realmname, strlen(realmname)))
116 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
117 if (!strncasecmp(realm->name, realmname, strlen(realmname)))
123 realm_get_realm_by_pid(pid)
129 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
130 if (realm->child_pid == pid)
142 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
143 if (realm->child_pid != 0)
144 kill(realm->child_pid, 9);
150 get_realm_lists(file)
153 ZRealmname *rlm_list, *rlm;
154 int ii, nused, ntotal;
156 char buf[REALM_SZ + MAXHOSTNAMELEN + 1]; /* one for newline */
157 char realm[REALM_SZ], server[MAXHOSTNAMELEN + 1];
160 if (!(fp = fopen(file, "r")))
161 return((ZRealmname *)0);
163 /* start with 16, realloc if necessary */
165 rlm_list = (ZRealmname *)malloc(ntotal * sizeof(ZRealmname));
167 syslog(LOG_CRIT, "get_realm_lists malloc");
171 while (fgets(buf, REALM_SZ + MAXHOSTNAMELEN + 1, fp)) {
172 if (sscanf(buf, "%s %s", realm, server) != 2) {
173 syslog(LOG_CRIT, "bad format in %s", file);
176 for (ii = 0; ii < nused; ii++) {
177 /* look for this realm */
178 if (!strcmp(rlm_list[ii].name, realm))
183 if (rlm->nused +1 >= rlm->nservers) {
184 /* make more space */
185 rlm->servers = (char **)realloc((char *)rlm->servers,
186 (unsigned)rlm->nservers * 2 *
189 syslog(LOG_CRIT, "get_realm_lists realloc");
194 rlm->servers[rlm->nused++] = strsave(server);
197 if (nused + 1 >= ntotal) {
198 /* make more space */
199 rlm_list = (ZRealmname *)realloc((char *)rlm_list,
200 (unsigned)ntotal * 2 *
203 syslog(LOG_CRIT, "get_realm_lists realloc");
208 rlm = &rlm_list[nused++];
209 strcpy(rlm->name, realm);
212 rlm->servers = (char **)malloc(rlm->nservers * sizeof(char *));
214 syslog(LOG_CRIT, "get_realm_lists malloc");
217 rlm->servers[rlm->nused++] = strsave(server);
220 if (nused + 1 >= ntotal) {
221 rlm_list = (ZRealmname *)realloc((char *)rlm_list,
222 (unsigned)(ntotal + 1) *
225 syslog(LOG_CRIT, "get_realm_lists realloc");
229 *rlm_list[nused].name = '\0';
239 for (cnt = 0; cnt < nrealms; cnt++) {
240 if (retval = (subscr_send_realm_subs(&otherrealms[cnt])) != ZERR_NONE)
247 realm_bound_for_realm(realm, recip)
252 int remote = strcmp(ZGetRealm(), realm);
255 rlm = strchr(recip, '@');
260 if (rlm && strcmp(realm_expand_realm(rlm + 1), realm) == 0)
267 realm_sender_in_realm(realm, sender)
272 int remote = strcmp(ZGetRealm(), realm);
275 rlm = strchr(sender, '@');
280 if (rlm && strcmp((rlm + 1), realm) == 0)
286 int sender_in_realm(notice)
291 realm = strchr(notice->z_sender, '@');
293 if (!realm || !strcmp(realm + 1, ZGetRealm()))
300 realm_which_realm(who)
301 struct sockaddr_in *who;
304 struct sockaddr_in *addr;
307 if (who->sin_port != srv_addr.sin_port)
310 /* loop through the realms */
311 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
312 /* loop through the addresses for the realm */
313 for (addr = realm->addrs, b = 0; b < realm->count; b++, addr++)
314 if (addr->sin_addr.s_addr == who->sin_addr.s_addr)
321 realm_get_realm_by_name(name)
327 /* First, look for an exact match (case insensitive) */
328 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
329 if (!strcasecmp(realm->name, name))
332 /* Failing that, look for an inexact match */
333 for (realm = otherrealms, a = 0; a < nrealms; a++, realm++)
334 if (!strncasecmp(realm->name, name, strlen(name)))
341 rlm_nack_cancel(notice, who)
342 register ZNotice_t *notice;
343 struct sockaddr_in *who;
345 register ZRealm *which = realm_which_realm(who);
346 register Unacked *nacked, *next;
350 zdbug((LOG_DEBUG, "rlm_nack_cancel: %s:%08X,%08X",
351 inet_ntoa(notice->z_uid.zuid_addr),
352 notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
355 syslog(LOG_ERR, "non-realm ack?");
359 for (nacked = rlm_nacklist; nacked; nacked = nacked->next) {
360 if (&otherrealms[nacked->dest.rlm.rlm_idx] == which) {
361 /* First, note the realm appears to be up */
362 which->state = REALM_UP;
363 if (ZCompareUID(&nacked->uid, ¬ice->z_uid)) {
364 timer_reset(nacked->timer);
366 if (nacked->ack_addr.sin_addr.s_addr)
367 rlm_ack(notice, nacked);
370 free(nacked->packet);
378 zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X",
379 inet_ntoa (notice->z_uid.zuid_addr),
380 notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec));
386 rlm_ack(notice, nacked)
395 /* tell the original sender the result */
397 acknotice.z_message_len = strlen(acknotice.z_message) + 1;
399 packlen = sizeof(ackpack);
401 if ((retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen))
403 syslog(LOG_ERR, "rlm_ack format: %s",
404 error_message(retval));
407 zdbug((LOG_DEBUG, "rlm_ack sending to %s/%d",
408 inet_ntoa(nacked->ack_addr.sin_addr),
409 ntohs(nacked->ack_addr.sin_port)));
410 if ((retval = ZSetDestAddr(&nacked->ack_addr)) != ZERR_NONE) {
411 syslog(LOG_WARNING, "rlm_ack set addr: %s",
412 error_message(retval));
415 if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) {
416 syslog(LOG_WARNING, "rlm_ack xmit: %s", error_message(retval));
422 realm_dispatch(notice, auth, who, server)
425 struct sockaddr_in *who;
429 struct sockaddr_in newwho;
430 Code_t status = ZERR_NONE;
431 char rlm_recipient[REALM_SZ + 1];
433 String *notice_class;
435 if (notice->z_kind == SERVACK || notice->z_kind == SERVNAK) {
436 rlm_nack_cancel(notice, who);
439 /* set up a who for the real origin */
440 memset((caddr_t) &newwho, 0, sizeof(newwho));
441 newwho.sin_family = AF_INET;
442 newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr;
443 newwho.sin_port = hm_port;
445 /* check if it's a control message */
446 realm = realm_which_realm(who);
448 notice_class = make_string(notice->z_class,1);
450 if (class_is_admin(notice_class)) {
451 syslog(LOG_WARNING, "%s sending admin opcode %s",
452 realm->name, notice->z_opcode);
453 } else if (class_is_hm(notice_class)) {
454 syslog(LOG_WARNING, "%s sending hm opcode %s",
455 realm->name, notice->z_opcode);
456 } else if (class_is_control(notice_class)) {
457 status = realm_control_dispatch(notice, auth, who,
459 } else if (class_is_ulogin(notice_class)) {
460 /* don't need to forward this */
461 if (server == me_server) {
462 sprintf(rlm_recipient, "@%s", realm->name);
463 notice->z_recipient = rlm_recipient;
465 sendit(notice, 1, who, 0);
467 } else if (class_is_ulocate(notice_class)) {
468 status = realm_ulocate_dispatch(notice, auth, who, server, realm);
470 /* redo the recipient */
471 if (*notice->z_recipient == '\0') {
472 sprintf(rlm_recipient, "@%s", realm->name);
473 notice->z_recipient = rlm_recipient;
475 } else if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient)
476 && *notice->z_recipient == '@')
478 /* we're responsible for getting this message out */
480 notice->z_recipient = "";
483 /* otherwise, send to local subscribers */
484 sendit(notice, auth, who, external);
494 ZRealmname *rlmnames;
497 struct in_addr *addresses;
500 char rlmprinc[ANAME_SZ+INST_SZ+REALM_SZ+3];
502 sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, REALM_LIST_FILE);
503 rlmnames = get_realm_lists(list_file);
505 zdbug((LOG_DEBUG, "No other realms"));
510 for (nrealms = 0; *rlmnames[nrealms].name; nrealms++);
512 otherrealms = (ZRealm *)malloc(nrealms * sizeof(ZRealm));
514 syslog(LOG_CRIT, "malloc failed in realm_init");
518 for (ii = 0; ii < nrealms; ii++) {
519 rlm = &otherrealms[ii];
520 strcpy(rlm->name, rlmnames[ii].name);
522 addresses = (struct in_addr *)malloc(rlmnames[ii].nused *
523 sizeof(struct in_addr));
525 syslog(LOG_CRIT, "malloc failed in realm_init");
528 /* convert names to addresses */
530 for (jj = 0; jj < rlmnames[ii].nused; jj++) {
531 hp = gethostbyname(rlmnames[ii].servers[jj]);
533 memmove((caddr_t) &addresses[found], (caddr_t)hp->h_addr,
534 sizeof(struct in_addr));
537 syslog(LOG_WARNING, "hostname failed, %s",
538 rlmnames[ii].servers[jj]);
539 /* free the hostname */
540 free(rlmnames[ii].servers[jj]);
543 rlm->addrs = (struct sockaddr_in *)malloc(found *
544 sizeof (struct sockaddr_in));
546 syslog(LOG_CRIT, "malloc failed in realm_init");
549 for (jj = 0; jj < rlm->count; jj++) {
550 rlm->addrs[jj].sin_family = AF_INET;
551 /* use the server port */
552 rlm->addrs[jj].sin_port = srv_addr.sin_port;
553 rlm->addrs[jj].sin_addr = addresses[jj];
555 client = (Client *) malloc(sizeof(Client));
557 syslog(LOG_CRIT, "malloc failed in realm_init");
560 memset(&client->addr, 0, sizeof(struct sockaddr_in));
562 client->session_keyblock = NULL;
565 memset(&client->session_key, 0, sizeof(client->session_key));
568 sprintf(rlmprinc, "%s.%s@%s", SERVER_SERVICE, SERVER_INSTANCE,
570 client->principal = make_string(rlmprinc, 0);
571 client->last_send = 0;
572 client->last_ack = NOW;
575 client->addr.sin_family = 0;
576 client->addr.sin_port = 0;
577 client->addr.sin_addr.s_addr = 0;
579 rlm->client = client;
580 rlm->idx = (rlm->count) ? random() % rlm->count : 0;
584 /* Assume the best */
585 rlm->state = REALM_TARDY;
587 free(rlmnames[ii].servers);
594 realm_deathgram(server)
598 char rlm_recipient[REALM_SZ + 1];
601 /* Get it out once, and assume foreign servers will share */
602 for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
605 char rlm_recipient[REALM_SZ + 1];
608 memset (&snotice, 0, sizeof (snotice));
610 snotice.z_kind = ACKED;
611 snotice.z_port = srv_addr.sin_port;
612 snotice.z_class = ZEPHYR_CTL_CLASS;
613 snotice.z_class_inst = ZEPHYR_CTL_REALM;
614 snotice.z_opcode = SERVER_SHUTDOWN;
615 snotice.z_sender = myname; /* my host name */
616 sprintf(rlm_recipient, "@%s", realm->name);
617 snotice.z_recipient = rlm_recipient;
618 snotice.z_default_format = "";
619 snotice.z_num_other_fields = 0;
620 snotice.z_default_format = "";
621 snotice.z_message = (server) ? server->addr_str : NULL;
622 snotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0;
624 zdbug((LOG_DEBUG, "rlm_deathgram: suggesting %s to %s",
625 (server) ? server->addr_str : "nothing", realm->name));
628 if (!ticket_lookup(realm->name))
629 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
630 syslog(LOG_WARNING, "rlm_deathgram failed: %s",
631 error_message(retval));
636 if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZCAUTH))
639 syslog(LOG_WARNING, "rlm_deathgram format: %s",
640 error_message(retval));
643 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
644 syslog(LOG_WARNING, "rlm_deathgram parse: %s",
645 error_message(retval));
650 realm_handoff(&snotice, 1, NULL, realm, 0);
660 char rlm_recipient[REALM_SZ + 1];
662 for (jj = 1; jj < nservers; jj++) { /* skip limbo server */
663 if (jj != me_server_idx && otherservers[jj].state == SERV_UP)
667 if (nservers < 2 || !found) {
668 /* if we're the only server up, send a REALM_BOOT to one of their
670 for (realm = otherrealms, jj = 0; jj < nrealms; jj++, realm++) {
673 char rlm_recipient[REALM_SZ + 1];
676 memset (&snotice, 0, sizeof (snotice));
678 snotice.z_opcode = REALM_BOOT;
679 snotice.z_port = srv_addr.sin_port;
680 snotice.z_class_inst = ZEPHYR_CTL_REALM;
681 snotice.z_class = ZEPHYR_CTL_CLASS;
682 snotice.z_recipient = "";
683 snotice.z_kind = ACKED;
684 snotice.z_num_other_fields = 0;
685 snotice.z_default_format = "";
686 snotice.z_sender = myname; /* my host name */
687 sprintf(rlm_recipient, "@%s", realm->name);
688 snotice.z_recipient = rlm_recipient;
689 snotice.z_default_format = "";
690 snotice.z_message = NULL;
691 snotice.z_message_len = 0;
694 if (!ticket_lookup(realm->name))
695 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
696 syslog(LOG_WARNING, "rlm_wakeup failed: %s",
697 error_message(retval));
702 if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH))
705 syslog(LOG_WARNING, "rlm_wakeup format: %s",
706 error_message(retval));
709 if ((retval = ZParseNotice(pack, packlen, &snotice))
711 syslog(LOG_WARNING, "rlm_wakeup parse: %s",
712 error_message(retval));
717 realm_handoff(&snotice, 1, NULL, realm, 0);
724 realm_ulocate_dispatch(notice, auth, who, server, realm)
727 struct sockaddr_in *who;
731 register char *opcode = notice->z_opcode;
735 syslog(LOG_WARNING, "unauth locate msg from %s (%s/%s/%s)",
736 inet_ntoa(who->sin_addr),
737 notice->z_class, notice->z_class_inst,
738 notice->z_opcode); /* XXX */
740 syslog(LOG_WARNING, "unauth locate msg from %s",
741 inet_ntoa(who->sin_addr));
743 clt_ack(notice, who, AUTH_FAILED);
747 if (!strcmp(opcode, REALM_REQ_LOCATE)) {
749 ulogin_realm_locate(notice, who, realm);
750 } else if (!strcmp(opcode, REALM_ANS_LOCATE)) {
752 ulogin_relay_locate(notice, who);
754 syslog(LOG_WARNING, "%s unknown/illegal loc opcode %s",
755 realm->name, opcode);
764 realm_control_dispatch(notice, auth, who, server, realm)
767 struct sockaddr_in *who;
771 register char *opcode = notice->z_opcode;
775 syslog(LOG_WARNING, "unauth ctl msg from %s (%s/%s/%s)",
776 inet_ntoa(who->sin_addr),
777 notice->z_class, notice->z_class_inst,
778 notice->z_opcode); /* XXX */
780 syslog(LOG_WARNING, "unauth ctl msg from %s",
781 inet_ntoa(who->sin_addr));
783 if (server == me_server)
784 clt_ack(notice, who, AUTH_FAILED);
788 if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM)) {
789 syslog(LOG_WARNING, "Invalid rlm_dispatch instance %s",
790 notice->z_class_inst);
794 if (!strcmp(opcode, REALM_REQ_SUBSCRIBE) || !strcmp(opcode, REALM_ADD_SUBSCRIBE)) {
795 /* try to add subscriptions */
796 /* attempts to get defaults are ignored */
797 if ((status = subscr_foreign_user(notice, who, server, realm)) != ZERR_NONE) {
798 clt_ack(notice, who, AUTH_FAILED);
799 } else if (server == me_server) {
800 server_forward(notice, auth, who);
803 } else if (!strcmp(opcode, REALM_UNSUBSCRIBE)) {
804 /* try to remove subscriptions */
805 if ((status = subscr_realm_cancel(who, notice, realm)) != ZERR_NONE) {
806 clt_ack(notice, who, NOT_FOUND);
807 } else if (server == me_server) {
808 server_forward(notice, auth, who);
811 } else if (!strcmp(opcode, REALM_BOOT)) {
812 zdbug((LOG_DEBUG, "got a REALM_BOOT from %d (me %d)", server, me_server));
813 realm->state = REALM_STARTING;
814 realm_set_server(who, realm);
816 /* resend subscriptions but only if this was to us */
817 if (server == me_server) {
818 if ((status = subscr_realm_subs(realm)) != ZERR_NONE) {
819 clt_ack(notice, who, NOT_FOUND);
821 /* do forward the hint in case it ever matters */
822 server_forward(notice, auth, who);
827 } else if (!strcmp(opcode, SERVER_SHUTDOWN)) {
828 /* try to remove subscriptions */
829 if ((status = realm_new_server(who, notice, realm)) != ZERR_NONE) {
830 clt_ack(notice, who, NOT_FOUND);
831 } else if (server == me_server) {
832 server_forward(notice, auth, who);
836 syslog(LOG_WARNING, "%s unknown/illegal ctl opcode %s",
837 realm->name, opcode);
838 if (server == me_server)
846 realm_new_server(sin, notice, realm)
847 struct sockaddr_in *sin;
852 char suggested_server[MAXHOSTNAMELEN];
855 struct sockaddr_in sinaddr;
861 srvidx = realm_get_idx_by_addr(realm, sin);
862 zdbug((LOG_DEBUG, "rlm_new_srv: message from %d in %s (%s)",
863 srvidx, realm->name, inet_ntoa(sin->sin_addr)));
864 if (realm->idx == srvidx) {
865 if (notice->z_message_len) {
866 addr = inet_addr(notice->z_message);
867 sinaddr.sin_addr.s_addr = addr;
868 rlm = realm_which_realm(&sinaddr);
870 if (!rlm || (rlm != realm))
872 realm->idx = realm_get_idx_by_addr(realm, &sinaddr);
874 realm->idx = (realm->idx + 1) % realm->count;
876 zdbug((LOG_DEBUG, "rlm_new_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
878 zdbug((LOG_DEBUG, "rlm_new_srv: not switching servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
883 realm_set_server(sin, realm)
884 struct sockaddr_in *sin;
889 rlm = realm_which_realm(sin);
891 if (!rlm || (rlm != realm))
893 realm->idx = realm_get_idx_by_addr(realm, sin);
894 zdbug((LOG_DEBUG, "rlm_pick_srv: switched servers (%s)", inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
898 realm_handoff(notice, auth, who, realm, ack_to_sender)
901 struct sockaddr_in *who;
909 zdbug((LOG_DEBUG, "realm_sendit unauthentic to realm %s",
911 realm_sendit(notice, who, auth, realm, ack_to_sender);
915 if (!ticket_lookup(realm->name))
916 if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
917 syslog(LOG_WARNING, "rlm_handoff failed: %s",
918 error_message(retval));
919 realm_sendit(notice, who, auth, realm, ack_to_sender);
923 zdbug((LOG_DEBUG, "realm_sendit to realm %s auth %d", realm->name, auth));
924 /* valid ticket available now, send the message */
925 retval = realm_sendit_auth(notice, who, auth, realm, ack_to_sender);
926 #else /* HAVE_KRB4 */
927 realm_sendit(notice, who, auth, realm, ack_to_sender);
928 #endif /* HAVE_KRB4 */
932 realm_sendit(notice, who, auth, realm, ack_to_sender)
934 struct sockaddr_in *who;
944 notice->z_auth = auth;
946 /* format the notice */
947 if ((retval = ZFormatRawNotice(notice, &pack, &packlen)) != ZERR_NONE) {
948 syslog(LOG_WARNING, "rlm_sendit format: %s",
949 error_message(retval));
954 if ((retval = ZSetDestAddr(&realm->addrs[realm->idx])) != ZERR_NONE) {
955 syslog(LOG_WARNING, "rlm_sendit set addr: %s",
956 error_message(retval));
960 if ((retval = ZSendPacket(pack, packlen, 0)) != ZERR_NONE) {
961 syslog(LOG_WARNING, "rlm_sendit xmit: %s", error_message(retval));
966 /* now we've sent it, mark it as not ack'ed */
968 if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
969 /* no space: just punt */
970 syslog(LOG_ERR, "rlm_sendit nack malloc");
975 nacked->client = NULL;
977 nacked->packet = pack;
978 nacked->dest.rlm.rlm_idx = realm - otherrealms;
979 nacked->dest.rlm.rlm_srv_idx = realm->idx;
980 nacked->packsz = packlen;
981 nacked->uid = notice->z_uid;
983 nacked->ack_addr = *who;
985 nacked->ack_addr.sin_addr.s_addr = 0;
987 /* set a timer to retransmit */
988 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
990 LIST_INSERT(&rlm_nacklist, nacked);
995 packet_ctl_nack(nackpacket)
1000 /* extract the notice */
1001 ZParseNotice(nackpacket->packet, nackpacket->packsz, ¬ice);
1002 if (nackpacket->ack_addr.sin_addr.s_addr != 0)
1003 nack(¬ice, &nackpacket->ack_addr);
1006 syslog(LOG_WARNING, "would have acked nobody (%s/%s/%s)",
1007 notice.z_class, notice.z_class_inst, notice.z_opcode); /* XXX */
1015 Unacked *nackpacket = (Unacked *) arg;
1017 register ZRealm *realm;
1020 zdbug((LOG_DEBUG,"rlm_rexmit"));
1022 realm = &otherrealms[nackpacket->dest.rlm.rlm_idx];
1024 zdbug((LOG_DEBUG, "rlm_rexmit: sending to %s:%d (%d)",
1025 realm->name, realm->idx, nackpacket->rexmits));
1027 if (realm->count == 0)
1030 /* Check to see if we've retransmitted as many times as we can */
1031 if (nackpacket->rexmits >= (NUM_REXMIT_TIMES * realm->count)) {
1032 /* give a server ack that the packet is lost/realm dead */
1033 packet_ctl_nack(nackpacket);
1034 LIST_DELETE(nackpacket);
1036 zdbug((LOG_DEBUG, "rlm_rexmit: %s appears dead", realm->name));
1037 realm->state = REALM_DEAD;
1039 free(nackpacket->packet);
1044 /* if we've reached our limit, move on to the next server */
1045 if ((realm->state == REALM_TARDY) ||
1046 (nackpacket->rexmits &&
1047 !((nackpacket->rexmits+1) % (NUM_REXMIT_TIMES/3))))
1049 realm->idx = (realm->idx + 1) % realm->count;
1050 zdbug((LOG_DEBUG, "rlm_rexmit: %s switching servers:%d (%s)",
1051 realm->name, realm->idx,
1052 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1055 /* throttle back if it looks like the realm is down */
1056 if ((realm->state != REALM_DEAD) ||
1057 ((nackpacket->rexmits % (realm->count+1)) == 1)) {
1058 /* do the retransmit */
1059 retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1060 if (retval != ZERR_NONE) {
1061 syslog(LOG_WARNING, "rlm_rexmit set addr: %s",
1062 error_message(retval));
1064 retval = ZSendPacket(nackpacket->packet, nackpacket->packsz, 0);
1065 if (retval != ZERR_NONE)
1066 syslog(LOG_WARNING, "rlm_rexmit xmit: %s",
1067 error_message(retval));
1069 /* no per-server nack queues for foreign realms yet, doesn't matter */
1070 nackpacket->dest.rlm.rlm_srv_idx = realm->idx;
1071 zdbug((LOG_DEBUG, "rlm_rexmit(%s): send to %s", realm->name,
1072 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1074 zdbug((LOG_DEBUG, "rlm_rexmit(%s): not sending to %s", realm->name,
1075 inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1078 /* reset the timer */
1079 nackpacket->rexmits++;
1081 timer_set_rel(rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES],
1082 rlm_rexmit, nackpacket);
1083 if (rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES] == -1)
1084 zdbug((LOG_DEBUG, "rlm_rexmit(%s): would send at -1 to %s",
1085 realm->name, inet_ntoa((realm->addrs[realm->idx]).sin_addr)));
1091 realm_dump_realms(fp)
1094 register int ii, jj;
1096 for (ii = 0; ii < nrealms; ii++) {
1097 (void) fprintf(fp, "%d:%s\n", ii, otherrealms[ii].name);
1098 for (jj = 0; jj < otherrealms[ii].count; jj++) {
1099 (void) fprintf(fp, "\t%s\n",
1100 inet_ntoa(otherrealms[ii].addrs[jj].sin_addr));
1103 subscr_dump_subs(fp, otherrealms[ii].subs);
1109 realm_sendit_auth(notice, who, auth, realm, ack_to_sender)
1112 struct sockaddr_in *who;
1118 int buffer_len, hdrlen, offset, fragsize, ret_len, message_len;
1119 int origoffset, origlen;
1122 char buf[1024], multi[64];
1123 ZNotice_t partnotice, newnotice;
1127 buffer = (char *) malloc(sizeof(ZPacket_t));
1129 syslog(LOG_ERR, "realm_sendit_auth malloc");
1130 return ENOMEM; /* DON'T put on nack list */
1133 buffer_len = sizeof(ZPacket_t);
1135 newnotice = *notice;
1138 retval = ZMakeZcodeRealmAuthentication(&newnotice, buffer, buffer_len,
1139 &hdrlen, realm->name);
1140 if (retval != ZERR_NONE) {
1141 syslog(LOG_WARNING, "rlm_sendit_auth make zcksum: %s",
1142 error_message(retval));
1146 /* set the dest addr */
1147 retval = ZSetDestAddr(&realm->addrs[realm->idx]);
1148 if (retval != ZERR_NONE) {
1149 syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s",
1150 error_message(retval));
1154 /* This is not terribly pretty, but it does do its job.
1155 * If a packet we get that needs to get sent off to another realm is
1156 * too big after we slap on our authent, we refragment it further,
1157 * a la Z_SendFragmentedNotice. This obviates the need for what
1158 * used to be done in ZFormatAuthenticRealmNotice, as we do it here.
1159 * At some point it should be pulled back out into its own function,
1160 * but only the server uses it.
1163 if ((notice->z_message_len+hdrlen > buffer_len) ||
1164 (notice->z_message_len+hdrlen > Z_MAXPKTLEN)) {
1166 /* Reallocate buffers inside the refragmenter */
1169 partnotice = *notice;
1172 origlen = notice->z_message_len;
1174 if (notice->z_multinotice && strcmp(notice->z_multinotice, ""))
1175 if (sscanf(notice->z_multinotice, "%d/%d", &origoffset,
1177 syslog(LOG_WARNING, "rlm_sendit_auth frag: parse failed");
1178 return ZERR_BADFIELD;
1182 zdbug((LOG_DEBUG,"rlm_send_auth: orig: %d-%d/%d", origoffset,
1183 notice->z_message_len, origlen));
1186 fragsize = Z_MAXPKTLEN-hdrlen-Z_FRAGFUDGE;
1188 while (offset < notice->z_message_len || !notice->z_message_len) {
1189 (void) sprintf(multi, "%d/%d", offset+origoffset, origlen);
1190 partnotice.z_multinotice = multi;
1192 (void) Z_gettimeofday(&partnotice.z_uid.tv,
1193 (struct timezone *)0);
1194 partnotice.z_uid.tv.tv_sec = htonl((u_long)
1195 partnotice.z_uid.tv.tv_sec);
1196 partnotice.z_uid.tv.tv_usec =
1197 htonl((u_long) partnotice.z_uid.tv.tv_usec);
1198 (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
1201 message_len = min(notice->z_message_len-offset, fragsize);
1202 partnotice.z_message = notice->z_message+offset;
1203 partnotice.z_message_len = message_len;
1206 zdbug((LOG_DEBUG,"rlm_send_auth: new: %d-%d/%d",
1207 origoffset+offset, message_len, origlen));
1210 buffer = (char *) malloc(sizeof(ZPacket_t));
1212 syslog(LOG_ERR, "realm_sendit_auth malloc");
1213 return ENOMEM; /* DON'T put on nack list */
1216 buffer_len = sizeof(ZPacket_t);
1218 retval = ZMakeZcodeRealmAuthentication(&partnotice, buffer,
1219 buffer_len, &hdrlen,
1221 if (retval != ZERR_NONE) {
1222 syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s",
1223 error_message(retval));
1228 ptr = buffer+hdrlen;
1230 (void) memcpy(ptr, partnotice.z_message, partnotice.z_message_len);
1232 buffer_len = hdrlen+partnotice.z_message_len;
1235 if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
1236 syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
1237 error_message(retval));
1242 if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
1243 /* no space: just punt */
1244 syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
1249 nacked->rexmits = 0;
1250 nacked->packet = buffer;
1251 nacked->dest.rlm.rlm_idx = realm - otherrealms;
1252 nacked->dest.rlm.rlm_srv_idx = realm->idx;
1253 nacked->packsz = buffer_len;
1254 nacked->uid = partnotice.z_uid;
1256 /* Do the ack for the last frag, below */
1258 nacked->ack_addr = *who;
1260 nacked->ack_addr.sin_addr.s_addr = 0;
1262 /* set a timer to retransmit */
1263 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
1266 LIST_INSERT(&rlm_nacklist, nacked);
1270 if (!notice->z_message_len)
1275 /* This is easy, no further fragmentation needed */
1276 ptr = buffer+hdrlen;
1278 (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len);
1280 buffer_len = hdrlen+newnotice.z_message_len;
1283 if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
1284 syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
1285 error_message(retval));
1290 /* now we've sent it, mark it as not ack'ed */
1292 if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
1293 /* no space: just punt */
1294 syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
1299 nacked->rexmits = 0;
1300 nacked->packet = buffer;
1301 nacked->dest.rlm.rlm_idx = realm - otherrealms;
1302 nacked->dest.rlm.rlm_srv_idx = realm->idx;
1303 nacked->packsz = buffer_len;
1304 nacked->uid = notice->z_uid;
1306 /* Do the ack for the last frag, below */
1308 nacked->ack_addr = *who;
1310 nacked->ack_addr.sin_addr.s_addr = 0;
1312 /* set a timer to retransmit */
1313 nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked);
1315 LIST_INSERT(&rlm_nacklist, nacked);
1321 ticket_lookup(realm)
1324 krb5_error_code result;
1327 krb5_creds creds_in, *creds;
1329 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1333 memset(&creds_in, 0, sizeof(creds_in));
1335 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1337 krb5_cc_close(Z_krb5_ctx, ccache);
1341 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1344 SERVER_KRB5_SERVICE, SERVER_INSTANCE, 0);
1346 krb5_cc_close(Z_krb5_ctx, ccache);
1350 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1352 krb5_cc_close(Z_krb5_ctx, ccache);
1355 krb5_timeofday (Z_krb5_ctx, &sec);
1356 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1357 if ((result == 0) && (sec < creds->times.endtime)) {
1358 krb5_free_creds(Z_krb5_ctx, creds);
1361 if (!result) krb5_free_creds(Z_krb5_ctx, creds);
1367 ticket_retrieve(realm)
1372 krb5_error_code result;
1373 krb5_auth_context authctx;
1374 krb5_creds creds_in, *creds;
1378 if (realm->child_pid)
1379 /* Right idea. Basically, we haven't gotten it yet */
1380 return KRB5KRB_AP_ERR_TKT_EXPIRED;
1382 if (realm->have_tkt) {
1383 /* Get a pointer to the default ccache. We don't need to free this. */
1384 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1386 /* GRRR. There's no allocator or constructor for krb5_creds */
1387 /* GRRR. It would be nice if this API were documented at all */
1388 memset(&creds_in, 0, sizeof(creds_in));
1391 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1392 /* construct the service principal */
1394 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1395 strlen(realm->name), realm->name,
1396 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1399 /* HOLDING: creds_in.server */
1401 /* look up or get the credentials we need */
1403 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1405 krb5_cc_close(Z_krb5_ctx, ccache);
1406 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1408 krb5_free_creds(Z_krb5_ctx, creds);
1412 syslog(LOG_ERR, "tkt_rtrv: don't have ticket, but have no child");
1413 result = KRB5KRB_AP_ERR_TKT_EXPIRED;
1418 syslog(LOG_ERR, "tkt_rtrv: can't fork");
1419 return KRBET_KDC_AUTH_EXP;
1421 else if (pid == 0) {
1422 #ifdef _POSIX_VERSION
1423 struct sigaction action;
1425 action.sa_flags = 0;
1426 sigemptyset(&action.sa_mask);
1427 action.sa_handler = 0;
1428 sigaction(SIGCHLD, &action, NULL);
1429 sigaction(SIGINT, &action, NULL);
1430 sigaction(SIGTERM, &action, NULL);
1431 sigaction(SIGUSR1, &action, NULL);
1432 sigaction(SIGUSR2, &action, NULL);
1433 sigaction(SIGFPE, &action, NULL);
1434 sigaction(SIGHUP, &action, NULL);
1436 sigaction(SIGEMT, &action, NULL);
1439 signal(SIGCHLD, SIG_DFL);
1440 signal(SIGINT, SIG_DFL);
1441 signal(SIGTERM, SIG_DFL);
1442 signal(SIGUSR1, SIG_DFL);
1443 signal(SIGUSR2, SIG_DFL);
1444 signal(SIGFPE, SIG_DFL);
1445 signal(SIGHUP, SIG_DFL);
1447 signal(SIGEMT, SIG_DFL);
1451 syslog(LOG_INFO, "tkt_rtrv running for %s", realm->name);
1453 /* Get a pointer to the default ccache. We don't need to free this. */
1454 result = krb5_cc_default(Z_krb5_ctx, &ccache);
1456 /* GRRR. There's no allocator or constructor for krb5_creds */
1457 /* GRRR. It would be nice if this API were documented at all */
1458 memset(&creds_in, 0, sizeof(creds_in));
1461 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
1462 /* construct the service principal */
1464 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
1465 strlen(realm->name), realm->name,
1466 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1469 /* HOLDING: creds_in.server */
1471 /* look up or get the credentials we need */
1473 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
1475 krb5_cc_close(Z_krb5_ctx, ccache);
1476 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
1478 krb5_free_creds(Z_krb5_ctx, creds);
1479 syslog(LOG_INFO, "tkt_rtrv succeeded for %s", realm->name);
1483 /* Sleep a little while before retrying */
1487 realm->child_pid = pid;
1488 realm->have_tkt = 0;
1490 syslog(LOG_WARNING, "tkt_rtrv: %s: %d", realm->name,
1495 #endif /* HAVE_KRB5 */