1 /*
2 * linc-protocols.c: This file is part of the linc library.
3 *
4 * Authors:
5 * Elliot Lee (sopwith@redhat.com)
6 * Michael Meeks (michael@ximian.com)
7 * Mark McLouglin (mark@skynet.ie) & others
8 *
9 * Copyright 2001, Red Hat, Inc., Ximian, Inc.,
10 * Sun Microsystems, Inc.
11 */
12 #include <config.h>
13 #include "linc-compat.h"
14 #include <linc/linc-protocol.h>
15 #include <linc/linc-connection.h>
16
17 #include "linc-private.h"
18
19 #include <glib/gstdio.h>
20
21 #ifdef HAVE_SYS_SOCKIO_H
22 #include <sys/sockio.h>
23 #endif
24
25 #ifndef G_OS_WIN32
26 #include <net/if.h>
27 #include <sys/ioctl.h>
28 #endif
29
30 #undef LOCAL_DEBUG
31
32 static char *link_tmpdir = NULL;
33 #ifdef G_OS_WIN32
34 static LinkNetIdType use_local_host = LINK_NET_ID_IS_IPADDR;
35 #else
36 static LinkNetIdType use_local_host = LINK_NET_ID_IS_FQDN;
37 #endif
38 static const char *fixed_host_net_id = NULL;
39
40 /*
41 * make_local_tmpdir:
42 * @dirname: directory name.
43 *
44 * Create a directory with the name in @dirname. Also, clear the
45 * access and modification times of @dirname.
46 *
47 * If the directory already exists and is not owned by the current
48 * user, or is not solely readable by the current user, then linc
49 * will error out.
50 */
51 static void
make_local_tmpdir(const char * dirname)52 make_local_tmpdir (const char *dirname)
53 {
54 struct stat statbuf;
55
56 if (g_mkdir (dirname, 0700) != 0) {
57 int e = errno;
58
59 switch (e) {
60 case 0:
61 case EEXIST:
62 if (g_stat (dirname, &statbuf) != 0)
63 g_error ("Can not stat %s\n", dirname);
64
65 #if !defined (__CYGWIN__) && !defined(_WIN32)
66 if (getuid() != 0 && statbuf.st_uid != getuid ())
67 g_error ("Owner of %s is not the current user\n", dirname);
68
69 if ((statbuf.st_mode & (S_IRWXG|S_IRWXO)) ||
70 !S_ISDIR (statbuf.st_mode))
71 g_error ("Wrong permissions for %s\n", dirname);
72 #endif
73
74 break;
75
76 default:
77 g_error("Unknown error on directory creation of %s (%s)\n",
78 dirname, g_strerror (e));
79 }
80 }
81
82 #if (defined (HAVE_UTIME_H) || defined (HAVE_SYS_UTIME_H)) && !defined (G_OS_WIN32)
83 { /* Hide some information ( apparently ) */
84 struct utimbuf utb;
85 memset (&utb, 0, sizeof (utb));
86 utime (dirname, &utb);
87 }
88 #endif
89 }
90
91 /**
92 * link_set_tmpdir:
93 * @dir: directory name.
94 *
95 * Set the temporary directory used by linc to @dir.
96 *
97 * This directory is used for the creation of UNIX sockets.
98 * @dir must have the correct permissions, 0700, user owned
99 * otherwise this method will g_error.
100 **/
101 void
link_set_tmpdir(const char * dir)102 link_set_tmpdir (const char *dir)
103 {
104 g_free (link_tmpdir);
105 link_tmpdir = g_strdup (dir);
106
107 make_local_tmpdir (link_tmpdir);
108 }
109
110 /**
111 * link_get_tmpdir:
112 * @void:
113 *
114 * Fetches the directory name used by linc to whack
115 * Unix Domain sockets into.
116 *
117 * Return value: the g_allocated socket name.
118 **/
119 char *
link_get_tmpdir(void)120 link_get_tmpdir (void)
121 {
122 return g_strdup (link_tmpdir ? link_tmpdir : "");
123 }
124
125 #ifdef HAVE_SOCKADDR_SA_LEN
126 #define LINK_SET_SOCKADDR_LEN(saddr, len) \
127 ((struct sockaddr *)(saddr))->sa_len = (len)
128 #else
129 #define LINK_SET_SOCKADDR_LEN(saddr, len)
130 #endif
131
132 #if defined(HAVE_RESOLV_H) && defined(AF_INET6) && defined(RES_USE_INET6)
133 #define LINK_RESOLV_SET_IPV6 _res.options |= RES_USE_INET6
134 #define LINK_RESOLV_UNSET_IPV6 _res.options &= ~RES_USE_INET6
135 #else
136 #define LINK_RESOLV_SET_IPV6
137 #define LINK_RESOLV_UNSET_IPV6
138 #endif
139
140 #if defined(AF_INET) || defined(AF_INET6) || defined (AF_UNIX)
141
142 #ifndef G_OS_WIN32
143 static void
get_first_non_local_ipaddr(char * buf,size_t len)144 get_first_non_local_ipaddr(char *buf,
145 size_t len)
146 {
147 int sock;
148 const char *retv;
149 struct if_nameindex *ifname_idx_array;
150 struct if_nameindex *ifname_idx;
151 struct sockaddr_in sin;
152 struct ifreq ifr;
153
154 *buf = '\0';
155
156 sock = socket(AF_INET, SOCK_DGRAM, 0);
157 if (-1 == sock)
158 return;
159
160 ifname_idx_array = if_nameindex();
161 for (ifname_idx = ifname_idx_array; ifname_idx && ifname_idx->if_name && ifname_idx->if_name[0]; ifname_idx++) {
162 strncpy(ifr.ifr_name, ifname_idx->if_name, IFNAMSIZ);
163 if (ioctl(sock, SIOCGIFADDR, &ifr))
164 continue;
165
166 memcpy(&sin, &(ifr.ifr_addr), sizeof(struct sockaddr_in));
167 retv = (const char*)inet_ntoa(sin.sin_addr);
168 retv = strcmp("127.0.0.1", retv) ? retv : NULL;
169 if (retv) {
170 strncpy(buf, (const char*)inet_ntoa(sin.sin_addr), len);
171 break;
172 }
173 }
174
175 if (ifname_idx_array)
176 if_freenameindex(ifname_idx_array);
177
178 if (-1 != sock)
179 close(sock);
180 }
181 #endif
182
183 static char *
get_netid(LinkNetIdType which,char * buf,size_t len)184 get_netid(LinkNetIdType which,
185 char *buf,
186 size_t len)
187 {
188 if (LINK_NET_ID_IS_LOCAL == which) {
189 #ifndef G_OS_WIN32
190 return strncpy(buf, "localhost", len);
191 #else
192 return strncpy(buf, "127.0.0.1", len);
193 #endif
194 }
195
196 if ((LINK_NET_ID_IS_IPADDR == which)
197 || (LINK_NET_ID_IS_CUSTOM == which)) {
198 #ifndef G_OS_WIN32
199 if (fixed_host_net_id)
200 strncpy(buf, fixed_host_net_id, len);
201 else
202 get_first_non_local_ipaddr(buf, len);
203 if ('\0' == *buf)
204 strncpy(buf, "127.0.0.1", len);
205
206 return buf;
207 #else
208 SOCKET sock;
209 DWORD nbytes;
210 /* Let's hope 20 interfaces is enough. There doesn't
211 * seem to be any way to get information about how
212 * many interfaces there are.
213 */
214 INTERFACE_INFO interfaces[20];
215 int i;
216
217 sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
218 if (sock == INVALID_SOCKET)
219 goto out;
220
221 if (WSAIoctl (sock, SIO_GET_INTERFACE_LIST, NULL, 0,
222 interfaces, sizeof (interfaces),
223 &nbytes, NULL, NULL) == SOCKET_ERROR ||
224 nbytes == 0 ||
225 (nbytes % sizeof (INTERFACE_INFO)) != 0) {
226 closesocket (sock);
227 goto out;
228 }
229 closesocket (sock);
230
231 /* First look for a non-loopback IPv4 address */
232 for (i = 0; i < nbytes / sizeof (INTERFACE_INFO); i++) {
233 if ((interfaces[i].iiFlags & IFF_UP) &&
234 !(interfaces[i].iiFlags & IFF_LOOPBACK) &&
235 interfaces[i].iiAddress.Address.sa_family == AF_INET) {
236 d_printf("%s:%s:%d: returning %s\n", __FILE__, __FUNCTION__, __LINE__, inet_ntoa(interfaces[i].iiAddress.AddressIn.sin_addr));
237 return strncpy(buf, inet_ntoa(interfaces[i].iiAddress.AddressIn.sin_addr), len);
238 }
239 }
240
241 /* Next look for a loopback IPv4 address */
242 for (i = 0; i < nbytes / sizeof (INTERFACE_INFO); i++) {
243 if ((interfaces[i].iiFlags & IFF_UP) &&
244 (interfaces[i].iiFlags & IFF_LOOPBACK) &&
245 interfaces[i].iiAddress.Address.sa_family == AF_INET)
246 return strncpy(buf, inet_ntoa(interfaces[i].iiAddress.AddressIn.sin_addr), len);
247 }
248
249 /* Fail */
250 goto out;
251 #endif
252 }
253
254 if ((LINK_NET_ID_IS_SHORT_HOSTNAME == which) || (LINK_NET_ID_IS_FQDN == which)) {
255 d_printf("%s:%s:%d:gethostname()\n", __FILE__, __FUNCTION__, __LINE__);
256 if (gethostname(buf, len))
257 goto out;
258 #ifndef G_OS_WIN32
259 if (errno == EINVAL)
260 goto out;
261 #endif
262 if (LINK_NET_ID_IS_SHORT_HOSTNAME == which) {
263 char *retv = buf;
264 while (*buf) {
265 if ('.' == *buf)
266 *buf = '\0';
267 buf++;
268 }
269 return retv;
270 }
271 }
272
273 if (LINK_NET_ID_IS_FQDN == which) {
274 #ifdef HAVE_GETADDRINFO
275 struct addrinfo *result, hints;
276 memset(&hints, 0, sizeof(struct addrinfo));
277 hints.ai_flags = AI_CANONNAME;
278 if (!getaddrinfo(buf, NULL, &hints, &result)) {
279 strncpy(buf, result->ai_canonname, len);
280 freeaddrinfo(result);
281 } else
282 goto out;
283 #else
284 struct hostent *he;
285
286 /* gethostbyname() is MT-safe on Windows, btw */
287 d_printf("%s:%s:%d:gethostbyname(%s)\n", __FILE__, __FUNCTION__, __LINE__, buf);
288 he = gethostbyname(buf);
289
290 if (!he)
291 goto out;
292
293 strncpy(buf, he->h_name, len);
294 #endif
295 return buf;
296 }
297
298 out:
299 return NULL;
300 }
301
302 const char *
link_get_local_hostname(void)303 link_get_local_hostname (void)
304 {
305 static char local_host[NI_MAXHOST] = { 0 };
306
307 if (local_host[0])
308 return local_host;
309
310 get_netid(use_local_host, local_host, NI_MAXHOST);
311
312 return local_host;
313 }
314
315 void
link_use_local_hostname(LinkNetIdType use)316 link_use_local_hostname (LinkNetIdType use)
317 {
318 use_local_host = use;
319 }
320
321 void
link_set_local_hostname(const char * host_id)322 link_set_local_hostname (const char *host_id)
323 {
324 if (!host_id || !strlen(host_id))
325 return;
326
327 fixed_host_net_id = host_id;
328 use_local_host = LINK_NET_ID_IS_CUSTOM;
329 }
330
331 /*
332 * True if succeeded in mapping, else false.
333 */
334 static gboolean
ipv4_addr_from_addr(struct in_addr * dest_addr,guint8 * src_addr,int src_length)335 ipv4_addr_from_addr (struct in_addr *dest_addr,
336 guint8 *src_addr,
337 int src_length)
338 {
339 if (src_length == 4)
340 memcpy (dest_addr, src_addr, 4);
341
342 else if (src_length == 16) {
343 int i;
344
345 #ifdef LOCAL_DEBUG
346 g_warning ("Doing conversion ...");
347 #endif
348
349 /* An ipv6 address, might be an IPv4 mapped though */
350 for (i = 0; i < 10; i++)
351 if (src_addr [i] != 0)
352 return FALSE;
353
354 if (src_addr [10] != 0xff ||
355 src_addr [11] != 0xff)
356 return FALSE;
357
358 memcpy (dest_addr, &src_addr[12], 4);
359 } else
360 return FALSE;
361
362 return TRUE;
363 }
364
365 static gboolean
link_protocol_is_local_ipv46(const LinkProtocolInfo * proto,const struct sockaddr * saddr,LinkSockLen saddr_len)366 link_protocol_is_local_ipv46 (const LinkProtocolInfo *proto,
367 const struct sockaddr *saddr,
368 LinkSockLen saddr_len)
369 {
370 static int warned = 0;
371 #if defined (AF_INET6) && defined (HAVE_GETADDRINFO)
372 struct addrinfo hints, *result = NULL;
373 static struct addrinfo *local_addr = NULL;
374 #else
375 int i;
376 static struct hostent *local_hostent;
377 #endif
378
379 g_assert (saddr->sa_family == proto->family);
380
381 #if defined (AF_INET6) && defined (HAVE_GETADDRINFO)
382 if (!local_addr) {
383 memset(&hints, 0, sizeof(hints));
384 hints.ai_socktype = SOCK_STREAM;
385 hints.ai_flags = AI_CANONNAME;
386
387 if (getaddrinfo(link_get_local_hostname(), NULL, &hints, &local_addr) != 0) {
388 if (!warned++)
389 g_warning ("can't getaddrinfo on '%s'",
390 link_get_local_hostname ());
391 return FALSE;
392 }
393 }
394
395 if (!local_addr->ai_addr)
396 g_error ("No address for local host");
397
398 if (proto->family != AF_INET) {
399 if (proto->family == AF_INET6 &&
400 local_addr->ai_family != AF_INET6)
401 return FALSE; /* can connect via IPv4 */
402
403 if (proto->family == AF_INET6)
404 return FALSE;
405 }
406
407 for (result = local_addr; result; result = result->ai_next) {
408 int af = result->ai_family;
409
410 if ((af != AF_INET6) && (af != AF_INET))
411 continue;
412
413 /*
414 * We set the local_addr port number to the same value as
415 * in the incoming_addr since the port number does not
416 * affect testing whether the IP address is local or not.
417 * On some machines, access() fills in the port value so
418 * saddr will have a non-zero port value, and calling
419 * getaddrinfo() on "localhost" will have 0 for the port
420 * value. So doing this ensures the test will not fail
421 * if the port numbers are different. Note that this code
422 * is protected by the I/O thread so this is handled
423 * synchronously, so it is safe to modify the static
424 * local_addr value.
425 */
426 if (proto->family == AF_INET) {
427 if (af == AF_INET) {
428 struct in_addr ipv4_def_addr;
429
430 struct sockaddr_in * localaddr;
431 struct sockaddr_in * incomingaddr;
432
433 inet_aton ("127.0.0.1", &ipv4_def_addr);
434 localaddr = (struct sockaddr_in *)result->ai_addr;
435 incomingaddr = (struct sockaddr_in *)saddr;
436 localaddr->sin_port = incomingaddr->sin_port;
437 if (ipv4_def_addr.s_addr == incomingaddr->sin_addr.s_addr ||
438 !memcmp (localaddr, incomingaddr, result->ai_addrlen)) {
439 #ifdef LOCAL_DEBUG
440 g_warning ("local ipv4 address");
441 #endif
442 return TRUE;
443 }
444 }
445 }
446 else {
447 if (af == AF_INET6) {
448 struct in6_addr ipv6_def_addr;
449 struct sockaddr_in6 * localaddr;
450 struct sockaddr_in6 * incomingaddr;
451
452 inet_pton (AF_INET6, "::1", (void *)&ipv6_def_addr);
453 localaddr = (struct sockaddr_in6 *)result->ai_addr;
454 incomingaddr = (struct sockaddr_in6 *)saddr;
455 localaddr->sin6_port = incomingaddr->sin6_port;
456 if (!memcmp (&ipv6_def_addr, &incomingaddr->sin6_addr, sizeof(ipv6_def_addr))
457 || !memcmp (localaddr, incomingaddr, result->ai_addrlen)) {
458 #ifdef LOCAL_DEBUG
459 g_warning ("local ipv6 address");
460 #endif
461 return TRUE;
462 }
463 }
464 }
465 }
466 #ifdef LOCAL_DEBUG
467 g_warning ("No match over all");
468 #endif
469 return FALSE;
470 #else /*HAVE_GETADDRINFO*/
471
472 /* Do simple check for INADDR_LOOPBACK first */
473 if (saddr->sa_family == AF_INET &&
474 ((struct sockaddr_in *)saddr)->sin_addr.s_addr == htonl (INADDR_LOOPBACK)) {
475 #ifdef LOCAL_DEBUG
476 /* I don't understand why g_warning() is used here,
477 * but as the existing code does this if LOCAL_DEBUG
478 * is defined and we are going to return TRUE, keep
479 * doing it like that then... Not that I know if
480 * anybody is using the LOCAL_DEBUG possibility?
481 */
482 g_warning ("local ipv4 address");
483 #endif
484 return TRUE;
485 }
486
487 #ifdef AF_INET6
488 /* Then simple check for IPv6 loopback address */
489 if (saddr->sa_family == AF_INET6 &&
490 IN6_IS_ADDR_LOOPBACK (saddr)) {
491 #ifdef LOCAL_DEBUG
492 g_warning ("local ipv6 address");
493 #endif
494 return TRUE;
495 }
496 #endif
497
498 if (!local_hostent) {
499 LINK_RESOLV_SET_IPV6;
500 d_printf("%s:%s:%d:gethostbyname(%s)\n", __FILE__, __FUNCTION__, __LINE__, link_get_local_hostname ());
501 local_hostent = gethostbyname (link_get_local_hostname ());
502 }
503
504 if (!local_hostent) {
505 if (!warned++)
506 g_warning ("can't gethostbyname on '%s'",
507 link_get_local_hostname ());
508 return FALSE;
509 }
510
511 if (!local_hostent->h_addr_list)
512 g_error ("No address for local host");
513
514 if (proto->family != AF_INET) {
515 #ifdef AF_INET6
516 if (proto->family == AF_INET6 &&
517 local_hostent->h_addrtype != AF_INET6)
518 return FALSE; /* can connect via IPv4 */
519
520 if (proto->family != AF_INET6)
521 return FALSE;
522 #else
523 return FALSE;
524 #endif
525 }
526
527 for (i = 0; local_hostent->h_addr_list [i]; i++) {
528
529 if (proto->family == AF_INET) {
530 struct in_addr ipv4_addr;
531
532 if (!ipv4_addr_from_addr (&ipv4_addr,
533 (guint8 *)local_hostent->h_addr_list [i],
534 local_hostent->h_length))
535 continue;
536
537 if (!memcmp (&ipv4_addr,
538 &((struct sockaddr_in *)saddr)->sin_addr.s_addr, 4)) {
539 #ifdef LOCAL_DEBUG
540 g_warning ("local ipv4 address");
541 #endif
542 return TRUE;
543 }
544
545 }
546 #ifdef AF_INET6
547 else if (!memcmp (local_hostent->h_addr_list [i],
548 &((struct sockaddr_in6 *)saddr)->sin6_addr.s6_addr,
549 local_hostent->h_length)) {
550 #ifdef LOCAL_DEBUG
551 g_warning ("local ipv6 address");
552 #endif
553 return TRUE;
554 }
555 #endif
556 }
557
558 #ifdef LOCAL_DEBUG
559 g_warning ("No match over all");
560 #endif
561
562 return FALSE;
563 #endif /*HAVE_GETADDRINFO*/
564 }
565
566 #endif
567
568 /*
569 * link_protocol_get_sockaddr_ipv4:
570 * @proto: the #LinkProtocolInfo structure for the IPv4 protocol.
571 * @hostname: the hostname.
572 * @portnum: the port number.
573 * @saddr_len: location in which to store the returned structure's length.
574 *
575 * Allocates and fills a #sockaddr_in with with the IPv4 address
576 * information.
577 *
578 * Return Value: a pointer to a valid #sockaddr_in structure if the call
579 * succeeds, NULL otherwise.
580 */
581 #ifdef AF_INET
582 static struct sockaddr *
link_protocol_get_sockaddr_ipv4(const LinkProtocolInfo * proto,const char * hostname,const char * portnum,LinkSockLen * saddr_len)583 link_protocol_get_sockaddr_ipv4 (const LinkProtocolInfo *proto,
584 const char *hostname,
585 const char *portnum,
586 LinkSockLen *saddr_len)
587 {
588 struct sockaddr_in *saddr;
589 struct hostent *host;
590
591 g_assert (proto->family == AF_INET);
592 g_assert (hostname);
593
594 if (!portnum)
595 portnum = "0";
596
597 saddr = g_new0 (struct sockaddr_in, 1);
598
599 *saddr_len = sizeof (struct sockaddr_in);
600
601 LINK_SET_SOCKADDR_LEN (saddr, sizeof (struct sockaddr_in));
602
603 saddr->sin_family = AF_INET;
604 saddr->sin_port = htons (atoi (portnum));
605
606 if ((saddr->sin_addr.s_addr = inet_addr (hostname)) == INADDR_NONE) {
607 int i;
608
609 LINK_RESOLV_UNSET_IPV6;
610 #ifdef HAVE_RESOLV_H
611 if (!(_res.options & RES_INIT))
612 res_init();
613 #endif
614
615 d_printf("%s:%s:%d:gethostbyname(%s)\n", __FILE__, __FUNCTION__, __LINE__, hostname);
616 host = gethostbyname (hostname);
617 if (!host) {
618 g_free (saddr);
619 return NULL;
620 }
621
622 for(i = 0; host->h_addr_list[i]; i++)
623 if(ipv4_addr_from_addr (&saddr->sin_addr,
624 (guint8 *)host->h_addr_list [i],
625 host->h_length))
626 break;
627
628 if(!host->h_addr_list[i]) {
629 g_free (saddr);
630 return NULL;
631 }
632 }
633
634 return (struct sockaddr *) saddr;
635 }
636 #endif /* AF_INET */
637
638 /*
639 * link_protocol_get_sockaddr_ipv6:
640 * @proto: the #LinkProtocolInfo structure for the IPv6 protocol.
641 * @hostname: the hostname.
642 * @portnum: the port number
643 * @saddr_len: location in which to store the returned structure's length.
644 *
645 * Allocates and fills a #sockaddr_in6 with with the IPv6 address
646 * information.
647 *
648 * NOTE: This function is untested.
649 *
650 * Return Value: a pointer to a valid #sockaddr_in6 structure if the call
651 * succeeds, NULL otherwise.
652 */
653 #ifdef AF_INET6
654 static struct sockaddr *
link_protocol_get_sockaddr_ipv6(const LinkProtocolInfo * proto,const char * hostname,const char * portnum,LinkSockLen * saddr_len)655 link_protocol_get_sockaddr_ipv6 (const LinkProtocolInfo *proto,
656 const char *hostname,
657 const char *portnum,
658 LinkSockLen *saddr_len)
659 {
660 struct sockaddr_in6 *saddr;
661 #ifdef HAVE_GETADDRINFO
662 struct addrinfo *host, hints, *result = NULL;
663 #else
664 struct hostent *host;
665
666 #endif
667 g_assert (proto->family == AF_INET6);
668 g_assert (hostname);
669
670 if (!portnum)
671 portnum = "0";
672
673 saddr = g_new0 (struct sockaddr_in6, 1);
674
675 *saddr_len = sizeof (struct sockaddr_in6);
676
677 LINK_SET_SOCKADDR_LEN (saddr, sizeof (struct sockaddr_in6));
678
679 saddr->sin6_family = AF_INET6;
680 saddr->sin6_port = htons (atoi (portnum));
681 #ifdef HAVE_INET_PTON
682 if (inet_pton (AF_INET6, hostname, &saddr->sin6_addr) > 0)
683 return (struct sockaddr *)saddr;
684 #endif
685 #ifdef HAVE_GETADDRINFO
686 memset (&hints, 0, sizeof(hints));
687 hints.ai_socktype = SOCK_STREAM;
688
689 if (getaddrinfo (hostname, NULL, &hints, &result))
690 return NULL;
691
692 for (host = result; host; host = host->ai_next) {
693 if (host->ai_family == AF_INET6)
694 break;
695 }
696 if (!host) {
697 g_free (saddr);
698 freeaddrinfo (result);
699 return NULL;
700 }
701 memcpy (&saddr->sin6_addr, &((struct sockaddr_in6 *)host->ai_addr)->sin6_addr, sizeof (struct in6_addr));
702 freeaddrinfo (result);
703
704 return (struct sockaddr *)saddr;
705 #else
706
707 #ifdef HAVE_RESOLV_H
708 if (!(_res.options & RES_INIT))
709 res_init();
710 #endif
711
712 LINK_RESOLV_SET_IPV6;
713 d_printf("%s:%s:%d:gethostbyname(%s)\n", __FILE__, __FUNCTION__, __LINE__, hostname);
714 host = gethostbyname (hostname);
715 if (!host || host->h_addrtype != AF_INET6) {
716 g_free (saddr);
717 return NULL;
718 }
719
720 memcpy (&saddr->sin6_addr, host->h_addr_list[0], sizeof (struct in6_addr));
721
722 return (struct sockaddr *)saddr;
723 #endif /* HAVE_GETADDRINFO */
724 }
725 #endif /* AF_INET6 */
726
727 #ifdef AF_UNIX
728 /*
729 * link_protocol_get_sockaddr_unix:
730 * @proto: the #LinkProtocolInfo structure for the UNIX sockets protocol.
731 * @dummy: not used.
732 * @path: the path name of the UNIX socket.
733 * @saddr_len: location in which to store the returned structure's length.
734 *
735 * Allocates and fills a #sockaddr_un with with the UNIX socket address
736 * information.
737 *
738 * If @path is NULL, a new, unique path name will be generated.
739 *
740 * Return Value: a pointer to a valid #sockaddr_un structure if the call
741 * succeeds, NULL otherwise.
742 */
743 static struct sockaddr *
link_protocol_get_sockaddr_unix(const LinkProtocolInfo * proto,const char * dummy,const char * path,LinkSockLen * saddr_len)744 link_protocol_get_sockaddr_unix (const LinkProtocolInfo *proto,
745 const char *dummy,
746 const char *path,
747 LinkSockLen *saddr_len)
748 {
749 struct sockaddr_un *saddr;
750 int pathlen;
751 char buf[LINK_UNIX_PATH_MAX], *actual_path;
752
753 g_assert (proto->family == AF_UNIX);
754
755 if (!path) {
756 struct timeval t;
757 static guint pid = 0, idx = 0;
758
759 if (!pid)
760 pid = getpid ();
761
762 gettimeofday (&t, NULL);
763 g_snprintf (buf, sizeof (buf),
764 "%s/linc-%x-%x-%x%x",
765 link_tmpdir ? link_tmpdir : "",
766 pid, idx,
767 (guint) (rand() ^ t.tv_sec),
768 (guint) (idx ^ t.tv_usec));
769 idx++;
770 #ifdef CONNECTION_DEBUG
771 if (g_file_test (buf, G_FILE_TEST_EXISTS))
772 g_warning ("'%s' already exists !", buf);
773 #endif
774 actual_path = buf;
775 } else
776 actual_path = (char *)path;
777
778 pathlen = strlen (actual_path) + 1;
779
780 if (pathlen > sizeof (saddr->sun_path))
781 return NULL;
782
783 saddr = g_new0 (struct sockaddr_un, 1);
784
785 *saddr_len = sizeof (struct sockaddr_un) - sizeof (saddr->sun_path) + pathlen;
786
787 LINK_SET_SOCKADDR_LEN (saddr, *saddr_len);
788
789 saddr->sun_family = AF_UNIX;
790 strncpy (saddr->sun_path, actual_path, sizeof (saddr->sun_path) - 1);
791 saddr->sun_path[sizeof (saddr->sun_path) - 1] = '\0';
792
793 return (struct sockaddr *)saddr;
794 }
795 #endif /* AF_UNIX */
796
797 /*
798 * link_protocol_get_sockaddr:
799 * @proto: a #LinkProtocolInfo structure.
800 * @hostname: protocol dependant host information.
801 * @service: protocol dependant service information.
802 * @saddr_len: location in which to store the returned structure's length.
803 *
804 * Allocates, fills in and returns the #sockaddr structure appropriate
805 * for the supplied protocol, @proto.
806 *
807 * Return Value: a pointer to a valid #sockaddr structure if the call
808 * succeeds, NULL otherwise.
809 */
810 struct sockaddr *
link_protocol_get_sockaddr(const LinkProtocolInfo * proto,const char * hostname,const char * service,LinkSockLen * saddr_len)811 link_protocol_get_sockaddr (const LinkProtocolInfo *proto,
812 const char *hostname,
813 const char *service,
814 LinkSockLen *saddr_len)
815 {
816 if (proto && proto->get_sockaddr)
817 return proto->get_sockaddr (proto, hostname, service, saddr_len);
818
819 return NULL;
820 }
821
822 /*
823 * link_protocol_get_sockinfo_ipv46:
824 * @host: char pointer describing the hostname.
825 * @port: the portnumber.
826 * @hostname: pointer by which the hostname string is returned.
827 * @portnum: pointer by which the port number string is returned.
828 *
829 * Generates two strings, returned through @hostname and @portnum, corresponding
830 * to @host and @port. On return @hostname should contain the canonical hostname
831 * of the host and @portnum should contain the port number string.
832 *
833 * If @host is NULL, the local host name is used.
834 *
835 * Note: both @hostname and @service are allocated on the heap and should be
836 * freed using g_free().
837 *
838 * Return Value: #TRUE if the function succeeds, #FALSE otherwise.
839 */
840 static gboolean
link_protocol_get_sockinfo_ipv46(const char * host,guint port,gchar ** hostname,char ** portnum)841 link_protocol_get_sockinfo_ipv46 (const char *host,
842 guint port,
843 gchar **hostname,
844 char **portnum)
845 {
846 if (!host)
847 if (!(host = link_get_local_hostname ()))
848 return FALSE;
849
850 if (hostname)
851 *hostname = g_strdup (host);
852
853 if (portnum) {
854 gchar tmpport[NI_MAXSERV];
855
856 g_snprintf (tmpport, sizeof (tmpport), "%d", ntohs (port));
857
858 *portnum = g_strdup (tmpport);
859 }
860
861 return TRUE;
862 }
863
864 /*
865 * link_protocol_get_sockinfo_ipv4:
866 * @proto: the #LinkProtocolInfo structure for the IPv4 protocol.
867 * @sockaddr: a #sockaddr_in structure desribing the socket.
868 * @hostname: pointer by which the hostname string is returned.
869 * @portnum: pointer by which the port number string is returned.
870 *
871 * Generates two strings, returned through @hostname and @portnum, describing
872 * the socket address, @sockaddr. On return @hostname should contain the
873 * canonical hostname of the host described in @sockaddr and @portnum should
874 * contain the port number of the socket described in @sockaddr.
875 *
876 * Note: both @hostname and @service are allocated on the heap and should be
877 * freed using g_free().
878 *
879 * Return Value: #TRUE if the function succeeds, #FALSE otherwise.
880 */
881 #ifdef AF_INET
882 static gboolean
link_protocol_get_sockinfo_ipv4(const LinkProtocolInfo * proto,const struct sockaddr * saddr,gchar ** hostname,gchar ** portnum)883 link_protocol_get_sockinfo_ipv4 (const LinkProtocolInfo *proto,
884 const struct sockaddr *saddr,
885 gchar **hostname,
886 gchar **portnum)
887 {
888 struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr;
889 struct hostent *host = NULL;
890 char *hname = NULL;
891
892 g_assert (proto && saddr && saddr->sa_family == AF_INET);
893
894 #ifdef G_OS_WIN32
895 hname = inet_ntoa(sa_in->sin_addr);
896 #else
897 if (ntohl (sa_in->sin_addr.s_addr) != INADDR_ANY) {
898 host = gethostbyaddr ((char *)&sa_in->sin_addr,
899 sizeof (struct in_addr), AF_INET);
900 if (host)
901 hname = host->h_name;
902 }
903 #endif
904 return link_protocol_get_sockinfo_ipv46 (hname, sa_in->sin_port,
905 hostname, portnum);
906 }
907 #endif /* AF_INET */
908
909 /*
910 * link_protocol_get_sockinfo_ipv6:
911 * @proto: the #LinkProtocolInfo structure for the IPv6 protocol.
912 * @sockaddr: a #sockaddr_in structure desribing the socket.
913 * @hostname: pointer by which the hostname string is returned.
914 * @portnum: pointer by which the port number string is returned.
915 *
916 * Generates two strings, returned through @hostname and @portnum, describing
917 * the socket address, @sockaddr. On return @hostname should contain the
918 * canonical hostname of the host described in @sockaddr and @portnum should
919 * contain the port number of the socket described in @sockaddr.
920 *
921 * Note: both @hostname and @service are allocated on the heap and should be
922 * freed using g_free().
923 *
924 * Return Value: #TRUE if the function succeeds, #FALSE otherwise.
925 */
926 #ifdef AF_INET6
927
928 /*
929 * We need some explicit check for Macs here - OSF1 does this
930 * right, and does not use a #define; so the Mac gets to break for
931 * now, until someone sends me a patch.
932 */
933 #ifdef MAC_OS_X_IS_SO_BROKEN
934 /* FIXME: is IN6ADDR_ANY_INIT exported on Mac OS X ? */
935 /* on Mac OS X 10.1 inaddr6_any isn't exported by libc */
936 # ifndef in6addr_any
937 static const struct in6_addr in6addr_any = { { { 0 } } };
938 # endif
939 #endif
940
941 static gboolean
link_protocol_get_sockinfo_ipv6(const LinkProtocolInfo * proto,const struct sockaddr * saddr,gchar ** hostname,gchar ** portnum)942 link_protocol_get_sockinfo_ipv6 (const LinkProtocolInfo *proto,
943 const struct sockaddr *saddr,
944 gchar **hostname,
945 gchar **portnum)
946 {
947 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)saddr;
948 #ifdef HAVE_GETNAMEINFO
949 char hbuf[NI_MAXHOST];
950 #else
951 struct hostent *host = NULL;
952 #endif
953 char *hname = NULL;
954
955 g_assert (proto && saddr && saddr->sa_family == AF_INET6);
956
957 if (memcmp (&sa_in6->sin6_addr, &in6addr_any, sizeof (struct in6_addr))) {
958
959 #ifdef HAVE_GETNAMEINFO
960 if (!getnameinfo((struct sockaddr *)sa_in6, sizeof(*sa_in6), hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD))
961 hname = hbuf;
962 }
963 #else
964 host = gethostbyaddr ((char *)&sa_in6->sin6_addr,
965 sizeof (struct in6_addr), AF_INET6);
966 if (host)
967 hname = host->h_name;
968 }
969 #endif /* HAVE_GETNAMEINFO */
970
971 return link_protocol_get_sockinfo_ipv46 (hname, sa_in6->sin6_port,
972 hostname, portnum);
973 }
974
975 #endif /* AF_INET6 */
976
977 /*
978 * link_protocol_get_sockinfo_unix:
979 * @proto: a #LinkProtocolInfo structure.
980 * @sockaddr: a #sockaddr_un structure desribing the socket.
981 * @hostname: pointer by which the hostname string is returned.
982 * @service: pointer by which the sockets pathname string is returned.
983 *
984 * Generates two strings, returned through @hostname and @sock_path, describing
985 * the socket address, @sockaddr. On return @hostname should contain the
986 * canonical hostname of the local host and @sock_path should contain the
987 * path name of the unix socket described in @sockaddr.
988 *
989 * Note: both @hostname and @sock_path are allocated on the heap and should
990 * be freed using g_free().
991 *
992 * Return Value: #TRUE if the function succeeds, #FALSE otherwise.
993 */
994 #ifdef AF_UNIX
995 static gboolean
link_protocol_get_sockinfo_unix(const LinkProtocolInfo * proto,const struct sockaddr * saddr,gchar ** hostname,gchar ** sock_path)996 link_protocol_get_sockinfo_unix (const LinkProtocolInfo *proto,
997 const struct sockaddr *saddr,
998 gchar **hostname,
999 gchar **sock_path)
1000 {
1001 struct sockaddr_un *sa_un = (struct sockaddr_un *)saddr;
1002
1003 g_assert (proto && saddr && saddr->sa_family == AF_UNIX);
1004
1005 if (hostname) {
1006 const char *local_host;
1007
1008 if (!(local_host = link_get_local_hostname ()))
1009 return FALSE;
1010
1011 *hostname = g_strdup (local_host);
1012 }
1013
1014 if (sock_path)
1015 *sock_path = g_strdup (sa_un->sun_path);
1016
1017 return TRUE;
1018 }
1019
1020 /*
1021 * link_protocol_post_create_unix:
1022 * @fd: the file descriptor.
1023 * @sockaddr: a #sockaddr_un structure describing the socket.
1024 *
1025 * For a user running a program as root, set the owner of the socket to
1026 * the original user.
1027 */
1028 static void
link_protocol_post_create_unix(int fd,struct sockaddr * saddr)1029 link_protocol_post_create_unix (int fd, struct sockaddr *saddr)
1030 {
1031 #ifndef G_OS_WIN32
1032 struct sockaddr_un *saddr_un = (struct sockaddr_un *)saddr;
1033
1034 if (getuid() == 0) {
1035 struct stat stat_buf;
1036 if (!stat (link_tmpdir, &stat_buf))
1037 chown (saddr_un->sun_path, stat_buf.st_uid, -1);
1038 }
1039 #endif
1040 }
1041 #endif /* AF_UNIX */
1042
1043 /*
1044 * link_protocol_get_sockinfo:
1045 * @proto: a #LinkProtocolInfo structure.
1046 * @sockaddr: a #sockadrr structure desribing the socket.
1047 * @hostname: pointer by which the hostname string is returned.
1048 * @service: pointer by which the service string is returned.
1049 *
1050 * Generates two strings, returned through @hostname and @service, describing
1051 * the socket address, @sockaddr. On return @hostname should contain the
1052 * canonical hostname of the host described in @sockaddr and @service should
1053 * contain the service descriptor(e.g. port number) of the socket described in
1054 * @sockaddr
1055 *
1056 * Note: both @hostname and @service are allocated on the heap and should be
1057 * freed using g_free().
1058 *
1059 * Return Value: #TRUE if the function succeeds, #FALSE otherwise.
1060 */
1061 gboolean
link_protocol_get_sockinfo(const LinkProtocolInfo * proto,const struct sockaddr * saddr,gchar ** hostname,gchar ** service)1062 link_protocol_get_sockinfo (const LinkProtocolInfo *proto,
1063 const struct sockaddr *saddr,
1064 gchar **hostname,
1065 gchar **service)
1066 {
1067 if (proto && proto->get_sockinfo)
1068 return proto->get_sockinfo (proto, saddr, hostname, service);
1069
1070 return FALSE;
1071 }
1072
1073 /**
1074 * link_protocol_is_local:
1075 * @proto: the protocol
1076 * @saddr: the socket address of a connecting client.
1077 *
1078 * This method determines if the client is from the same
1079 * machine or not - per protocol.
1080 *
1081 * Return value: TRUE if the connection is local, else FALSE
1082 **/
1083 gboolean
link_protocol_is_local(const LinkProtocolInfo * proto,const struct sockaddr * saddr,LinkSockLen saddr_len)1084 link_protocol_is_local (const LinkProtocolInfo *proto,
1085 const struct sockaddr *saddr,
1086 LinkSockLen saddr_len)
1087 {
1088 if (proto && proto->is_local)
1089 return proto->is_local (proto, saddr, saddr_len);
1090
1091 return FALSE;
1092 }
1093
1094 /*
1095 * af_unix_destroy:
1096 * @fd: file descriptor of the socket.
1097 * @dummy: not used.
1098 * @pathname: path name of the UNIX socket
1099 *
1100 * Removes the UNIX socket file.
1101 */
1102 #ifdef AF_UNIX
1103 static void
link_protocol_unix_destroy(int fd,const char * dummy,const char * pathname)1104 link_protocol_unix_destroy (int fd,
1105 const char *dummy,
1106 const char *pathname)
1107 {
1108 g_unlink (pathname);
1109 }
1110
1111 static gboolean
link_protocol_unix_is_local(const LinkProtocolInfo * proto,const struct sockaddr * saddr,LinkSockLen saddr_len)1112 link_protocol_unix_is_local (const LinkProtocolInfo *proto,
1113 const struct sockaddr *saddr,
1114 LinkSockLen saddr_len)
1115 {
1116 return TRUE;
1117 }
1118 #endif /* AF_UNIX */
1119
1120 /*
1121 * link_protocol_tcp_setup:
1122 * @fd: file descriptor of the socket.
1123 * @cnx_flags: a #LinkConnectionOptions value.
1124 *
1125 * Sets the TCP_NODELAY option on the TCP socket.
1126 *
1127 * Note: this is not applied to SSL TCP sockets.
1128 */
1129 #if defined(AF_INET) || defined(AF_INET6)
1130 static void
link_protocol_tcp_setup(int fd,LinkConnectionOptions cnx_flags)1131 link_protocol_tcp_setup (int fd,
1132 LinkConnectionOptions cnx_flags)
1133 {
1134 #ifdef TCP_NODELAY
1135 if (!(cnx_flags & LINK_CONNECTION_SSL)) {
1136 struct protoent *proto;
1137 int on = 1;
1138
1139 proto = getprotobyname ("tcp");
1140 if (!proto)
1141 return;
1142
1143 setsockopt (fd, proto->p_proto, TCP_NODELAY,
1144 (const char *) &on, sizeof (on));
1145 }
1146 #endif
1147 }
1148 #endif /* defined(AF_INET) || defined(AF_INET6) */
1149
1150 /*
1151 * Comments from bug #422908.
1152 * Since version 2.14.9 we now always set the flag
1153 * LINK_PROTOCOL_NEEDS_BIND for IPv4 and IPv6. This was
1154 * changed because on Solaris this bind is needed to open
1155 * the ports securely when ORBLocalOnly is being used. The
1156 * maintainers decided it would be best to simply turn the
1157 * flag on for all platforms rather than support complicated
1158 * ifdefs. We believe this will not cause any issues.
1159 * However, if there is a need to revert, please make sure
1160 * that this flag continues to be set for the following
1161 * platforms at minimum:
1162 *
1163 * IPv4: #if defined (G_OS_WIN32) || defined (__sun)
1164 * IPv6: #if defined (__sun)
1165 */
1166 static LinkProtocolInfo static_link_protocols[] = {
1167 #if defined(AF_INET)
1168 {
1169 "IPv4", /* name */
1170 AF_INET, /* family */
1171 sizeof (struct sockaddr_in), /* addr_len */
1172 IPPROTO_TCP, /* stream_proto_num */
1173 LINK_PROTOCOL_NEEDS_BIND, /* flags */
1174 link_protocol_tcp_setup, /* setup */
1175 NULL, /* destroy */
1176 link_protocol_get_sockaddr_ipv4,/* get_sockaddr */
1177 link_protocol_get_sockinfo_ipv4,/* get_sockinfo */
1178 link_protocol_is_local_ipv46, /* is_local */
1179 NULL /* post_create */
1180 },
1181 #endif
1182 #if defined(AF_INET6)
1183 {
1184 "IPv6", /* name */
1185 AF_INET6, /* family */
1186 sizeof (struct sockaddr_in6), /* addr_len */
1187 IPPROTO_TCP, /* stream_proto_num */
1188 LINK_PROTOCOL_NEEDS_BIND, /* flags */
1189 link_protocol_tcp_setup, /* setup */
1190 NULL, /* destroy */
1191 link_protocol_get_sockaddr_ipv6,/* get_sockaddr */
1192 link_protocol_get_sockinfo_ipv6,/* get_sockinfo */
1193 link_protocol_is_local_ipv46, /* is_local */
1194 NULL /* post_create */
1195 },
1196 #endif
1197 #ifdef AF_UNIX
1198 {
1199 "UNIX", /* name */
1200 AF_UNIX, /* family */
1201 sizeof (struct sockaddr_un), /* addr_len */
1202 0, /* stream_proto_num */
1203 LINK_PROTOCOL_SECURE|LINK_PROTOCOL_NEEDS_BIND, /* flags */
1204 NULL, /* setup */
1205 link_protocol_unix_destroy, /* destroy */
1206 link_protocol_get_sockaddr_unix, /* get_sockaddr */
1207 link_protocol_get_sockinfo_unix, /* get_sockinfo */
1208 link_protocol_unix_is_local, /* is_local */
1209 link_protocol_post_create_unix /* post_create */
1210 },
1211 #endif
1212 { NULL /* name */ }
1213 };
1214
1215 void
link_protocol_destroy_cnx(const LinkProtocolInfo * proto,int fd,const char * host,const char * service)1216 link_protocol_destroy_cnx (const LinkProtocolInfo *proto,
1217 int fd,
1218 const char *host,
1219 const char *service)
1220 {
1221 g_return_if_fail (proto != NULL);
1222
1223 if (fd >= 0) {
1224 if (proto->destroy)
1225 proto->destroy (fd, host, service);
1226 d_printf ("link_protocol_destroy_cnx: closing %d\n", fd);
1227 LINK_CLOSE_SOCKET (fd);
1228 }
1229 }
1230
1231
1232 void
link_protocol_destroy_addr(const LinkProtocolInfo * proto,int fd,struct sockaddr * saddr)1233 link_protocol_destroy_addr (const LinkProtocolInfo *proto,
1234 int fd,
1235 struct sockaddr *saddr)
1236 {
1237 g_return_if_fail (proto != NULL);
1238
1239 if (fd >= 0) {
1240 #ifdef AF_UNIX
1241 if (proto->family == AF_UNIX && proto->destroy) {
1242 /* We are AF_UNIX - we need the path to unlink */
1243 struct sockaddr_un *addr_un =
1244 (struct sockaddr_un *) saddr;
1245 proto->destroy (fd, NULL, addr_un->sun_path);
1246 }
1247 #endif
1248 d_printf ("link_protocol_destroy_addr: closing %d\n", fd);
1249 LINK_CLOSE_SOCKET (fd);
1250 g_free (saddr);
1251 }
1252
1253 }
1254
1255 /*
1256 * link_protocol_all:
1257 *
1258 * Returns a list of protocols supported by linc.
1259 *
1260 * Note: the list is terminated by a #LinkProtocolInfo with a
1261 * NULL name pointer.
1262 *
1263 * Return Value: an array of #LinkProtocolInfo structures.
1264 */
1265 LinkProtocolInfo *
link_protocol_all(void)1266 link_protocol_all (void)
1267 {
1268 return static_link_protocols;
1269 }
1270
1271 /*
1272 * link_protocol_find:
1273 * @name: name of the protocol.
1274 *
1275 * Find a protocol identified by @name.
1276 *
1277 * Return Value: a pointer to a valid #LinkProtocolInfo structure if
1278 * the protocol is supported by linc, NULL otherwise.
1279 */
1280 LinkProtocolInfo *
link_protocol_find(const char * name)1281 link_protocol_find (const char *name)
1282 {
1283 int i;
1284
1285 for (i = 0; static_link_protocols [i].name; i++) {
1286 if (!strcmp (name, static_link_protocols [i].name))
1287 return &static_link_protocols [i];
1288 }
1289
1290 return NULL;
1291 }
1292
1293 /*
1294 * link_protocol_find_num:
1295 * @family: the family identifier of the protocol - i.e. AF_*
1296 *
1297 * Find a protocol identified by @family.
1298 *
1299 * Return Value: a pointer to a valid #LinkProtocolInfo structure if
1300 * the protocol is supported by linc, NULL otherwise.
1301 */
1302 LinkProtocolInfo *
link_protocol_find_num(const int family)1303 link_protocol_find_num (const int family)
1304 {
1305 int i;
1306
1307 for (i = 0; static_link_protocols [i].name; i++) {
1308 if (family == static_link_protocols [i].family)
1309 return &static_link_protocols [i];
1310 }
1311
1312 return NULL;
1313 }
1314