]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/ZInit.c
new upstream version
[1ts-debian.git] / zephyr / lib / ZInit.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains source for the ZInitialize function.
3  *
4  *      Created by:     Robert French
5  *
6  *      $Id: ZInit.c 2276 2008-12-29 08:27:51Z kcr $
7  *
8  *      Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology.
9  *      For copying and distribution information, see the file
10  *      "mit-copyright.h". 
11  */
12
13 #ifndef lint
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 $";
16 #endif
17
18 #include <internal.h>
19
20 #include <sys/socket.h>
21 #ifdef HAVE_KRB4
22 #include <krb_err.h>
23 #endif
24 #ifdef HAVE_KRB5
25 #include <krb5.h>
26 #endif
27 #ifdef HAVE_KRB5_ERR_H
28 #include <krb5_err.h>
29 #endif
30
31 #ifndef INADDR_NONE
32 #define INADDR_NONE 0xffffffff
33 #endif
34
35 #if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM)
36 #include <profile.h>
37
38 int z_get_host_realm_replacement(char *, char ***);
39 #endif
40
41 Code_t
42 ZInitialize(void)
43 {
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);
50     Code_t code;
51     ZNotice_t notice;
52 #ifdef HAVE_KRB5
53     char **krealms = NULL;
54 #else
55 #ifdef HAVE_KRB4
56     char *krealm = NULL;
57     int krbval;
58     char d1[ANAME_SZ], d2[INST_SZ];
59 #endif
60 #endif
61
62 #ifdef HAVE_KRB4
63     initialize_krb_error_table();
64 #endif
65 #ifdef HAVE_KRB5
66     initialize_krb5_error_table();
67 #endif
68
69     initialize_zeph_error_table();
70     
71     (void) memset((char *)&__HM_addr, 0, sizeof(__HM_addr));
72
73     __HM_addr.sin_family = AF_INET;
74
75     /* Set up local loopback address for HostManager */
76     addr[0] = 127;
77     addr[1] = 0;
78     addr[2] = 0;
79     addr[3] = 1;
80
81     hmserv = (struct servent *)getservbyname(HM_SVCNAME, "udp");
82     __HM_addr.sin_port = (hmserv) ? hmserv->s_port : HM_SVC_FALLBACK;
83
84     (void) memcpy((char *)&__HM_addr.sin_addr, addr, 4);
85
86     __HM_set = 0;
87
88     /* Initialize the input queue */
89     __Q_Tail = NULL;
90     __Q_Head = NULL;
91     
92 #ifdef HAVE_KRB5
93     if ((code = krb5_init_context(&Z_krb5_ctx)))
94         return(code);
95 #endif
96
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. */
100
101     servaddr.s_addr = INADDR_NONE;
102     if (! __Zephyr_server) {
103        if ((code = ZOpenPort(NULL)) != ZERR_NONE)
104           return(code);
105
106        if ((code = ZhmStat(NULL, &notice)) != ZERR_NONE)
107           return(code);
108
109        ZClosePort();
110
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 */
114
115 #ifdef HAVE_KRB5
116 #ifndef KRB5_REFERRAL_REALM
117        code = krb5_get_host_realm(Z_krb5_ctx, notice.z_message, &krealms);
118        if (code)
119          return(code);
120 #else
121        code = z_get_host_realm_replacement(notice.z_message, &krealms);
122 #endif
123 #else
124 #ifdef HAVE_KRB4
125        krealm = krb_realmofhost(notice.z_message);
126 #endif
127 #endif
128        hostent = gethostbyname(notice.z_message);
129        if (hostent && hostent->h_addrtype == AF_INET)
130            memcpy(&servaddr, hostent->h_addr, sizeof(servaddr));
131
132        ZFreeNotice(&notice);
133     }
134
135 #ifdef HAVE_KRB5
136     if (krealms) {
137       strcpy(__Zephyr_realm, krealms[0]);
138       krb5_free_host_realm(Z_krb5_ctx, krealms);
139     } else {
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);
146 #else
147       free(p);
148 #endif
149       if (code)
150         return code;
151     }
152 #else
153 #ifdef HAVE_KRB4
154     if (krealm) {
155         strcpy(__Zephyr_realm, krealm);
156     } else if ((krb_get_tf_fullname(TKT_FILE, d1, d2, __Zephyr_realm)
157                 != KSUCCESS) &&
158                ((krbval = krb_get_lrealm(__Zephyr_realm, 1)) != KSUCCESS)) {
159         return (krbval);
160     }
161 #else
162     strcpy(__Zephyr_realm, "local-realm");
163 #endif
164 #endif
165
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);
173         if (s != -1) {
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));
182             close(s);
183         }
184     }
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));
194         }
195     }
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;
200
201     /* Get the sender so we can cache it */
202     (void) ZGetSender();
203
204     return (ZERR_NONE);
205 }
206
207 const char * ZGetRealm (void) {
208     return __Zephyr_realm;
209 }
210
211 int ZGetFD (void) {
212     return __Zephyr_fd;
213 }
214
215 int ZQLength (void) {
216     return __Q_CompleteLength;
217 }
218
219 struct sockaddr_in ZGetDestAddr (void) {
220     return __HM_addr;
221 }
222
223 #if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM)
224 #include <ctype.h>
225 #include <netinet/in.h>
226 #include <arpa/nameser.h>
227 #include <resolv.h>
228
229 static int txt_lookup(char *qname, char **result) {
230     int ret, buflen, left;
231     void *buf = NULL;
232     HEADER *hdr;
233     unsigned char *p;
234     char dname[MAXDNAME];
235     int queries, answers, stored;
236
237     ret = res_init();
238     if (ret < 0)
239         return -1;
240
241     buflen = 0;
242     do {
243         buflen = buflen ? buflen * 2 : 2048;
244         buf = (buf == NULL) ? malloc(buflen) : realloc(buf, buflen);
245         
246         ret = res_search(qname, C_IN, T_TXT, buf, buflen);
247     } while (ret > buflen);
248
249     if (ret < 0)
250         return -1;
251
252     buflen = ret;
253     left = ret;
254
255     hdr = (HEADER *)buf;
256     p = buf;
257     queries = ntohs(hdr->qdcount);
258     answers = ntohs(hdr->ancount);
259     p += sizeof (HEADER);
260     left -= sizeof (HEADER);
261
262     while (queries--) {
263         ret = dn_expand(buf, buf + buflen, p, dname, sizeof dname);
264         if (ret < 0 || (ret + 4) > left)
265             return -1;
266         p += ret + 4;
267         left -= ret + 4;
268     }
269
270     if (!ret || !answers)
271         return -1;
272
273     stored = 0;
274     while (answers--) {
275         int class, type;
276         
277         ret = dn_expand(buf, buf + buflen, p, dname, sizeof dname);
278         if (ret < 0 || ret > left)
279             return -1;
280         p += ret;
281         left -= ret;
282
283         if (left < 10)
284             return -1;
285         type = ntohs(*(u_int16_t *)p);
286         p += 2;
287         class = ntohs(*(u_int16_t *)p);
288         p += 6;
289         ret = ntohs(*(u_int16_t *)p);
290         p += 2;
291         left -= 10;
292
293         if (ret > left)
294             return -1;
295
296         if (class == C_IN && type == T_TXT) {
297             *result = malloc(ret);
298             if (*result == NULL)
299                 return -1;
300             memcpy(*result, p + 1, ret - 1);
301             (*result)[ret - 1] = 0;
302             return 0;
303         }
304
305         p += ret;
306     }
307     return -1;
308 }       
309
310 int z_get_host_realm_replacement(char *inhost, char ***krealms) {
311     char *host, *p;
312     char *realm = NULL;
313     char *default_realm = NULL;
314     char *tmp_realm;
315     char *qname;
316     profile_t prof;
317     int ret;
318     
319     host = strdup(inhost);
320
321     for (p = host; *p; p++)
322         if (isupper(*p))
323             *p = tolower(*p);
324
325     p = host;
326     while (p && !default_realm) {
327         if (*p == '.') {
328             p++;
329             if (default_realm == NULL) {
330                 default_realm = p;
331             }
332         } else {
333             p = strchr(p, '.');
334         }
335     }
336
337     p = host;
338     tmp_realm = NULL;
339
340     krb5_get_profile(Z_krb5_ctx, &prof);
341     while(p) {
342         ret = profile_get_string(prof, "domain_realm", p,
343                                  0, NULL, &tmp_realm);
344         if (ret) {
345             profile_abandon(prof);
346             free(host);
347             return ret;
348         }
349
350         if (tmp_realm != NULL)
351             break;
352
353         if (*p == '.')
354             p++;
355         else
356             p = strchr(p, '.');
357     }
358
359     if (tmp_realm != NULL) {
360         realm = strdup(tmp_realm);
361         profile_release_string(tmp_realm);
362         if (realm == NULL) {
363             free(host);
364             return errno;
365         }
366     }
367     profile_abandon(prof);
368
369     if (realm == NULL) {
370         p = host;
371         do {
372             qname = malloc(strlen(p) + strlen("_kerberos..") + 1);
373             if (qname == NULL) {
374                 free(host);
375                 return errno;
376             }
377             sprintf(qname, "_kerberos.%s.", p);
378             ret = txt_lookup(qname, &realm);
379             free(qname);
380             
381             p = strchr(p,'.');
382             if (p) 
383                 p++;
384         } while (ret && p && p[0]);
385     }
386
387     if (realm == NULL) {
388         if (default_realm != NULL) {
389             realm = strdup(default_realm);
390             if (realm == NULL) {
391                 free(host);
392                 return errno;
393             }
394             
395             for (p = realm; *p; p++)
396                 if (islower(*p))
397                     *p = toupper(*p);
398         } else {
399             ret = krb5_get_default_realm(Z_krb5_ctx, &realm);
400             if (ret) {
401                 free(host);
402                 return ret;
403             }
404         }
405     }
406     
407     free(host);
408
409     if ((*krealms = calloc(2, sizeof(*krealms))) == NULL) {
410         if (realm)
411             free(realm);
412         return errno;
413     }
414
415     (*krealms)[0] = realm;
416     (*krealms)[1] = NULL;
417
418     return 0;
419 }
420 #endif