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