remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / kx / common.c
1 /*
2  * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "kx.h"
35
36 RCSID("$Id: common.c,v 1.68 2003/04/16 16:45:39 joda Exp $");
37
38 char x_socket[MaxPathLen];
39
40 u_int32_t display_num;
41 char display[MaxPathLen];
42 int display_size = sizeof(display);
43 char xauthfile[MaxPathLen];
44 int xauthfile_size = sizeof(xauthfile);
45 u_char cookie[16];
46 size_t cookie_len = sizeof(cookie);
47
48 #ifndef X_UNIX_PATH
49 #define X_UNIX_PATH "/tmp/.X11-unix/X"
50 #endif
51
52 #ifndef X_PIPE_PATH
53 #define X_PIPE_PATH "/tmp/.X11-pipe/X"
54 #endif
55
56 /*
57  * Allocate a unix domain socket in `s' for display `dpy' and with
58  * filename `pattern'
59  *
60  * 0 if all is OK
61  * -1 if bind failed badly
62  * 1 if dpy is already used */
63
64 static int
65 try_socket (struct x_socket *s, int dpy, const char *pattern)
66 {
67     struct sockaddr_un addr;
68     int fd;
69
70     fd = socket (AF_UNIX, SOCK_STREAM, 0);
71     if (fd < 0)
72         err (1, "socket AF_UNIX");
73     memset (&addr, 0, sizeof(addr));
74     addr.sun_family = AF_UNIX;
75     snprintf (addr.sun_path, sizeof(addr.sun_path), pattern, dpy);
76     if(bind(fd,
77             (struct sockaddr *)&addr,
78             sizeof(addr)) < 0) {
79         close (fd);
80         if (errno == EADDRINUSE ||
81             errno == EACCES  /* Cray return EACCESS */
82 #ifdef ENOTUNIQ
83             || errno == ENOTUNIQ /* bug in Solaris 2.4 */
84 #endif
85             )
86             return 1;
87         else
88             return -1;
89     }
90     s->fd = fd;
91     s->pathname = strdup (addr.sun_path);
92     if (s->pathname == NULL)
93         errx (1, "strdup: out of memory");
94     s->flags = UNIX_SOCKET;
95     return 0;
96 }
97
98 #ifdef MAY_HAVE_X11_PIPES
99 /*
100  * Allocate a stream (masqueraded as a named pipe)
101  *
102  * 0 if all is OK
103  * -1 if bind failed badly
104  * 1 if dpy is already used
105  */
106
107 static int
108 try_pipe (struct x_socket *s, int dpy, const char *pattern)
109 {
110     char path[MAXPATHLEN];
111     int ret;
112     int fd;
113     int pipefd[2];
114     
115     snprintf (path, sizeof(path), pattern, dpy);
116     fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600);
117     if (fd < 0) {
118         if (errno == EEXIST)
119             return 1;
120         else
121             return -1;
122     }
123
124     close (fd);
125
126     ret = pipe (pipefd);
127     if (ret < 0)
128         err (1, "pipe");
129
130     ret = ioctl (pipefd[1], I_PUSH, "connld");
131     if (ret < 0) {
132         if(errno == ENOSYS)
133             return -1;
134         err (1, "ioctl I_PUSH");
135     }
136
137     ret = fattach (pipefd[1], path);
138     if (ret < 0)
139         err (1, "fattach %s", path);
140
141     s->fd  = pipefd[0];
142     close (pipefd[1]);
143     s->pathname = strdup (path);
144     if (s->pathname == NULL)
145         errx (1, "strdup: out of memory");
146     s->flags = STREAM_PIPE;
147     return 0;
148 }
149 #endif /* MAY_HAVE_X11_PIPES */
150
151 /*
152  * Try to create a TCP socket in `s' corresponding to display `dpy'.
153  *
154  * 0 if all is OK
155  * -1 if bind failed badly
156  * 1 if dpy is already used
157  */
158
159 static int
160 try_tcp (struct x_socket *s, int dpy)
161 {
162     struct sockaddr_in tcpaddr;
163     struct in_addr local;
164     int one = 1;
165     int fd;
166
167     memset(&local, 0, sizeof(local));
168     local.s_addr = htonl(INADDR_LOOPBACK);
169
170     fd = socket (AF_INET, SOCK_STREAM, 0);
171     if (fd < 0)
172         err (1, "socket AF_INET");
173 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
174     setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&one,
175                 sizeof(one));
176 #endif
177     memset (&tcpaddr, 0, sizeof(tcpaddr));
178     tcpaddr.sin_family = AF_INET;
179     tcpaddr.sin_addr = local;
180     tcpaddr.sin_port = htons(6000 + dpy);
181     if (bind (fd, (struct sockaddr *)&tcpaddr,
182               sizeof(tcpaddr)) < 0) {
183         close (fd);
184         if (errno == EADDRINUSE)
185             return 1;
186         else
187             return -1;
188     }
189     s->fd = fd;
190     s->pathname = NULL;
191     s->flags = TCP;
192     return 0;
193 }
194
195 /*
196  * The potential places to create unix sockets.
197  */
198
199 static char *x_sockets[] = {
200 X_UNIX_PATH "%u",
201 "/var/X/.X11-unix/X" "%u",
202 "/usr/spool/sockets/X11/" "%u",
203 NULL
204 };
205
206 /*
207  * Dito for stream pipes.
208  */
209
210 #ifdef MAY_HAVE_X11_PIPES
211 static char *x_pipes[] = {
212 X_PIPE_PATH "%u",
213 "/var/X/.X11-pipe/X" "%u",
214 NULL
215 };
216 #endif
217
218 /*
219  * Create the directory corresponding to dirname of `path' or fail.
220  */
221
222 static void
223 try_mkdir (const char *path)
224 {
225     char *dir;
226     char *p;
227     int oldmask;
228
229     if((dir = strdup (path)) == NULL)
230         errx (1, "strdup: out of memory");
231     p = strrchr (dir, '/');
232     if (p)
233         *p = '\0';
234
235     oldmask = umask(0);
236     mkdir (dir, 01777);
237     umask (oldmask);
238     free (dir);
239 }
240
241 /*
242  * Allocate a display, returning the number of sockets in `number' and
243  * all the corresponding sockets in `sockets'.  If `tcp_socket' is
244  * true, also allcoaet a TCP socket.
245  *
246  * The return value is the display allocated or -1 if an error occurred.
247  */
248
249 int
250 get_xsockets (int *number, struct x_socket **sockets, int tcp_socket)
251 {
252      int dpy;
253      struct x_socket *s;
254      int n;
255      int i;
256
257      s = malloc (sizeof(*s) * 5);
258      if (s == NULL)
259          errx (1, "malloc: out of memory");
260
261      try_mkdir (X_UNIX_PATH);
262      try_mkdir (X_PIPE_PATH);
263
264      for(dpy = 4; dpy < 256; ++dpy) {
265          char **path;
266          int tmp = 0;
267
268          n = 0;
269          for (path = x_sockets; *path; ++path) {
270              tmp = try_socket (&s[n], dpy, *path);
271              if (tmp == -1) {
272                  if (errno != ENOTDIR && errno != ENOENT)
273                      return -1;
274              } else if (tmp == 1) {
275                  while(--n >= 0) {
276                      close (s[n].fd);
277                      free (s[n].pathname);
278                  }
279                  break;
280              } else if (tmp == 0)
281                  ++n;
282          }
283          if (tmp == 1)
284              continue;
285
286 #ifdef MAY_HAVE_X11_PIPES
287          for (path = x_pipes; *path; ++path) {
288              tmp = try_pipe (&s[n], dpy, *path);
289              if (tmp == -1) {
290                  if (errno != ENOTDIR && errno != ENOENT && errno != ENOSYS)
291                      return -1;
292              } else if (tmp == 1) {
293                  while (--n >= 0) {
294                      close (s[n].fd);
295                      free (s[n].pathname);
296                  }
297                  break;
298              } else if (tmp == 0)
299                  ++n;
300          }
301
302          if (tmp == 1)
303              continue;
304 #endif
305
306          if (tcp_socket) {
307              tmp = try_tcp (&s[n], dpy);
308              if (tmp == -1)
309                  return -1;
310              else if (tmp == 1) {
311                  while (--n >= 0) {
312                      close (s[n].fd);
313                      free (s[n].pathname);
314                  }
315                  break;
316              } else if (tmp == 0)
317                  ++n;
318          }
319          break;
320      }
321      if (dpy == 256)
322          errx (1, "no free x-servers");
323      for (i = 0; i < n; ++i)
324          if (s[i].flags & LISTENP
325              && listen (s[i].fd, SOMAXCONN) < 0)
326              err (1, "listen %s", s[i].pathname ? s[i].pathname : "tcp");
327      *number = n;
328      *sockets = s;
329      return dpy;
330 }
331
332 /*
333  * Change owner on the `n' sockets in `sockets' to `uid', `gid'.
334  * Return 0 is succesful or -1 if an error occurred.
335  */
336
337 int
338 chown_xsockets (int n, struct x_socket *sockets, uid_t uid, gid_t gid)
339 {
340     int i;
341
342     for (i = 0; i < n; ++i)
343         if (sockets[i].pathname != NULL)
344             if (chown (sockets[i].pathname, uid, gid) < 0)
345                 return -1;
346     return 0;
347 }
348
349 /*
350  * Connect to local display `dnr' with local transport or TCP.
351  * Return a file descriptor.
352  */
353
354 int
355 connect_local_xsocket (unsigned dnr)
356 {
357      int fd;
358      char **path;
359
360      for (path = x_sockets; *path; ++path) {
361          struct sockaddr_un addr;
362
363          fd = socket (AF_UNIX, SOCK_STREAM, 0);
364          if (fd < 0)
365              break;
366          memset (&addr, 0, sizeof(addr));
367          addr.sun_family = AF_UNIX;
368          snprintf (addr.sun_path, sizeof(addr.sun_path), *path, dnr);
369          if (connect (fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
370              return fd;
371          close(fd);
372      }
373      {
374          struct sockaddr_in addr;
375
376          fd = socket(AF_INET, SOCK_STREAM, 0);
377          if (fd < 0)
378              err (1, "socket AF_INET");
379          memset (&addr, 0, sizeof(addr));
380          addr.sin_family = AF_INET;
381          addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
382          addr.sin_port = htons(6000 + dnr);
383          if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
384              return fd;
385          close(fd);
386      }
387      err (1, "connecting to local display %u", dnr);
388 }
389
390 /*
391  * Create a cookie file with a random cookie for the localhost.  The
392  * file name will be stored in `xauthfile' (but not larger than
393  * `xauthfile_size'), and the cookie returned in `cookie', `cookie_sz'.
394  * Return 0 if succesful, or errno.
395  */
396
397 int
398 create_and_write_cookie (char *xauthfile,
399                          size_t xauthfile_size,
400                          u_char *cookie,
401                          size_t cookie_sz)
402 {
403      Xauth auth;
404      char tmp[64];
405      int fd;
406      FILE *f;
407      char hostname[MaxHostNameLen];
408      int saved_errno;
409
410      gethostname (hostname, sizeof(hostname));
411      
412      auth.family = FamilyLocal;
413      auth.address = hostname;
414      auth.address_length = strlen(auth.address);
415      snprintf (tmp, sizeof(tmp), "%d", display_num);
416      auth.number_length = strlen(tmp);
417      auth.number = tmp;
418      auth.name = COOKIE_TYPE;
419      auth.name_length = strlen(auth.name);
420      auth.data_length = cookie_sz;
421      auth.data = (char*)cookie;
422 #ifdef KRB5
423      krb5_generate_random_block (cookie, cookie_sz);
424 #else
425      krb_generate_random_block (cookie, cookie_sz);
426 #endif
427
428      strlcpy(xauthfile, "/tmp/AXXXXXX", xauthfile_size);
429      fd = mkstemp(xauthfile);
430      if(fd < 0) {
431          saved_errno = errno;
432          syslog(LOG_ERR, "create_and_write_cookie: mkstemp: %m");
433          return saved_errno;
434      }
435      f = fdopen(fd, "r+");
436      if(f == NULL){
437          saved_errno = errno;
438          close(fd);
439          return errno;
440      }
441      if(XauWriteAuth(f, &auth) == 0) {
442          saved_errno = errno;
443          fclose(f);
444          return saved_errno;
445      }
446
447      /*
448       * I would like to write a cookie for localhost:n here, but some
449       * stupid code in libX11 will not look for cookies of that type,
450       * so we are forced to use FamilyWild instead.
451       */
452
453      auth.family  = FamilyWild;
454      auth.address_length = 0;
455
456      if (XauWriteAuth(f, &auth) == 0) {
457          saved_errno = errno;
458          fclose (f);
459          return saved_errno;
460      }
461
462      if(fclose(f))
463          return errno;
464      return 0;
465 }
466
467 /*
468  * Verify and remove cookies.  Read and parse a X-connection from
469  * `fd'. Check the cookie used is the same as in `cookie'.  Remove the
470  * cookie and copy the rest of it to `sock'.
471  * Expect cookies iff cookiesp.
472  * Return 0 iff ok.
473  *
474  * The protocol is as follows:
475  *
476  * C->S:        [Bl]                            1
477  *              unused                          1
478  *              protocol major version          2
479  *              protocol minor version          2
480  *              length of auth protocol name(n) 2
481  *              length of auth protocol data    2
482  *              unused                          2
483  *              authorization protocol name     n
484  *              pad                             pad(n)
485  *              authorization protocol data     d
486  *              pad                             pad(d)
487  *
488  * S->C:        Failed
489  *              0                               1
490  *              length of reason                1
491  *              protocol major version          2
492  *              protocol minor version          2
493  *              length in 4 bytes unit of
494  *              additional data (n+p)/4         2
495  *              reason                          n
496  *              unused                          p = pad(n)
497  */
498
499 int
500 verify_and_remove_cookies (int fd, int sock, int cookiesp)
501 {
502      u_char beg[12];
503      int bigendianp;
504      unsigned n, d, npad, dpad;
505      char *protocol_name, *protocol_data;
506      u_char zeros[6] = {0, 0, 0, 0, 0, 0};
507      u_char refused[20] = {0, 10, 
508                            0, 0, /* protocol major version  */
509                            0, 0, /* protocol minor version */
510                            0, 0, /* length of additional data / 4 */
511                            'b', 'a', 'd', ' ', 'c', 'o', 'o', 'k', 'i', 'e',
512                            0, 0};
513
514      if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
515           return 1;
516      if (net_write (sock, beg, 6) != 6)
517           return 1;
518      bigendianp = beg[0] == 'B';
519      if (bigendianp) {
520           n = (beg[6] << 8) | beg[7];
521           d = (beg[8] << 8) | beg[9];
522      } else {
523           n = (beg[7] << 8) | beg[6];
524           d = (beg[9] << 8) | beg[8];
525      }
526      npad = (4 - (n % 4)) % 4;
527      dpad = (4 - (d % 4)) % 4;
528      protocol_name = malloc(n + npad);
529      if (n + npad != 0 && protocol_name == NULL)
530          return 1;
531      protocol_data = malloc(d + dpad);
532      if (d + dpad != 0 && protocol_data == NULL) {
533          free (protocol_name);
534          return 1;
535      }
536      if (net_read (fd, protocol_name, n + npad) != n + npad)
537          goto fail;
538      if (net_read (fd, protocol_data, d + dpad) != d + dpad)
539          goto fail;
540      if (cookiesp) {
541          if (strncmp (protocol_name, COOKIE_TYPE, strlen(COOKIE_TYPE)) != 0)
542              goto refused;
543          if (d != cookie_len ||
544              memcmp (protocol_data, cookie, cookie_len) != 0)
545              goto refused;
546      }
547      free (protocol_name);
548      free (protocol_data);
549      if (net_write (sock, zeros, 6) != 6)
550           return 1;
551      return 0;
552 refused:
553      refused[2] = beg[2];
554      refused[3] = beg[3];
555      refused[4] = beg[4];
556      refused[5] = beg[5];
557      if (bigendianp)
558          refused[7] = 3;
559      else
560          refused[6] = 3;
561
562      net_write (fd, refused, sizeof(refused));
563 fail:
564      free (protocol_name);
565      free (protocol_data);
566      return 1;
567 }
568
569 /* 
570  * Return 0 iff `cookie' is compatible with the cookie for the
571  * localhost with name given in `ai' (or `hostname') and display
572  * number in `disp_nr'.
573  */
574
575 static int
576 match_local_auth (Xauth* auth,
577                   struct addrinfo *ai, const char *hostname, int disp_nr)
578 {
579     int auth_disp;
580     char *tmp_disp;
581     struct addrinfo *a;
582     
583     tmp_disp = malloc(auth->number_length + 1);
584     if (tmp_disp == NULL)
585         return -1;
586     memcpy(tmp_disp, auth->number, auth->number_length);
587     tmp_disp[auth->number_length] = '\0';
588     auth_disp = atoi(tmp_disp);
589     free (tmp_disp);
590     if (auth_disp != disp_nr)
591         return 1;
592     for (a = ai; a != NULL; a = a->ai_next) {
593         if ((auth->family == FamilyLocal
594              || auth->family == FamilyWild)
595             && a->ai_canonname != NULL
596             && strncmp (auth->address,
597                         a->ai_canonname,
598                         auth->address_length) == 0)
599             return 0;
600     }
601     if (hostname != NULL
602         && (auth->family    == FamilyLocal
603             || auth->family == FamilyWild)
604         && strncmp (auth->address, hostname, auth->address_length) == 0)
605         return 0;
606     return 1;
607 }
608
609 /*
610  * Find `our' cookie from the cookie file `f' and return it or NULL.
611  */
612
613 static Xauth*
614 find_auth_cookie (FILE *f)
615 {
616     Xauth *ret = NULL;
617     char local_hostname[MaxHostNameLen];
618     char *display = getenv("DISPLAY");
619     char d[MaxHostNameLen + 4];
620     char *colon;
621     struct addrinfo *ai;
622     struct addrinfo hints;
623     int disp;
624     int error;
625
626     if(display == NULL)
627         display = ":0";
628     strlcpy(d, display, sizeof(d));
629     display = d;
630     colon = strchr (display, ':');
631     if (colon == NULL)
632         disp = 0;
633     else {
634         *colon = '\0';
635         disp = atoi (colon + 1);
636     }
637     if (strcmp (display, "") == 0
638         || strncmp (display, "unix", 4) == 0
639         || strncmp (display, "localhost", 9) == 0) {
640         gethostname (local_hostname, sizeof(local_hostname));
641         display = local_hostname;
642     }
643     memset (&hints, 0, sizeof(hints));
644     hints.ai_flags    = AI_CANONNAME;
645     hints.ai_socktype = SOCK_STREAM;
646     hints.ai_protocol = IPPROTO_TCP;
647
648     error = getaddrinfo (display, NULL, &hints, &ai);
649     if (error)
650         ai = NULL;
651
652     for (; (ret = XauReadAuth (f)) != NULL; XauDisposeAuth(ret)) {
653         if (match_local_auth (ret, ai, display, disp) == 0) {
654             if (ai != NULL)
655                 freeaddrinfo (ai);
656             return ret;
657         }
658     }
659     if (ai != NULL)
660         freeaddrinfo (ai);
661     return NULL;
662 }
663
664 /*
665  * Get rid of the cookie that we were sent and get the correct one
666  * from our own cookie file instead.
667  */
668
669 int
670 replace_cookie(int xserver, int fd, char *filename, int cookiesp) /* XXX */
671 {
672      u_char beg[12];
673      int bigendianp;
674      unsigned n, d, npad, dpad;
675      FILE *f;
676      u_char zeros[6] = {0, 0, 0, 0, 0, 0};
677
678      if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
679           return 1;
680      if (net_write (xserver, beg, 6) != 6)
681           return 1;
682      bigendianp = beg[0] == 'B';
683      if (bigendianp) {
684           n = (beg[6] << 8) | beg[7];
685           d = (beg[8] << 8) | beg[9];
686      } else {
687           n = (beg[7] << 8) | beg[6];
688           d = (beg[9] << 8) | beg[8];
689      }
690      if (n != 0 || d != 0)
691           return 1;
692      f = fopen(filename, "r");
693      if (f != NULL) {
694          Xauth *auth = find_auth_cookie (f);
695          u_char len[6] = {0, 0, 0, 0, 0, 0};
696          
697          fclose (f);
698
699          if (auth != NULL) {
700              n = auth->name_length;
701              d = auth->data_length;
702          } else {
703              n = 0;
704              d = 0;
705          }
706          if (bigendianp) {
707              len[0] = n >> 8;
708              len[1] = n & 0xFF;
709              len[2] = d >> 8;
710              len[3] = d & 0xFF;
711          } else {
712              len[0] = n & 0xFF;
713              len[1] = n >> 8;
714              len[2] = d & 0xFF;
715              len[3] = d >> 8;
716          }
717          if (net_write (xserver, len, 6) != 6) {
718              XauDisposeAuth(auth);
719              return 1;
720          }
721          if(n != 0 && net_write (xserver, auth->name, n) != n) {
722              XauDisposeAuth(auth);
723              return 1;
724          }
725          npad = (4 - (n % 4)) % 4;
726          if (npad && net_write (xserver, zeros, npad) != npad) {
727              XauDisposeAuth(auth);
728              return 1;
729          }
730          if (d != 0 && net_write (xserver, auth->data, d) != d) {
731              XauDisposeAuth(auth);
732              return 1;
733          }
734          XauDisposeAuth(auth);
735          dpad = (4 - (d % 4)) % 4;
736          if (dpad && net_write (xserver, zeros, dpad) != dpad)
737              return 1;
738      } else {
739          if(net_write(xserver, zeros, 6) != 6)
740              return 1;
741      }
742      return 0;
743 }
744
745 /*
746  * Some simple controls on the address and corresponding socket
747  */
748
749 int
750 suspicious_address (int sock, struct sockaddr *addr)
751 {
752     char data[40];
753     socklen_t len = sizeof(data);
754
755     switch (addr->sa_family) {
756     case AF_INET:
757         return ((struct sockaddr_in *)addr)->sin_addr.s_addr != 
758             htonl(INADDR_LOOPBACK)
759 #if defined(IP_OPTIONS) && defined(HAVE_GETSOCKOPT)
760             || getsockopt (sock, IPPROTO_IP, IP_OPTIONS, data, &len) < 0
761             || len != 0
762 #endif
763             ;
764         break;
765 #ifdef HAVE_IPV6
766     case AF_INET6:
767         /* XXX check route headers */
768         return !IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6*)addr)->sin6_addr);
769 #endif
770     default:
771         return 1;
772     }
773 }
774
775 /*
776  * This really sucks, but these functions are used and if we're not
777  * linking against libkrb they don't exist.  Using the heimdal storage
778  * functions will not work either cause we do not always link with
779  * libkrb5 either.
780  */
781
782 #ifndef KRB4
783
784 int
785 krb_get_int(void *f, u_int32_t *to, int size, int lsb)
786 {
787     int i;
788     unsigned char *from = (unsigned char *)f;
789
790     *to = 0;
791     if(lsb){
792         for(i = size-1; i >= 0; i--)
793             *to = (*to << 8) | from[i];
794     }else{
795         for(i = 0; i < size; i++)
796             *to = (*to << 8) | from[i];
797     }
798     return size;
799 }
800
801 int
802 krb_put_int(u_int32_t from, void *to, size_t rem, int size)
803 {
804     int i;
805     unsigned char *p = (unsigned char *)to;
806
807     if (rem < size)
808         return -1;
809
810     for(i = size - 1; i >= 0; i--){
811         p[i] = from & 0xff;
812         from >>= 8;
813     }
814     return size;
815 }
816
817 #endif /* !KRB4 */