1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains source for the ZInitialize function.
4 * Created by: Robert French
6 * $Id: ZInit.c 2276 2008-12-29 08:27:51Z kcr $
8 * Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology.
9 * For copying and distribution information, see the file
14 static const char rcsid_ZInitialize_c[] =
15 "$Zephyr: /afs/athena.mit.edu/astaff/project/zephyr/src/lib/RCS/ZInitialize.c,v 1.17 89/05/30 18:11:25 jtkohl Exp $";
20 #include <sys/socket.h>
27 #ifdef HAVE_KRB5_ERR_H
32 #define INADDR_NONE 0xffffffff
35 #if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM)
38 int z_get_host_realm_replacement(char *, char ***);
44 struct servent *hmserv;
45 struct hostent *hostent;
46 char addr[4], hostname[MAXHOSTNAMELEN];
47 struct in_addr servaddr;
48 struct sockaddr_in sin;
49 unsigned int s, sinsize = sizeof(sin);
53 char **krealms = NULL;
58 char d1[ANAME_SZ], d2[INST_SZ];
63 initialize_krb_error_table();
66 initialize_krb5_error_table();
69 initialize_zeph_error_table();
71 (void) memset((char *)&__HM_addr, 0, sizeof(__HM_addr));
73 __HM_addr.sin_family = AF_INET;
75 /* Set up local loopback address for HostManager */
81 hmserv = (struct servent *)getservbyname(HM_SVCNAME, "udp");
82 __HM_addr.sin_port = (hmserv) ? hmserv->s_port : HM_SVC_FALLBACK;
84 (void) memcpy((char *)&__HM_addr.sin_addr, addr, 4);
88 /* Initialize the input queue */
93 if ((code = krb5_init_context(&Z_krb5_ctx)))
97 /* if the application is a server, there might not be a zhm. The
98 code will fall back to something which might not be "right",
99 but this is is ok, since none of the servers call krb_rd_req. */
101 servaddr.s_addr = INADDR_NONE;
102 if (! __Zephyr_server) {
103 if ((code = ZOpenPort(NULL)) != ZERR_NONE)
106 if ((code = ZhmStat(NULL, ¬ice)) != ZERR_NONE)
111 /* the first field, which is NUL-terminated, is the server name.
112 If this code ever support a multiplexing zhm, this will have to
113 be made smarter, and probably per-message */
116 #ifndef KRB5_REFERRAL_REALM
117 code = krb5_get_host_realm(Z_krb5_ctx, notice.z_message, &krealms);
121 code = z_get_host_realm_replacement(notice.z_message, &krealms);
125 krealm = krb_realmofhost(notice.z_message);
128 hostent = gethostbyname(notice.z_message);
129 if (hostent && hostent->h_addrtype == AF_INET)
130 memcpy(&servaddr, hostent->h_addr, sizeof(servaddr));
132 ZFreeNotice(¬ice);
137 strcpy(__Zephyr_realm, krealms[0]);
138 krb5_free_host_realm(Z_krb5_ctx, krealms);
140 char *p; /* XXX define this somewhere portable */
141 /* XXX check ticket file here */
142 code = krb5_get_default_realm(Z_krb5_ctx, &p);
143 strcpy(__Zephyr_realm, p);
144 #ifdef HAVE_KRB5_FREE_DEFAULT_REALM
145 krb5_free_default_realm(Z_krb5_ctx, p);
155 strcpy(__Zephyr_realm, krealm);
156 } else if ((krb_get_tf_fullname(TKT_FILE, d1, d2, __Zephyr_realm)
158 ((krbval = krb_get_lrealm(__Zephyr_realm, 1)) != KSUCCESS)) {
162 strcpy(__Zephyr_realm, "local-realm");
166 __My_addr.s_addr = INADDR_NONE;
167 if (servaddr.s_addr != INADDR_NONE) {
168 /* Try to get the local interface address by connecting a UDP
169 * socket to the server address and getting the local address.
170 * Some broken operating systems (e.g. Solaris 2.0-2.5) yield
171 * INADDR_ANY (zero), so we have to check for that. */
172 s = socket(AF_INET, SOCK_DGRAM, 0);
174 memset(&sin, 0, sizeof(sin));
175 sin.sin_family = AF_INET;
176 memcpy(&sin.sin_addr, &servaddr, sizeof(servaddr));
177 sin.sin_port = HM_SRV_SVC_FALLBACK;
178 if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == 0
179 && getsockname(s, (struct sockaddr *) &sin, &sinsize) == 0
180 && sin.sin_addr.s_addr != 0)
181 memcpy(&__My_addr, &sin.sin_addr, sizeof(__My_addr));
185 if (__My_addr.s_addr == INADDR_NONE) {
186 /* We couldn't figure out the local interface address by the
187 * above method. Try by resolving the local hostname. (This
188 * is a pretty broken thing to do, and unfortunately what we
189 * always do on server machines.) */
190 if (gethostname(hostname, sizeof(hostname)) == 0) {
191 hostent = gethostbyname(hostname);
192 if (hostent && hostent->h_addrtype == AF_INET)
193 memcpy(&__My_addr, hostent->h_addr, sizeof(__My_addr));
196 /* If the above methods failed, zero out __My_addr so things will
197 * sort of kind of work. */
198 if (__My_addr.s_addr == INADDR_NONE)
199 __My_addr.s_addr = 0;
201 /* Get the sender so we can cache it */
207 const char * ZGetRealm (void) {
208 return __Zephyr_realm;
215 int ZQLength (void) {
216 return __Q_CompleteLength;
219 struct sockaddr_in ZGetDestAddr (void) {
223 #if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM)
225 #include <netinet/in.h>
226 #include <arpa/nameser.h>
229 static int txt_lookup(char *qname, char **result) {
230 int ret, buflen, left;
234 char dname[MAXDNAME];
235 int queries, answers, stored;
243 buflen = buflen ? buflen * 2 : 2048;
244 buf = (buf == NULL) ? malloc(buflen) : realloc(buf, buflen);
246 ret = res_search(qname, C_IN, T_TXT, buf, buflen);
247 } while (ret > buflen);
257 queries = ntohs(hdr->qdcount);
258 answers = ntohs(hdr->ancount);
259 p += sizeof (HEADER);
260 left -= sizeof (HEADER);
263 ret = dn_expand(buf, buf + buflen, p, dname, sizeof dname);
264 if (ret < 0 || (ret + 4) > left)
270 if (!ret || !answers)
277 ret = dn_expand(buf, buf + buflen, p, dname, sizeof dname);
278 if (ret < 0 || ret > left)
285 type = ntohs(*(u_int16_t *)p);
287 class = ntohs(*(u_int16_t *)p);
289 ret = ntohs(*(u_int16_t *)p);
296 if (class == C_IN && type == T_TXT) {
297 *result = malloc(ret);
300 memcpy(*result, p + 1, ret - 1);
301 (*result)[ret - 1] = 0;
310 int z_get_host_realm_replacement(char *inhost, char ***krealms) {
313 char *default_realm = NULL;
319 host = strdup(inhost);
321 for (p = host; *p; p++)
326 while (p && !default_realm) {
329 if (default_realm == NULL) {
340 krb5_get_profile(Z_krb5_ctx, &prof);
342 ret = profile_get_string(prof, "domain_realm", p,
343 0, NULL, &tmp_realm);
345 profile_abandon(prof);
350 if (tmp_realm != NULL)
359 if (tmp_realm != NULL) {
360 realm = strdup(tmp_realm);
361 profile_release_string(tmp_realm);
367 profile_abandon(prof);
372 qname = malloc(strlen(p) + strlen("_kerberos..") + 1);
377 sprintf(qname, "_kerberos.%s.", p);
378 ret = txt_lookup(qname, &realm);
384 } while (ret && p && p[0]);
388 if (default_realm != NULL) {
389 realm = strdup(default_realm);
395 for (p = realm; *p; p++)
399 ret = krb5_get_default_realm(Z_krb5_ctx, &realm);
409 if ((*krealms = calloc(2, sizeof(*krealms))) == NULL) {
415 (*krealms)[0] = realm;
416 (*krealms)[1] = NULL;