1 /* This is a simple name server for GNUstep Distributed Objects
2    Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc.
3 
4    Written by:  Richard Frith-Macdonald <richard@brainstorm.co.uk>
5    Created: October 1996
6 
7    This file is part of the GNUstep Base Library.
8 
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public
11    License as published by the Free Software Foundation; either
12    version 2 of the License, or (at your option) any later version.
13 
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18 
19    You should have received a copy of the GNU General Public
20    License along with this library; if not, write to the Free
21    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22    Boston, MA 02111 USA.
23    */
24 
25 /* Ported to mingw 07/12/00 by Bjorn Giesler <Bjoern.Giesler@gmx.de> */
26 
27 #include "config.h"
28 
29 #if	!defined(__MINGW__)
30 #  if	defined(__MINGW32__) || defined(__MINGW64__)
31 #    define	__MINGW__
32 #  endif
33 #endif
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <unistd.h>		/* for gethostname() */
39 #include <inttypes.h>
40 #ifndef __MINGW__
41 #include <sys/param.h>		/* for MAXHOSTNAMELEN */
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>		/* for inet_ntoa() */
46 #endif /* !__MINGW__ */
47 #include <errno.h>
48 #include <limits.h>
49 #include <string.h>		/* for strchr() */
50 #include <ctype.h>		/* for strchr() */
51 #include <fcntl.h>
52 #if	defined(__MINGW__)
53 #include <stdint.h>
54 #include <winsock2.h>
55 #include <ws2tcpip.h>
56 #include <wininet.h>
57 #include <process.h>
58 #include <sys/time.h>
59 #else
60 #include <sys/time.h>
61 #include <sys/resource.h>
62 #include <netdb.h>
63 #include <signal.h>
64 #include <sys/socket.h>
65 #include <sys/file.h>
66 #if	defined(HAVE_TIME_H)
67 #include <time.h>
68 #endif
69 #if	defined(HAVE_PWD_H)
70 #include <pwd.h>
71 #endif
72 #if	defined(HAVE_GRP_H)
73 #include <grp.h>
74 #endif
75 
76 #if HAVE_GETOPT_H
77 #include <getopt.h>
78 #endif
79 
80 /*
81  *	Stuff for setting the sockets into non-blocking mode.
82  */
83 #if	defined(__POSIX_SOURCE) || defined(__EXT_POSIX1_198808)
84 #define NBLK_OPT     O_NONBLOCK
85 #else
86 #define NBLK_OPT     FNDELAY
87 #endif
88 
89 #include <netinet/in.h>
90 #include <net/if.h>
91 #if	!defined(SIOCGIFCONF) || defined(__CYGWIN__)
92 #include <sys/ioctl.h>
93 #ifndef	SIOCGIFCONF
94 #include <sys/sockio.h>
95 #endif
96 #endif
97 
98 #if	defined(__svr4__)
99 #if defined(HAVE_SYS_STROPTS_H)
100 #include <sys/stropts.h>
101 #endif
102 #endif
103 #endif /* !__MINGW__ */
104 
105 
106 #if	defined(HAVE_SYSLOG_H)
107 #include <syslog.h>
108 #elif   defined(HAVE_SYS_SLOG_H)
109 #  include <sys/slog.h>
110 #  if 	defined(HAVE_SYS_SLOGCODES_H)
111 #    include <sys/slogcodes.h>
112 #  endif
113 #endif
114 
115 #if	HAVE_STRERROR
116   #define	lastErr()	strerror(errno)
117 #else
118 #if	defined(__MINGW__)
119 static	errbuf[BUFSIZ];
120   #define	lastErr()	(sprintf(errbuf, "WSAGetLastError()=%d", WSAGetLastError()), errbuf)
121 #else
122 static	errbuf[BUFSIZ];
123   #define	lastErr()	(sprintf(errbuf, "%m"), errbuf)
124 #endif
125 #endif
126 
127 #include	"gdomap.h"
128 /*
129  *	ABOUT THIS PROGRAM
130  *
131  *	This is a simple name server for GNUstep Distributed Objects
132  *	The server program listens on a well known port (service name 'gdomap')
133  *
134  *	The officially assigned port is 538.  On most systems port numbers
135  *	under 1024 can only be used by root (for security).  So this program
136  *	needs to be run as root.
137  *
138  *	This is UNIX code - I have no idea how portable to other OSs it may be.
139  *
140  *	For detailed information about the communication protocol used - see
141  *	the include file.
142  */
143 
144 /* For IRIX machines, which don't define this */
145 #ifndef        IPPORT_USERRESERVED
146 #define        IPPORT_USERRESERVED     5000
147 #endif /* IPPORT_USERRESERVED */
148 
149 #define QUEBACKLOG	(16)	/* How many coonections to queue.	*/
150 #define	MAX_IFACE	(256)	/* How many network interfaces.		*/
151 #define	IASIZE		(sizeof(struct in_addr))
152 
153 #define	MAX_EXTRA	((GDO_NAME_MAX_LEN - 2 * IASIZE)/IASIZE)
154 
155 #define ROUND(V, A) \
156   ({ typeof(V) __v=(V); typeof(A) __a=(A); \
157 	 __a*((__v+__a-1)/__a); })
158 
159 typedef	unsigned char	*uptr;
160 #ifndef __MINGW__
161 static int	is_daemon = 0;		/* Currently running as daemon.	 */
162 #endif
163 static int	in_config = 0;		/* Reading config file.	 */
164 static int	debug = 0;		/* Extra debug gdomap_logging.	 */
165 static int	nobcst = 0;		/* turn off broadcast probing.	 */
166 static int	nofork = 0;		/* turn off fork() for debugging. */
167 static int	noprobe = 0;		/* disable probe for unknown servers. */
168 static int	interval = 600;		/* Minimum time (sec) between probes. */
169 static char	*pidfile = NULL;	/* file to write PID to		*/
170 
171 static int	udp_sent = 0;
172 static int	tcp_sent = 0;
173 static int	udp_read = 0;
174 static int	tcp_read = 0;
175 static int	soft_int = 0;
176 
177 static long	last_probe;
178 static struct in_addr	loopback;
179 
180 static unsigned short	my_port;	/* Set in init_iface()		*/
181 
182 static struct in_addr	class_a_mask;
183 static struct in_addr	class_b_mask;
184 static uint32_t	class_a_net;
185 static uint32_t	class_b_net;
186 static uint32_t	class_c_net;
187 struct in_addr	class_c_mask;
188 
189 static char	*local_hostname = 0;
190 
191 /*
192  *	Predeclare some of the functions used.
193  */
194 static void	dump_stats();
195 #ifndef __MINGW__
196 static void	dump_tables();
197 #endif
198 static void	handle_accept();
199 static void	handle_io();
200 static void	handle_read(int);
201 static void	handle_recv();
202 static void	handle_request(int);
203 static void	handle_send();
204 static void	handle_write(int);
205 static void	init_iface();
206 static void	load_iface(const char* from);
207 static void	init_ports();
208 static void	init_probe();
209 static void	queue_msg(struct sockaddr_in* a, uptr d, unsigned l);
210 static void	queue_pop();
211 static void	queue_probe(struct in_addr* to, struct in_addr *from,
212   int num_extras, struct in_addr* extra, int is_reply);
213 
214 char *xgethostname (void);
215 
216 #if	defined(__MINGW__)
217 #ifndef HAVE_GETOPT
218 /* A simple implementation of getopt() */
219 
220 static int
indexof(char c,char * string)221 indexof(char c, char *string)
222 {
223   int i;
224 
225   for (i = 0; i < strlen(string); i++)
226     {
227       if (string[i] == c)
228 	{
229 	  return i;
230 	}
231     }
232   return -1;
233 }
234 
235 static char *optarg;
236 
237 static char
getopt(int argc,char ** argv,char * options)238 getopt(int argc, char **argv, char *options)
239 {
240   static int	argi;
241   static char	*arg;
242   int		index;
243   char		retval = '\0';
244 
245   optarg = NULL;
246   if (argi == 0)
247     {
248       argi = 1;
249     }
250   while (argi < argc)
251     {
252       arg = argv[argi];
253       if (strlen(arg) == 2)
254 	{
255 	  if (arg[0] == '-')
256 	    {
257 	      if ((index = indexof(arg[1], options)) != -1)
258 		{
259 		  retval = arg[1];
260 		  if (index < strlen(options))
261 		    {
262 		      if (options[index+1] == ':')
263 			{
264 			  if (argi < argc-1)
265 			    {
266 			      argi++;
267 			      optarg = argv[argi];
268 			    }
269 			  else
270 			    {
271 			      return -1; /* ':' given, but argv exhausted */
272 			    }
273 			}
274 		    }
275 		}
276 	    }
277 	}
278       argi++;
279       return retval;
280     }
281   return -1;
282 }
283 #endif
284 #endif
285 
286 
287 static char	ebuf[2048];
288 
289 
290 #if	defined(HAVE_SYSLOG) || defined(HAVE_SLOGF)
291 #  if defined(HAVE_SLOGF)
292 #    define LOG_CRIT _SLOG_CRITICAL
293 #    define LOG_DEBUG _SLOG_DEBUG1
294 #    define LOG_ERR _SLOG_ERROR
295 #    define LOG_INFO _SLOG_INFO
296 #    define LOG_WARNING _SLOG_WARNING
297 #    define syslog(prio, msg,...) slogf(_SLOG_SETCODE(_SLOG_SYSLOG, 0), prio, msg, __VA_ARGS__)
298 #  endif
299 
300 static int	log_priority = 0;
301 
302 static void
gdomap_log(int prio)303 gdomap_log (int prio)
304 {
305   if (in_config)
306     {
307 #ifndef __MINGW__
308       if (geteuid () != getuid ())
309         {
310 	  strcpy(ebuf, "problem with config file");
311 	}
312 #endif
313     }
314   if (is_daemon)
315     {
316 #if   defined(HAVE_SLOGF)
317       // QNX doesn't like 0 as the prio. It means "shutdown" to them.
318       syslog (prio ? log_priority : prio, "%s", ebuf);
319 #     else
320       syslog (log_priority | prio, "%s", ebuf);
321 #endif
322     }
323   else if (prio == LOG_INFO)
324     {
325       write (1, ebuf, strlen (ebuf));
326       write (1, "\n", 1);
327     }
328   else
329     {
330       write (2, ebuf, strlen (ebuf));
331       write (2, "\n", 1);
332     }
333 
334   if (prio == LOG_CRIT)
335     {
336       if (is_daemon)
337 	{
338 	  syslog (LOG_CRIT, "%s", "exiting.");
339 	}
340       else
341      	{
342 	  fprintf (stderr, "exiting.\n");
343 	  fflush (stderr);
344 	}
345       exit(EXIT_FAILURE);
346     }
347 }
348 #else
349 
350 #define	LOG_CRIT	2
351 #define LOG_DEBUG	0
352 #define LOG_ERR		1
353 #define LOG_INFO	0
354 #define LOG_WARNING	0
355 void
gdomap_log(int prio)356 gdomap_log (int prio)
357 {
358   if (in_config)
359     {
360 #ifndef __MINGW__
361       if (geteuid () != getuid ())
362         {
363 	  strcpy(ebuf, "problem with config file");
364 	}
365 #endif
366     }
367   write (2, ebuf, strlen (ebuf));
368   write (2, "\n", 1);
369   if (prio == LOG_CRIT)
370     {
371       fprintf (stderr, "exiting.\n");
372       fflush (stderr);
373       exit(EXIT_FAILURE);
374     }
375 }
376 #endif
377 
378 /*
379  *	Structure for linked list of addresses to probe rather than
380  *	probing entire network.
381  */
382 typedef struct plstruct {
383   struct plstruct	*next;
384   int			direct;
385   struct in_addr	addr;
386 } plentry;
387 
388 static plentry	*plist = 0;
389 
390 /*
391  *	Variables used for determining if a connection is from a process
392  *	on the local host.
393  */
394 static int interfaces = 0;		/* Number of interfaces.	*/
395 static struct in_addr	*addr;		/* Address of each interface.	*/
396 static unsigned char	*bcok;		/* Broadcast OK for interface?	*/
397 static struct in_addr	*bcst;		/* Broadcast for interface.	*/
398 static struct in_addr	*mask;		/* Netmask of each interface.	*/
399 
400 static int
is_local_host(struct in_addr a)401 is_local_host(struct in_addr a)
402 {
403   int	i;
404 
405   for (i = 0; i < interfaces; i++)
406     {
407       if (a.s_addr == addr[i].s_addr)
408 	{
409 	  return 1;
410 	}
411     }
412   return 0;
413 }
414 
415 static int
is_probe_host(struct in_addr a)416 is_probe_host(struct in_addr a)
417 {
418   if (plist)
419     {
420       plentry	*p;
421 
422       /* Hosts explicitly configured to be probed are ones we treat
423        * as being part of our LAN and therefore trusted.
424        */
425       for (p = plist; p != 0; p = p->next)
426 	{
427 	  if (a.s_addr == p->addr.s_addr)
428 	    {
429 	      return 1;
430 	    }
431 	}
432     }
433   return 0;
434 }
435 
436 static int
is_local_net(struct in_addr a)437 is_local_net(struct in_addr a)
438 {
439   int	i;
440 
441   for (i = 0; i < interfaces; i++)
442     {
443       if ((mask[i].s_addr & addr[i].s_addr) == (mask[i].s_addr & a.s_addr))
444 	{
445 	  return 1;
446 	}
447     }
448   return 0;
449 }
450 
451 /*
452  *	Variables used for handling non-blocking I/O on channels.
453  */
454 static int	tcp_desc = -1;	/* Socket for incoming TCP connections.	*/
455 static int	udp_desc = -1;	/* Socket for UDP communications.	*/
456 static fd_set	read_fds;	/* Descriptors which are readable.	*/
457 static fd_set	write_fds;	/* Descriptors which are writable.	*/
458 
459 
460 /* Internal info structures. Rewritten Wed Jul 12 14:51:19  2000 by
461    Bjoern Giesler <Bjoern.Giesler@gmx.de> to work on Win32. */
462 
463 typedef struct {
464 #if	defined(__MINGW__)
465   SOCKET s;
466 #else
467   int s;
468 #endif /* __MINGW__ */
469   struct sockaddr_in	addr;	/* Address of process making request.	*/
470   socklen_t		pos;	/* Position reading data.		*/
471   union {
472     gdo_req		r;
473     unsigned char	b[GDO_REQ_SIZE];
474   } buf;
475 } RInfo;		/* State of reading each request.	*/
476 
477 typedef struct {
478 #if	defined(__MINGW__)
479   SOCKET s;
480 #else
481   int s;
482 #endif /* __MINGW__ */
483   int	len;		/* Length of data to be written.	*/
484   int	pos;		/* Amount of data already written.	*/
485   char*	buf;		/* Buffer for data.			*/
486 } WInfo;
487 
488 static RInfo *_rInfo = NULL;
489 static unsigned _rInfoCapacity = 0;
490 static unsigned _rInfoCount = 0;
491 static WInfo *_wInfo = NULL;
492 static unsigned _wInfoCapacity = 0;
493 static unsigned _wInfoCount = 0;
494 
495 static void
496 #if	defined(__MINGW__)
delRInfo(SOCKET s)497 delRInfo(SOCKET s)
498 #else
499 delRInfo(int s)
500 #endif /* __MINGW__ */
501 {
502   unsigned int	i;
503 
504   for (i = 0; i < _rInfoCount; i++)
505     {
506       if (_rInfo[i].s == s)
507 	{
508 	  break;
509 	}
510     }
511   if (i == _rInfoCount)
512     {
513       snprintf(ebuf, sizeof(ebuf),
514 	"%s requested unallocated RInfo struct (socket %d)",
515 	__FUNCTION__, s);
516       gdomap_log(LOG_ERR);
517       return;
518     }
519   _rInfoCount--;
520   if (i != _rInfoCount) /* not last element */
521     {
522       memmove(&(_rInfo[i]), &(_rInfo[i+1]), (_rInfoCount-i)*sizeof(RInfo));
523     }
524 }
525 
526 
527 static RInfo *
528 #if	defined(__MINGW__)
getRInfo(SOCKET s,int make)529 getRInfo(SOCKET s, int make)
530 #else
531 getRInfo(int s, int make)
532 #endif
533 {
534   unsigned int	i;
535 
536   for (i = 0; i < _rInfoCount; i++)
537     {
538       if (_rInfo[i].s == s)
539 	{
540 	  break;
541 	}
542     }
543   if (i == _rInfoCount)
544     {
545       if (make)
546 	{
547 	  if (_rInfoCount >= _rInfoCapacity)
548 	    {
549 	      RInfo	*tmp;
550 
551 	      _rInfoCapacity = _rInfoCount + 1;
552 	      tmp = (RInfo *)calloc(_rInfoCapacity, sizeof(RInfo));
553 	      if (_rInfoCount > 0)
554 		{
555 		  memcpy(tmp, _rInfo, sizeof(RInfo)*_rInfoCount);
556 		  free(_rInfo);
557 		}
558 	      _rInfo = tmp;
559 	    }
560 	  _rInfoCount++;
561 	  _rInfo[_rInfoCount-1].s = s;
562 	  return &(_rInfo[_rInfoCount-1]);
563 	}
564       return NULL;
565     }
566   return &(_rInfo[i]);
567 }
568 
569 static void
570 #if	defined(__MINGW__)
delWInfo(SOCKET s)571 delWInfo(SOCKET s)
572 #else
573 delWInfo(int s)
574 #endif /* __MINGW__ */
575 {
576   unsigned int	i;
577 
578   for (i = 0; i < _wInfoCount; i++)
579     {
580       if (_wInfo[i].s == s)
581 	{
582 	  break;
583 	}
584     }
585   if (i == _wInfoCount)
586     {
587       snprintf(ebuf, sizeof(ebuf),
588 	"%s requested unallocated WInfo struct (socket %d)",
589 	__FUNCTION__, s);
590       gdomap_log(LOG_ERR);
591       return;
592     }
593   _wInfoCount--;
594   if (i != _wInfoCount) /* not last element */
595     {
596       memmove(&(_wInfo[i]), &(_wInfo[i+1]), (_wInfoCount-i)*sizeof(WInfo));
597     }
598 }
599 
600 
601 static WInfo *
602 #if	defined(__MINGW__)
getWInfo(SOCKET s,int make)603 getWInfo(SOCKET s, int make)
604 #else
605 getWInfo(int s, int make)
606 #endif
607 {
608   unsigned int	i;
609 
610   for (i = 0; i < _wInfoCount; i++)
611     {
612       if (_wInfo[i].s == s)
613 	{
614 	  break;
615 	}
616     }
617   if (i == _wInfoCount)
618     {
619       if (make)
620 	{
621 	  if (_wInfoCount >= _wInfoCapacity)
622 	    {
623 	      WInfo	*tmp;
624 
625 	      _wInfoCapacity = _wInfoCount + 1;
626 	      tmp = (WInfo *)calloc(_wInfoCapacity, sizeof(WInfo));
627 	      if (_wInfoCount > 0)
628 		{
629 		  memcpy(tmp, _wInfo, sizeof(WInfo)*_wInfoCount);
630 		  free(_wInfo);
631 		}
632 	      _wInfo = tmp;
633 	    }
634 	  _wInfoCount++;
635 	  _wInfo[_wInfoCount-1].s = s;
636 	  return &(_wInfo[_wInfoCount-1]);
637 	}
638       return NULL;
639     }
640   return &(_wInfo[i]);
641 }
642 
643 
644 static struct	u_data	{
645   struct sockaddr_in	addr;	/* Address to send to.			*/
646   int			pos;	/* Number of bytes already sent.	*/
647   int	 		len;	/* Length of data to send.		*/
648   uptr			dat;	/* Data to be sent.			*/
649   struct u_data		*next;	/* Next message to send.		*/
650 } *u_queue = 0;
651 static int	udp_pending = 0;
652 
653 /*
654  *	Name -		queue_msg()
655  *	Purpose -	Add a message to the queue of those to be sent
656  *			on the UDP socket.
657  */
658 static void
queue_msg(struct sockaddr_in * a,uptr d,unsigned l)659 queue_msg(struct sockaddr_in* a, uptr d, unsigned l)
660 {
661   struct u_data*	entry = (struct u_data*)malloc(sizeof(struct u_data));
662 
663   memcpy(&entry->addr, a, sizeof(*a));
664   entry->pos = 0;
665   entry->len = l;
666   entry->dat = malloc(l);
667   memcpy(entry->dat, d, l);
668   entry->next = 0;
669   if (u_queue)
670     {
671       struct u_data*	tmp = u_queue;
672 
673       while (tmp->next)
674 	{
675 	  tmp = tmp->next;
676 	}
677       tmp->next = entry;
678     }
679   else
680     {
681       u_queue = entry;
682     }
683   udp_pending++;
684 }
685 
686 static void
queue_pop()687 queue_pop()
688 {
689   struct u_data*	tmp = u_queue;
690 
691   if (tmp)
692     {
693       u_queue = tmp->next;
694       free(tmp->dat);
695       free(tmp);
696       udp_pending--;
697     }
698 }
699 
700 /*
701  *	Primitive mapping stuff.
702  */
703 typedef struct {
704   uptr			name;	/* Service name registered.	*/
705   unsigned int		port;	/* Port it was mapped to.	*/
706   unsigned short	size;	/* Number of bytes in name.	*/
707   unsigned char		net;	/* Type of port registered.	*/
708   unsigned char		svc;	/* Type of port registered.	*/
709 } map_ent;
710 
711 static int	map_used = 0;
712 static int	map_size = 0;
713 static map_ent	**map = 0;
714 
715 static int
compare(uptr n0,int l0,uptr n1,int l1)716 compare(uptr n0, int l0, uptr n1, int l1)
717 {
718   if (l0 == l1)
719     {
720       return memcmp(n0, n1, l0);
721     }
722   else if (l0 < l1)
723     {
724       return -1;
725     }
726   return 1;
727 }
728 
729 /*
730  *	Name -		map_add()
731  *	Purpose -	Create a new map entry structure and insert it
732  *			into the map in the appropriate position.
733  */
734 static map_ent*
map_add(uptr n,unsigned char l,unsigned int p,unsigned char t)735 map_add(uptr n, unsigned char l, unsigned int p, unsigned char t)
736 {
737   map_ent	*m;
738   int		i;
739 
740   m = (map_ent*)malloc(sizeof(map_ent));
741   if (0 == m)
742     {
743       perror("no memory for map entry");
744       exit(EXIT_FAILURE);
745     }
746   m->port = p;
747   m->name = (unsigned char*)malloc(l);
748   if (0 == m->name)
749     {
750       perror("no memory for map entry name");
751       exit(EXIT_FAILURE);
752     }
753   m->size = l;
754   m->net = (t & GDO_NET_MASK);
755   m->svc = (t & GDO_SVC_MASK);
756   memcpy(m->name, n, l);
757 
758   if (map_used == map_size)
759     {
760       map_size += 16;
761       if (map)
762 	{
763 	  map = (map_ent**)realloc(map, map_size * sizeof(map_ent*));
764 	}
765       else
766 	{
767 	  map = (map_ent**)calloc(map_size, sizeof(map_ent*));
768 	}
769       if (0 == map)
770         {
771           perror("no memory for map");
772           exit(EXIT_FAILURE);
773         }
774     }
775   for (i = 0; i < map_used; i++)
776     {
777       if (compare(map[i]->name, map[i]->size, m->name, m->size) > 0)
778 	{
779 	  int	j;
780 
781 	  for (j = map_used; j > i; j--)
782 	    {
783 	      map[j] = map[j-1];
784 	    }
785 	  break;
786 	}
787     }
788   map[i] = m;
789   map_used++;
790   if (debug > 2)
791     {
792       snprintf(ebuf, sizeof(ebuf), "Added port %d to map for %.*s",
793 	m->port, m->size, m->name);
794       gdomap_log(LOG_DEBUG);
795     }
796   return m;
797 }
798 
799 /*
800  *	Name -		map_by_name()
801  *	Purpose -	Search the map for an entry for a particular name
802  */
803 static map_ent*
map_by_name(uptr n,int s)804 map_by_name(uptr n, int s)
805 {
806   int		lower = 0;
807   int		upper = map_used;
808   int		index;
809 
810   if (debug > 2)
811     {
812       snprintf(ebuf, sizeof(ebuf), "Searching map for %.*s", s, n);
813       gdomap_log(LOG_DEBUG);
814     }
815   for (index = upper/2; upper != lower; index = lower + (upper - lower)/2)
816     {
817       int	i = compare(map[index]->name, map[index]->size, n, s);
818 
819       if (i < 0)
820 	{
821 	  lower = index + 1;
822         }
823       else if (i > 0)
824 	{
825 	  upper = index;
826         }
827       else
828 	{
829 	  break;
830         }
831     }
832   if (index<map_used && compare(map[index]->name,map[index]->size,n,s) == 0)
833     {
834       if (debug > 2)
835 	{
836 	  snprintf(ebuf, sizeof(ebuf),
837 	    "Found port %d for %.*s", map[index]->port, s, n);
838 	  gdomap_log(LOG_DEBUG);
839 	}
840       return map[index];
841     }
842   if (debug > 2)
843     {
844       snprintf(ebuf, sizeof(ebuf), "Failed to find map entry for %.*s", s, n);
845       gdomap_log(LOG_DEBUG);
846     }
847   return 0;
848 }
849 
850 /*
851  *	Name -		map_by_port()
852  *	Purpose -	Search the map for an entry for a particular port
853  */
854 static map_ent*
map_by_port(unsigned p,unsigned char t)855 map_by_port(unsigned p, unsigned char t)
856 {
857   int	index;
858 
859   if (debug > 2)
860     {
861       snprintf(ebuf, sizeof(ebuf), "Searching map for %u:%x", p, t);
862       gdomap_log(LOG_DEBUG);
863     }
864   for (index = 0; index < map_used; index++)
865     {
866       map_ent	*e = map[index];
867 
868       if (e->port == p && (e->net | e->svc) == t)
869 	{
870 	  break;
871 	}
872     }
873   if (index < map_used)
874     {
875       if (debug > 2)
876 	{
877 	  snprintf(ebuf, sizeof(ebuf), "Found port %d with name %s",
878 		map[index]->port, map[index]->name);
879 	  gdomap_log(LOG_DEBUG);
880 	}
881       return map[index];
882     }
883   if (debug > 2)
884     {
885       snprintf(ebuf, sizeof(ebuf), "Failed to find map entry for %u:%x", p, t);
886       gdomap_log(LOG_DEBUG);
887     }
888   return 0;
889 }
890 
891 /*
892  *	Name -		map_del()
893  *	Purpose -	Remove a mapping entry from the map and release
894  *			the memory it uses.
895  */
896 static void
map_del(map_ent * e)897 map_del(map_ent* e)
898 {
899   int	i;
900 
901   if (debug > 2)
902     {
903       snprintf(ebuf, sizeof(ebuf), "Removing port %d from map for %.*s",
904 	e->port, e->size, e->name);
905       gdomap_log(LOG_DEBUG);
906     }
907   for (i = 0; i < map_used; i++)
908     {
909       if (map[i] == e)
910 	{
911 	  int	j;
912 
913 	  free(e->name);
914 	  free(e);
915 	  for (j = i + 1; j < map_used; j++)
916 	    {
917 	      map[j-1] = map[j];
918 	    }
919 	  map_used--;
920 	  return;
921 	}
922     }
923 }
924 
925 /*
926  *	Variables and functions for keeping track of the IP addresses of
927  *	hosts which are running the name server.
928  */
929 static uint32_t	prb_used = 0;
930 static uint32_t	prb_size = 0;
931 typedef struct	{
932   struct in_addr	sin;
933   time_t		when;
934 } prb_type;
935 static prb_type	**prb = 0;
936 
937 /*
938  *	Name -		prb_add()
939  *	Purpose -	Create a new probe entry in the list.
940  *			The new entry is always placed at the end of the list
941  *			so that the list remains in the order in which hosts
942  *			have been contancted.
943  */
944 static void
prb_add(struct in_addr * p)945 prb_add(struct in_addr *p)
946 {
947   prb_type	*n = 0;
948   unsigned int	i;
949 
950   if (is_local_host(*p) != 0)
951     {
952       return;
953     }
954   if (is_local_net(*p) == 0 && is_probe_host(*p) == 0)
955     {
956       return;
957     }
958 
959   /*
960    * If we already have an entry for this address, remove it from the list
961    * ready for re-insertion in the correct place.
962    */
963   i = prb_used;
964   while (i-- > 0)
965     {
966       if (memcmp(&prb[i]->sin, p, IASIZE) == 0)
967 	{
968 	  n = prb[i];
969 	  prb_used--;
970 	  while (i++ < prb_used)
971 	    {
972 	      prb[i-1] = prb[i];
973 	    }
974 	  break;
975 	}
976     }
977 
978   /*
979    * Create a new entry structure if necessary.
980    * Set the current time in the structure, so we know when we last had contact.
981    */
982   if (0 == n)
983     {
984       n = (prb_type*)calloc(sizeof(prb_type), 1);
985       n->sin = *p;
986     }
987   n->when = time(0);
988 
989   /*
990    * Grow the list if we need more space.
991    */
992   if (prb_used >= prb_size)
993     {
994       prb_size = prb_used + 16;
995       if (prb)
996 	{
997 	  prb = (prb_type**)realloc(prb, prb_size * sizeof(prb_type*));
998 	}
999       else
1000 	{
1001 	  prb = (prb_type**)calloc(prb_size * sizeof(prb_type*), 1);
1002 	}
1003     }
1004 
1005   /*
1006    * Append the new item at the end of the list.
1007    */
1008   prb[prb_used++] = n;
1009 }
1010 
1011 
1012 /*
1013  *	Name -		prb_del()
1014  *	Purpose -	Remove an entry from the list.
1015  */
1016 static void
prb_del(struct in_addr * p)1017 prb_del(struct in_addr *p)
1018 {
1019   unsigned int	i = prb_used;
1020 
1021   while (i-- > 0)
1022     {
1023       if (memcmp(&prb[i]->sin, p, IASIZE) == 0)
1024 	{
1025 	  free(prb[i]);
1026 	  prb_used--;
1027 	  while (i++ < prb_used)
1028 	    {
1029 	      prb[i - 1] = prb[i];
1030 	    }
1031 	  return;
1032 	}
1033     }
1034 }
1035 
1036 /*
1037  *	Remove any server from which we have had no messages in the last
1038  *	thirty minutes (as long as we have sent as probe in that time).
1039  */
1040 static void
prb_tim(time_t when)1041 prb_tim(time_t when)
1042 {
1043   int	i = prb_used;
1044 
1045   when -= 1800;
1046   while (i-- > 0)
1047     {
1048       if (noprobe == 0 && prb[i]->when < when && prb[i]->when < last_probe)
1049 	{
1050 	  prb_del(&prb[i]->sin);
1051 	}
1052     }
1053 }
1054 
1055 /*
1056  *	Name -		clear_chan()
1057  *	Purpose -	Release all resources associated with a channel
1058  *			and remove it from the list of requests being
1059  *			serviced.
1060  */
1061 static void
clear_chan(int desc)1062 clear_chan(int desc)
1063 {
1064 #if	defined(__MINGW__)
1065   if (desc != INVALID_SOCKET)
1066 #else
1067   if (desc >= 0 && desc < FD_SETSIZE)
1068 #endif
1069     {
1070       WInfo	*wi;
1071 
1072       FD_CLR(desc, &write_fds);
1073       if (desc == tcp_desc || desc == udp_desc)
1074 	{
1075 	  FD_SET(desc, &read_fds);
1076 	}
1077       else
1078 	{
1079 	  FD_CLR(desc, &read_fds);
1080 #if	defined(__MINGW__)
1081 	  closesocket(desc);
1082 #else
1083 	  close(desc);
1084 #endif
1085 	}
1086       if ((wi = getWInfo(desc, 0)) != 0)
1087 	{
1088 	  if (wi->buf)
1089 	    {
1090 	      free(wi->buf);
1091 	      wi->buf = 0;
1092 	    }
1093 	  wi->len = 0;
1094 	  wi->pos = 0;
1095 	}
1096       if (!(desc == tcp_desc || desc == udp_desc))
1097 	{
1098 	  if (wi != 0)
1099 	    {
1100 	      delWInfo(desc);
1101 	    }
1102 	  delRInfo(desc);
1103 	}
1104     }
1105 }
1106 
1107 static void
dump_stats()1108 dump_stats()
1109 {
1110   int	tcp_pending = 0;
1111   unsigned int	i;
1112 
1113   for (i = 0; i < _wInfoCount; i++)
1114     {
1115       if (_wInfo[i].len > 0)
1116 	{
1117 	  tcp_pending++;
1118 	}
1119     }
1120   snprintf(ebuf, sizeof(ebuf),
1121     "tcp messages waiting for send - %d", tcp_pending);
1122   gdomap_log(LOG_INFO);
1123   snprintf(ebuf, sizeof(ebuf),
1124     "udp messages waiting for send - %d", udp_pending);
1125   gdomap_log(LOG_INFO);
1126   snprintf(ebuf, sizeof(ebuf), "size of name-to-port map - %d", map_used);
1127   gdomap_log(LOG_INFO);
1128   snprintf(ebuf, sizeof(ebuf), "number of known name servers - %"PRIu32,
1129     prb_used);
1130   gdomap_log(LOG_INFO);
1131   snprintf(ebuf, sizeof(ebuf), "TCP %d read, %d sent", tcp_read, tcp_sent);
1132   gdomap_log(LOG_INFO);
1133   snprintf(ebuf, sizeof(ebuf), "UDP %d read, %d sent", udp_read, udp_sent);
1134   gdomap_log(LOG_INFO);
1135 }
1136 
1137 #ifndef __MINGW__
1138 static void
dump_tables()1139 dump_tables()
1140 {
1141   FILE	*fptr;
1142 
1143   soft_int++;
1144   if (access(".", W_OK) != 0)
1145     {
1146       snprintf(ebuf, sizeof(ebuf),
1147 	"Failed to access gdomap.dump file for output\n");
1148       gdomap_log(LOG_ERR);
1149       return;
1150     }
1151   fptr = fopen("gdomap.dump", "w");
1152   if (fptr != 0)
1153     {
1154       fprintf(fptr, "\n");
1155       fprintf(fptr, "Known nameserver addresses\n");
1156       fprintf(fptr, "==========================\n");
1157       if (prb_used == 0)
1158 	{
1159 	  fprintf(fptr, "None.\n");
1160 	}
1161       else
1162 	{
1163 	  unsigned int	i;
1164 
1165 	  for (i = 0; i < prb_used; i++)
1166 	    {
1167 	      fprintf(fptr, "%16s %s\n",
1168 		inet_ntoa(prb[i]->sin), (const char*)ctime(&prb[i]->when));
1169 	    }
1170 	}
1171 
1172       fprintf(fptr, "\n");
1173       fclose(fptr);
1174     }
1175   else
1176     {
1177       snprintf(ebuf, sizeof(ebuf),
1178 	"Failed to open gdomap.dump file for output\n");
1179       gdomap_log(LOG_ERR);
1180     }
1181 }
1182 #endif
1183 
1184 /*
1185  *	Name -		init_iface()
1186  *	Purpose -	Build up an array of the IP addresses supported on
1187  *			the network interfaces of this machine.
1188  */
1189 static void
init_iface()1190 init_iface()
1191 {
1192 #if	defined(__MINGW__)
1193   INTERFACE_INFO InterfaceList[20];
1194   uint32_t nBytesReturned;
1195   int i, countActive, nNumInterfaces;
1196   SOCKET desc = WSASocket(PF_INET, SOCK_RAW, AF_INET, 0, 0, 0);
1197 
1198   if (desc == INVALID_SOCKET)
1199     {
1200       snprintf(ebuf, sizeof(ebuf),
1201 	"Failed to get a socket. Error %d\n", WSAGetLastError());
1202       gdomap_log(LOG_CRIT);
1203       exit(EXIT_FAILURE);
1204     }
1205 
1206   memset((void*)InterfaceList, '\0', sizeof(InterfaceList));
1207   if (WSAIoctl(desc, SIO_GET_INTERFACE_LIST, 0, 0, (void*)InterfaceList,
1208     sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR)
1209     {
1210       snprintf(ebuf, sizeof(ebuf),
1211 	"Failed WSAIoctl. Error %d\n", WSAGetLastError());
1212       gdomap_log(LOG_CRIT);
1213       exit(EXIT_FAILURE);
1214     }
1215 
1216   nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
1217 
1218   /*
1219    * See how many active entries there are.
1220    */
1221   countActive = 0;
1222   for (i = 0; i < nNumInterfaces; i++)
1223     {
1224       u_long	nFlags = InterfaceList[i].iiFlags;
1225 
1226       if ((nFlags & IFF_UP)
1227 	&& (InterfaceList[i].iiAddress.Address.sa_family == AF_INET))
1228 	{
1229 	  countActive++;
1230 	}
1231     }
1232 
1233   /*
1234    * Allocate enough space for all interfaces.
1235    */
1236   if (addr != 0) free(addr);
1237   addr = (struct in_addr*)malloc((countActive+1)*IASIZE);
1238   if (bcok != 0) free(bcok);
1239   bcok = (unsigned char*)malloc((countActive+1)*sizeof(unsigned char));
1240   if (bcst != 0) free(bcst);
1241   bcst = (struct in_addr*)malloc((countActive+1)*IASIZE);
1242   if (mask != 0) free(mask);
1243   mask = (struct in_addr*)malloc((countActive+1)*IASIZE);
1244 
1245   for (i = 0; i < nNumInterfaces; i++)
1246     {
1247       u_long	nFlags = InterfaceList[i].iiFlags;
1248 
1249       if ((nFlags & IFF_UP)
1250 	&& (InterfaceList[i].iiAddress.Address.sa_family == AF_INET))
1251 	{
1252 	  int	broadcast = 0;
1253 	  int	pointopoint = 0;
1254 	  int	loopback = 0;
1255 
1256 	  if (nFlags & IFF_BROADCAST)
1257 	    {
1258 	      broadcast = 1;
1259 	    }
1260 	  if (nFlags & IFF_POINTTOPOINT)
1261 	    {
1262 	      pointopoint = 1;
1263 	    }
1264 	  if (nFlags & IFF_LOOPBACK)
1265 	    {
1266 	      loopback = 1;
1267 	    }
1268 	  addr[interfaces] = ((struct sockaddr_in*)
1269 	    &(InterfaceList[i].iiAddress))->sin_addr;
1270 	  mask[interfaces] = ((struct sockaddr_in*)
1271 	    &(InterfaceList[i].iiNetmask))->sin_addr;
1272 	  bcst[interfaces] = ((struct sockaddr_in*)
1273 	    &(InterfaceList[i].iiBroadcastAddress))->sin_addr;
1274 	  bcok[interfaces] = (broadcast | pointopoint);
1275 
1276 	  if (addr[interfaces].s_addr == 0)
1277 	    {
1278 	      addr[interfaces].s_addr = htonl(0x8f000001);
1279 	      fprintf(stderr, "Bad iface addr (0.0.0.0) guess (%s)\n",
1280 		inet_ntoa(addr[interfaces]));
1281 	    }
1282 	  if (mask[interfaces].s_addr == 0)
1283 	    {
1284 	      mask[interfaces].s_addr = htonl(0xffffff00);
1285 	      fprintf(stderr, "Bad iface mask (0.0.0.0) guess (%s)\n",
1286 		inet_ntoa(mask[interfaces]));
1287 	    }
1288 	  if (bcst[interfaces].s_addr == 0)
1289 	    {
1290 	      u_long	l = ntohl(addr[interfaces].s_addr);
1291 	      bcst[interfaces].s_addr = htonl(l | 0xff);
1292 	      fprintf(stderr, "Bad iface bcst (0.0.0.0) guess (%s)\n",
1293 		inet_ntoa(bcst[interfaces]));
1294 	    }
1295 	  interfaces++;
1296 	}
1297     }
1298   closesocket(desc);
1299 #else
1300 #if	defined(SIOCGIFCONF)
1301   struct ifconf	ifc;
1302   struct ifreq	ifreq;
1303   void		*final;
1304   void		*ifr_ptr;
1305   char		buf[MAX_IFACE * sizeof(struct ifreq)];
1306   int		desc;
1307 
1308   if ((desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1309     {
1310       perror("socket for init_iface");
1311       exit(EXIT_FAILURE);
1312     }
1313 // QNX seems to disagree about what it means to be SysV r4.
1314 #if	defined(__svr4__) && !defined(__QNXNTO__)
1315     {
1316       struct strioctl	ioc;
1317 
1318       ioc.ic_cmd = SIOCGIFCONF;
1319       ioc.ic_timout = 0;
1320       ioc.ic_len = sizeof(buf);
1321       ioc.ic_dp = buf;
1322       if (ioctl(desc, I_STR, (char*)&ioc) < 0)
1323 	{
1324 	  ioc.ic_len = 0;
1325 	}
1326       ifc.ifc_len = ioc.ic_len;
1327       ifc.ifc_buf = ioc.ic_dp;
1328     }
1329 #else
1330   ifc.ifc_len = sizeof(buf);
1331   ifc.ifc_buf = buf;
1332   if (ioctl(desc, SIOCGIFCONF, (char*)&ifc) < 0)
1333     {
1334       ifc.ifc_len = 0;
1335     }
1336 #endif
1337 
1338   /*
1339    *	Find the IP address of each active network interface.
1340    */
1341   if (ifc.ifc_len == 0)
1342     {
1343       int	res = errno;
1344 
1345       snprintf(ebuf, sizeof(ebuf),
1346 	"SIOCGIFCONF for init_iface found no active interfaces; %s", lastErr());
1347       gdomap_log(LOG_ERR);
1348 
1349       if (res == EINVAL)
1350 	{
1351 	  snprintf(ebuf, sizeof(ebuf),
1352 "Either you have too many network interfaces on your machine (in which case\n"
1353 "you need to change the 'MAX_IFACE' constant in gdomap.c and rebuild it), or\n"
1354 "your system is buggy, and you need to use the '-a' command line flag for\n"
1355 "gdomap to manually set the interface addresses and masks to be used.\n"
1356 "Try 'gdomap -C' for more information.\n");
1357 	  gdomap_log(LOG_INFO);
1358 	}
1359       close(desc);
1360       exit(EXIT_FAILURE);
1361     }
1362   /*
1363    * We cannot know the number of interfaces in advance, thus we
1364    * need to malloc to MAX_IFACE toensure sufficient space
1365    */
1366   if (addr != 0) free(addr);
1367   addr = (struct in_addr*)malloc((MAX_IFACE+1)*IASIZE);
1368   if (bcok != 0) free(bcok);
1369   bcok = (unsigned char*)malloc((MAX_IFACE+1)*sizeof(unsigned char));
1370   if (bcst != 0) free(bcst);
1371   bcst = (struct in_addr*)malloc((MAX_IFACE+1)*IASIZE);
1372   if (mask != 0) free(mask);
1373   mask = (struct in_addr*)malloc((MAX_IFACE+1)*IASIZE);
1374 
1375   final = &ifc.ifc_buf[ifc.ifc_len];
1376   for (ifr_ptr = ifc.ifc_req; ifr_ptr < final;)
1377     {
1378       ifreq = *(struct ifreq*)ifr_ptr;
1379 #if	defined(HAVE_SA_LEN)
1380       ifr_ptr += sizeof(ifreq) - sizeof(ifreq.ifr_addr)
1381 	+ ROUND(ifreq.ifr_addr.sa_len, sizeof(struct ifreq*));
1382 #else
1383       ifr_ptr += sizeof(ifreq);
1384 #endif
1385 
1386       if (ioctl(desc, SIOCGIFFLAGS, (char *)&ifreq) < 0)
1387         {
1388           snprintf(ebuf, sizeof(ebuf), "SIOCGIFFLAGS: %s", lastErr());
1389           gdomap_log(LOG_ERR);
1390         }
1391       else if (ifreq.ifr_flags & IFF_UP)
1392         {  /* interface is up */
1393 	  int	broadcast = 0;
1394 	  int	pointopoint = 0;
1395 	  int	loopback = 0;
1396 
1397 	  if (ifreq.ifr_flags & IFF_BROADCAST)
1398 	    {
1399 	      broadcast = 1;
1400 	    }
1401 #if	defined(IFF_POINTOPOINT)
1402 	  if (ifreq.ifr_flags & IFF_POINTOPOINT)
1403 	    {
1404 	      pointopoint = 1;
1405 	    }
1406 #endif
1407 #if	defined(IFF_LOOPBACK)
1408 	  if (ifreq.ifr_flags & IFF_LOOPBACK)
1409 	    {
1410 	      loopback = 1;
1411 	    }
1412 #endif
1413           if (ioctl(desc, SIOCGIFADDR, (char *)&ifreq) < 0)
1414             {
1415               snprintf(ebuf, sizeof(ebuf), "SIOCGIFADDR: %s", lastErr());
1416               gdomap_log(LOG_ERR);
1417             }
1418           else if (ifreq.ifr_addr.sa_family == AF_INET)
1419             {	/* IP interface */
1420 	      if (interfaces >= MAX_IFACE)
1421 	        {
1422 	          snprintf(ebuf, sizeof(ebuf),
1423 "You have too many network interfaces on your machine (in which case you need\n"
1424 "to change the 'MAX_IFACE' constant in gdomap.c and rebuild it), or your\n"
1425 "system is buggy, and you need to use the '-a' command line flag for\n"
1426 "gdomap to manually set the interface addresses and masks to be used.\n"
1427 "Try 'gdomap -C' for more information.\n");
1428 	          gdomap_log(LOG_INFO);
1429 		  close(desc);
1430 	          exit(EXIT_FAILURE);
1431 	        }
1432 	      addr[interfaces] =
1433 		((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
1434 	      bcok[interfaces] = (broadcast | pointopoint);
1435 #if	defined(IFF_POINTOPOINT)
1436 	      if (pointopoint)
1437 		{
1438 		  if (ioctl(desc, SIOCGIFDSTADDR, (char*)&ifreq) < 0)
1439 		    {
1440 		      snprintf(ebuf, sizeof(ebuf),
1441 			"SIOCGIFADDR: %s", lastErr());
1442 		      gdomap_log(LOG_ERR);
1443 		      bcok[interfaces] = 0;
1444 		    }
1445 		  else
1446 		    {
1447 		      bcst[interfaces]
1448 			= ((struct sockaddr_in *)&ifreq.ifr_dstaddr)->sin_addr;
1449 		    }
1450 		}
1451 	      else
1452 #endif
1453 		{
1454 		  if (!loopback
1455 		    && ioctl(desc, SIOCGIFBRDADDR, (char*)&ifreq) < 0)
1456 		    {
1457 		      snprintf(ebuf, sizeof(ebuf),
1458 			"SIOCGIFBRDADDR: %s", lastErr());
1459 		      gdomap_log(LOG_ERR);
1460 		      bcok[interfaces] = 0;
1461 		    }
1462 		  else
1463 		    {
1464 		      bcst[interfaces]
1465 			= ((struct sockaddr_in*)&ifreq.ifr_broadaddr)->sin_addr;
1466 		    }
1467 		}
1468 	      if (ioctl(desc, SIOCGIFNETMASK, (char *)&ifreq) < 0)
1469 	        {
1470 		  snprintf(ebuf, sizeof(ebuf), "SIOCGIFNETMASK: %s", lastErr());
1471 		  gdomap_log(LOG_ERR);
1472 		  /*
1473 		   *	If we can't get a netmask - assume a class-c
1474 		   *	network.
1475 		   */
1476 		   mask[interfaces] = class_c_mask;
1477 		}
1478               else
1479                 {
1480 /*
1481  *	Some systems don't have ifr_netmask
1482  */
1483 #ifdef	ifr_netmask
1484                   mask[interfaces] =
1485                     ((struct sockaddr_in *)&ifreq.ifr_netmask)->sin_addr;
1486 #else
1487                   mask[interfaces] =
1488                     ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
1489 #endif
1490                 }
1491               interfaces++;
1492 	    }
1493 	}
1494     }
1495   close(desc);
1496 #endif	/* SIOCGIFCONF */
1497 #endif	/* MINGW */
1498 
1499   if (interfaces == 0)
1500     {
1501       snprintf(ebuf, sizeof(ebuf),
1502 	"I can't find any network interfaces on this platform - "
1503 	"use the '-a' flag to load interface details from a file instead.\n"
1504 	"Try 'gdomap -C' for more information.\n");
1505       gdomap_log(LOG_CRIT);
1506       exit(EXIT_FAILURE);
1507     }
1508 }
1509 
1510 /*
1511  *	Name -		load_iface()
1512  *	Purpose -	Read addresses and netmasks for interfaces on this
1513  *			machine from a file.
1514  */
1515 static void
load_iface(const char * from)1516 load_iface(const char* from)
1517 {
1518   FILE	*fptr;
1519   char	buf[128];
1520   int	line = 0;
1521   int	num_iface = 0;
1522 
1523   in_config = 1;
1524 
1525   /* Can we open the fiel with current privs
1526    */
1527   fptr = fopen(from, "rt");
1528   if (fptr == 0)
1529     {
1530       snprintf(ebuf, sizeof(ebuf),
1531 	"Unable to open address config - '%s'", from);
1532       gdomap_log(LOG_CRIT);
1533       exit(EXIT_FAILURE);
1534     }
1535   /* Should we be opening it?
1536    */
1537   if (access(from, R_OK) != 0)
1538     {
1539       fclose(fptr);
1540       snprintf(ebuf, sizeof(ebuf),
1541 	"Unable to access address config - '%s'", from);
1542       gdomap_log(LOG_CRIT);
1543       exit(EXIT_FAILURE);
1544     }
1545 
1546   while (fgets(buf, sizeof(buf), fptr) != 0)
1547     {
1548       char	*ptr = buf;
1549 
1550       line++;
1551       /*
1552        *	Strip leading white space.
1553        */
1554       while (isspace(*ptr))
1555 	{
1556 	  ptr++;
1557 	}
1558       if (ptr != buf)
1559 	{
1560 	  strcpy(buf, ptr);
1561 	}
1562       /*
1563        *	Strip comments.
1564        */
1565       ptr = strchr(buf, '#');
1566       if (ptr)
1567 	{
1568 	  *ptr = '\0';
1569 	}
1570       /*
1571        *	Strip trailing white space.
1572        */
1573       ptr = buf;
1574       while (*ptr)
1575 	{
1576 	  ptr++;
1577 	}
1578       while (ptr > buf && isspace(ptr[-1]))
1579 	{
1580 	  ptr--;
1581 	}
1582       *ptr = '\0';
1583       /*
1584        *	Ignore blank lines.
1585        */
1586       if (*buf == '\0')
1587 	{
1588 	  continue;
1589 	}
1590       if (num_iface++ > 1000)
1591 	{
1592           snprintf(ebuf, sizeof(ebuf), "Too many network interfaces found");
1593           gdomap_log(LOG_CRIT);
1594           exit(EXIT_FAILURE);
1595 	}
1596     }
1597   fseek(fptr, 0, 0);
1598 
1599   if (num_iface == 0)
1600     {
1601       snprintf(ebuf, sizeof(ebuf), "No network interfaces found");
1602       gdomap_log(LOG_CRIT);
1603       exit(EXIT_FAILURE);
1604     }
1605   num_iface++;
1606   addr = (struct in_addr*)malloc((num_iface+1)*IASIZE);
1607   mask = (struct in_addr*)malloc((num_iface+1)*IASIZE);
1608   bcok = (unsigned char*)malloc((num_iface+1)*sizeof(unsigned char));
1609   bcst = (struct in_addr*)malloc((num_iface+1)*IASIZE);
1610 
1611   addr[interfaces].s_addr = inet_addr("127.0.0.1");
1612   mask[interfaces].s_addr = inet_addr("255.255.255.0");
1613   bcok[interfaces] = 0;
1614   bcst[interfaces].s_addr = inet_addr("127.0.0.255");
1615   interfaces++;
1616 
1617   while (fgets(buf, sizeof(buf), fptr) != 0)
1618     {
1619       char	*ptr = buf;
1620       char	*msk;
1621 
1622       line++;
1623       /*
1624        *	Strip leading white space.
1625        */
1626       while (isspace(*ptr))
1627 	{
1628 	  ptr++;
1629 	}
1630       if (ptr != buf)
1631 	{
1632 	  strcpy(buf, ptr);
1633 	}
1634       /*
1635        *	Strip comments.
1636        */
1637       ptr = strchr(buf, '#');
1638       if (ptr)
1639 	{
1640 	  *ptr = '\0';
1641 	}
1642       /*
1643        *	Strip trailing white space.
1644        */
1645       ptr = buf;
1646       while (*ptr)
1647 	{
1648 	  ptr++;
1649 	}
1650       while (ptr > buf && isspace(ptr[-1]))
1651 	{
1652 	  ptr--;
1653 	}
1654       *ptr = '\0';
1655       /*
1656        *	Ignore blank lines.
1657        */
1658       if (*buf == '\0')
1659 	{
1660 	  continue;
1661 	}
1662 
1663       ptr = buf;
1664       while (*ptr && (isdigit(*ptr) || (*ptr == '.')))
1665 	{
1666 	  ptr++;
1667 	}
1668       while (isspace(*ptr))
1669 	{
1670 	  *ptr++ = '\0';
1671 	}
1672       msk = ptr;
1673       while (*ptr && (isdigit(*ptr) || (*ptr == '.')))
1674 	{
1675 	  ptr++;
1676 	}
1677       while (isspace(*ptr))
1678 	{
1679 	  *ptr++ = '\0';
1680 	}
1681       addr[interfaces].s_addr = inet_addr(buf);
1682       mask[interfaces].s_addr = inet_addr(msk);
1683       if (isdigit(*ptr))
1684 	{
1685 	  bcok[interfaces] = 1;
1686 	  bcst[interfaces].s_addr = inet_addr(ptr);
1687 	}
1688       else
1689 	{
1690 	  bcok[interfaces] = 0;
1691 	  bcst[interfaces].s_addr = inet_addr("0.0.0.0");
1692 	}
1693       if (addr[interfaces].s_addr == (uint32_t)-1)
1694 	{
1695 	  snprintf(ebuf, sizeof(ebuf), "line %d of '%s' bad address (%s)",
1696 	    line, from, buf);
1697 	  gdomap_log(LOG_CRIT);
1698 	  exit(EXIT_FAILURE);
1699 	}
1700       else if (mask[interfaces].s_addr == (uint32_t)-1)
1701 	{
1702 	  snprintf(ebuf, sizeof(ebuf), "line %d of '%s' bad netmask (%s)",
1703 	    line, from, ptr);
1704 	  gdomap_log(LOG_CRIT);
1705 	  exit(EXIT_FAILURE);
1706 	}
1707       else
1708 	{
1709 	  interfaces++;
1710 	}
1711     }
1712   fclose(fptr);
1713   in_config = 0;
1714 }
1715 
1716 /*
1717  *	Name -		init_my_port()
1718  *	Purpose -	Establish our well-known port (my_port).
1719  */
1720 static void
init_my_port()1721 init_my_port()
1722 {
1723   /*
1724    *	First we determine the port for the 'gdomap' service - ideally
1725    *	this should be the default port, since we should have registered
1726    *	this with the appropriate authority and have it reserved for us.
1727    */
1728 #if	defined(GDOMAP_PORT_OVERRIDE)
1729   my_port = htons(GDOMAP_PORT_OVERRIDE);
1730 #else
1731   struct servent	*sp;
1732 
1733   my_port = htons(GDOMAP_PORT);
1734   if ((sp = getservbyname("gdomap", "tcp")) == 0)
1735     {
1736       if (debug)
1737 	{
1738 	  snprintf(ebuf, sizeof(ebuf), "Unable to find service 'gdomap'");
1739 	  gdomap_log(LOG_WARNING);
1740 	  snprintf(ebuf, sizeof(ebuf),
1741 	    "On a unix host it should be in /etc/services "
1742 	    "as 'gdomap %d/tcp' and 'gdomap %d/udp'\n",
1743 	    GDOMAP_PORT, GDOMAP_PORT);
1744 	  gdomap_log(LOG_INFO);
1745 	}
1746     }
1747   else
1748     {
1749       unsigned short	tcp_port = sp->s_port;
1750 
1751       if ((sp = getservbyname("gdomap", "udp")) == 0)
1752 	{
1753 	  if (debug)
1754 	    {
1755 	      snprintf(ebuf, sizeof(ebuf), "Unable to find service 'gdomap'");
1756 	      snprintf(ebuf, sizeof(ebuf),
1757 		"On a unix host it should be in /etc/services "
1758 		"as 'gdomap %d/tcp' and 'gdomap %d/udp'\n",
1759 		GDOMAP_PORT, GDOMAP_PORT);
1760 	      gdomap_log(LOG_INFO);
1761 	    }
1762 	}
1763       else if (sp->s_port != tcp_port)
1764 	{
1765 	  snprintf(ebuf, sizeof(ebuf),
1766 	    "UDP and TCP service entries differ. "
1767 	    "Using the TCP entry for both!");
1768 	  gdomap_log(LOG_WARNING);
1769 	}
1770       if (tcp_port != my_port)
1771 	{
1772 	  snprintf(ebuf, sizeof(ebuf), "gdomap not running on normal port");
1773 	  gdomap_log(LOG_WARNING);
1774 	}
1775       my_port = tcp_port;
1776     }
1777 #endif
1778 }
1779 
1780 /*
1781  *	Name -		init_ports()
1782  *	Purpose -	Set up the ports for accepting incoming requests.
1783  */
1784 static void
init_ports()1785 init_ports()
1786 {
1787   int		r;
1788   struct sockaddr_in	sa;
1789 #if	defined(__MINGW__)
1790   uint32_t dummy;
1791 #endif /* __MINGW__ */
1792 
1793   /*
1794    *	Now we set up the sockets to accept incoming connections and set
1795    *	options on it so that if this program is killed, we can restart
1796    *	immediately and not find the socket addresses hung.
1797    */
1798 
1799   udp_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1800 #if	defined(__MINGW__)
1801   if (udp_desc == INVALID_SOCKET)
1802 #else
1803   if (udp_desc < 0)
1804 #endif
1805     {
1806       snprintf(ebuf, sizeof(ebuf), "Unable to create UDP socket");
1807       gdomap_log(LOG_CRIT);
1808       exit(EXIT_FAILURE);
1809     }
1810   else if (debug)
1811     {
1812       snprintf(ebuf, sizeof(ebuf), "Opened UDP socket %d", udp_desc);
1813       gdomap_log(LOG_DEBUG);
1814     }
1815 #if	0 && defined(SO_EXCLUSIVEADDRUSE)
1816   r = 1;
1817   if ((setsockopt(udp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1818     {
1819       snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on UDP socket");
1820       gdomap_log(LOG_WARNING);
1821     }
1822   r = 1;
1823   if ((setsockopt
1824     (udp_desc,SOL_SOCKET,SO_EXCLUSIVEADDRUSE,(char*)&r,sizeof(r)))<0)
1825     {
1826       snprintf(ebuf, sizeof(ebuf),
1827 	"Unable to set 'exclusive-use' on UDP socket");
1828       gdomap_log(LOG_WARNING);
1829     }
1830 #endif
1831 #ifndef BROKEN_SO_REUSEADDR
1832   /*
1833    * Under decent systems, SO_REUSEADDR means that the port can be reused
1834    * immediately that this process exits.  Under some it means
1835    * that multiple processes can serve the same port simultaneously.
1836    * We don't want that broken behavior!
1837    */
1838   r = 1;
1839   if ((setsockopt(udp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1840     {
1841       snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on UDP socket");
1842       gdomap_log(LOG_WARNING);
1843     }
1844 #endif
1845   if (nobcst == 0)
1846     {
1847       r = 1;
1848       if ((setsockopt(udp_desc,SOL_SOCKET,SO_BROADCAST,(char*)&r,sizeof(r)))<0)
1849 	{
1850 	  nobcst++;
1851 	  snprintf(ebuf, sizeof(ebuf), "Unable to use 'broadcast' for probes");
1852 	  gdomap_log(LOG_WARNING);
1853 	}
1854     }
1855 #if	defined(__MINGW__)
1856   dummy = 1;
1857   if (ioctlsocket(udp_desc, FIONBIO, &dummy) < 0)
1858     {
1859       snprintf(ebuf, sizeof(ebuf), "Unable to handle UDP socket non-blocking");
1860       gdomap_log(LOG_CRIT);
1861       exit(EXIT_FAILURE);
1862     }
1863 #else /* !__MINGW__ */
1864   if ((r = fcntl(udp_desc, F_GETFL, 0)) >= 0)
1865     {
1866       r |= NBLK_OPT;
1867       if (fcntl(udp_desc, F_SETFL, r) < 0)
1868 	{
1869 	  snprintf(ebuf, sizeof(ebuf), "Unable to set UDP socket non-blocking");
1870 	  gdomap_log(LOG_CRIT);
1871 	  exit(EXIT_FAILURE);
1872 	}
1873     }
1874   else
1875     {
1876       snprintf(ebuf, sizeof(ebuf), "Unable to handle UDP socket non-blocking");
1877       gdomap_log(LOG_CRIT);
1878       exit(EXIT_FAILURE);
1879     }
1880 #endif
1881  /*
1882    *	Now we bind our address to the socket and prepare to accept incoming
1883    *	connections by listening on it.
1884    */
1885   memset(&sa, '\0', sizeof(sa));
1886   sa.sin_family = AF_INET;
1887   sa.sin_addr.s_addr = htonl(INADDR_ANY);
1888   sa.sin_port = my_port;
1889   if (bind(udp_desc, (void*)&sa, sizeof(sa)) < 0)
1890     {
1891       snprintf(ebuf, sizeof(ebuf),
1892 "Unable to bind address to UDP socket. Perhaps gdomap is already running");
1893       gdomap_log(LOG_ERR);
1894       if (errno == EACCES)
1895 	{
1896 	  snprintf(ebuf, sizeof(ebuf),
1897 "You probably need to run gdomap as root/system administrator (recommended),\n"
1898 "or run the nameserver on a non-standard port that does not require root\n"
1899 "privilege (poor option and last resort!!!)");
1900 	  gdomap_log(LOG_INFO);
1901 	}
1902       exit(EXIT_FAILURE);
1903     }
1904 
1905   /*
1906    *	Now we do the TCP socket.
1907    */
1908   tcp_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1909 #if	defined(__MINGW__)
1910   if (tcp_desc == INVALID_SOCKET)
1911 #else
1912   if (tcp_desc < 0)
1913 #endif
1914     {
1915       snprintf(ebuf, sizeof(ebuf), "Unable to create TCP socket");
1916       gdomap_log(LOG_CRIT);
1917       exit(EXIT_FAILURE);
1918     }
1919   else if (debug)
1920     {
1921       snprintf(ebuf, sizeof(ebuf), "Opened TDP socket %d", tcp_desc);
1922       gdomap_log(LOG_DEBUG);
1923     }
1924 #if	0 && defined(SO_EXCLUSIVEADDRUSE)
1925   r = 1;
1926   if ((setsockopt(tcp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1927     {
1928       snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on TCP socket");
1929       gdomap_log(LOG_WARNING);
1930     }
1931   r = 1;
1932   if ((setsockopt
1933     (tcp_desc,SOL_SOCKET,SO_EXCLUSIVEADDRUSE,(char*)&r,sizeof(r)))<0)
1934     {
1935       snprintf(ebuf, sizeof(ebuf),
1936 	"Unable to set 'exclusive-use' on TCP socket");
1937       gdomap_log(LOG_WARNING);
1938     }
1939 #endif
1940 #ifndef BROKEN_SO_REUSEADDR
1941   /*
1942    * Under decent systems, SO_REUSEADDR means that the port can be reused
1943    * immediately that this process exits.  Under some it means
1944    * that multiple processes can serve the same port simultaneously.
1945    * We don't want that broken behavior!
1946    */
1947   r = 1;
1948   if ((setsockopt(tcp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1949     {
1950       snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on TCP socket");
1951       gdomap_log(LOG_WARNING);
1952     }
1953 #endif
1954 
1955 #if	defined(__MINGW__)
1956   dummy = 1;
1957   if (ioctlsocket(tcp_desc, FIONBIO, &dummy) < 0)
1958     {
1959       snprintf(ebuf, sizeof(ebuf), "Unable to handle TCP socket non-blocking");
1960       gdomap_log(LOG_CRIT);
1961       exit(EXIT_FAILURE);
1962     }
1963 #else /* !__MINGW__ */
1964   if ((r = fcntl(tcp_desc, F_GETFL, 0)) >= 0)
1965     {
1966       r |= NBLK_OPT;
1967       if (fcntl(tcp_desc, F_SETFL, r) < 0)
1968 	{
1969 	  snprintf(ebuf, sizeof(ebuf), "Unable to set TCP socket non-blocking");
1970 	  gdomap_log(LOG_CRIT);
1971 	  exit(EXIT_FAILURE);
1972 	}
1973     }
1974   else
1975     {
1976       snprintf(ebuf, sizeof(ebuf), "Unable to handle TCP socket non-blocking");
1977       gdomap_log(LOG_CRIT);
1978       exit(EXIT_FAILURE);
1979     }
1980 #endif /* __MINGW__ */
1981 
1982   memset(&sa, '\0', sizeof(sa));
1983   sa.sin_family = AF_INET;
1984   sa.sin_addr.s_addr = htonl(INADDR_ANY);
1985   sa.sin_port = my_port;
1986   if (bind(tcp_desc, (void*)&sa, sizeof(sa)) < 0)
1987     {
1988       snprintf(ebuf, sizeof(ebuf),
1989 "Unable to bind address to TCP socket. Perhaps gdomap is already running");
1990       gdomap_log(LOG_ERR);
1991       if (errno == EACCES)
1992 	{
1993 	  snprintf(ebuf, sizeof(ebuf),
1994 "You probably need to run gdomap as root/system administrator (recommended),\n"
1995 "or run the nameserver on a non-standard port that does not require root\n"
1996 "privilege (poor option and last resort!!!)");
1997 	  gdomap_log(LOG_INFO);
1998 	}
1999       exit(EXIT_FAILURE);
2000     }
2001   if (listen(tcp_desc, QUEBACKLOG) < 0)
2002     {
2003       snprintf(ebuf, sizeof(ebuf),
2004 	"Unable to listen for connections on TCP socket");
2005       gdomap_log(LOG_CRIT);
2006       exit(EXIT_FAILURE);
2007     }
2008 
2009   /*
2010    *	Set up masks to say we are interested in these descriptors.
2011    */
2012   memset(&read_fds, '\0', sizeof(read_fds));
2013   memset(&write_fds, '\0', sizeof(write_fds));
2014 
2015   getRInfo(tcp_desc, 1);
2016   getRInfo(udp_desc, 1);
2017 
2018   FD_SET(tcp_desc, &read_fds);
2019   FD_SET(udp_desc, &read_fds);
2020 
2021 #ifndef __MINGW__
2022   /*
2023    *	Turn off pipe signals so we don't get interrupted if we attempt
2024    *	to write a response to a process which has died.
2025    */
2026   signal(SIGPIPE, SIG_IGN);
2027   /*
2028    *	Enable table dumping to /tmp/gdomap.dump
2029    */
2030   signal(SIGUSR1, dump_tables);
2031 #endif /* !__MINGW__  */
2032 }
2033 
2034 
2035 static int
other_addresses_on_net(struct in_addr old,struct in_addr ** extra)2036 other_addresses_on_net(struct in_addr old, struct in_addr **extra)
2037 {
2038   int	numExtra = 0;
2039   int	iface;
2040 
2041   for (iface = 0; iface < interfaces; iface++)
2042     {
2043       if (addr[iface].s_addr == old.s_addr)
2044 	{
2045 	  continue;
2046 	}
2047       if ((addr[iface].s_addr & mask[iface].s_addr) ==
2048 	    (old.s_addr & mask[iface].s_addr))
2049 	{
2050 	  numExtra++;
2051 	}
2052     }
2053   if (numExtra > 0)
2054     {
2055       struct in_addr	*addrs;
2056 
2057       addrs = (struct in_addr*)malloc(sizeof(struct in_addr)*numExtra);
2058       *extra = addrs;
2059       numExtra = 0;
2060 
2061       for (iface = 0; iface < interfaces; iface++)
2062 	{
2063 	  if (addr[iface].s_addr == old.s_addr)
2064 	    {
2065 	      continue;
2066 	    }
2067 	  if ((addr[iface].s_addr & mask[iface].s_addr) ==
2068 		(old.s_addr & mask[iface].s_addr))
2069 	    {
2070 	      addrs[numExtra].s_addr = addr[iface].s_addr;
2071 	      numExtra++;
2072 	    }
2073 	}
2074     }
2075   return numExtra;
2076 }
2077 
2078 
2079 /*
2080  *	Name -		init_probe()
2081  *	Purpose -	Send a request to all hosts on the local network
2082  *			to see if there is a name server running on them.
2083  */
2084 static void
init_probe()2085 init_probe()
2086 {
2087   uint32_t nlist[interfaces];
2088   int	nlist_size = 0;
2089   int	iface;
2090   int	i;
2091 
2092   if (noprobe > 0)
2093     {
2094       return;
2095     }
2096   if (debug > 2)
2097     {
2098       snprintf(ebuf, sizeof(ebuf), "Initiating probe requests.");
2099       gdomap_log(LOG_DEBUG);
2100     }
2101 
2102   /*
2103    *	Make a list of the different networks to which we must send.
2104    */
2105   for (iface = 0; iface < interfaces; iface++)
2106     {
2107       uint32_t	net = (addr[iface].s_addr & mask[iface].s_addr);
2108 
2109       if (addr[iface].s_addr == loopback.s_addr)
2110 	{
2111 	  continue;		/* Skip loopback	*/
2112 	}
2113       for (i = 0; i < nlist_size; i++)
2114 	{
2115 	  if (net == nlist[i])
2116 	    {
2117 	      break;
2118 	    }
2119 	}
2120       if (i == nlist_size)
2121 	{
2122 	  nlist[i] = net;
2123 	  nlist_size++;
2124 	}
2125     }
2126 
2127   for (i = 0; i < nlist_size; i++)
2128     {
2129       int		broadcast = 0;
2130       int		elen = 0;
2131       struct in_addr	*other = 0;
2132       struct in_addr	sin = { 0 };
2133       int		high = 0;
2134       int		low = 0;
2135       uint32_t  	net = 0;
2136       int		j;
2137       struct in_addr	b;
2138 
2139       /*
2140        *	Build up a list of addresses that we serve on this network.
2141        */
2142       for (iface = 0; iface < interfaces; iface++)
2143 	{
2144 	  if ((addr[iface].s_addr & mask[iface].s_addr) == nlist[i])
2145 	    {
2146 	      sin = addr[iface];
2147 	      if (bcok[iface])
2148 		{
2149 		  /*
2150 		   * Simple broadcast for this address.
2151 		   */
2152 		  b.s_addr = bcst[iface].s_addr;
2153 		  broadcast = 1;
2154 		}
2155 	      else
2156 		{
2157 		  uint32_t ha;		/* full host address.	*/
2158 		  uint32_t hm;		/* full netmask.	*/
2159 
2160 		  ha = ntohl(addr[iface].s_addr);
2161 		  hm = ntohl(mask[iface].s_addr);
2162 
2163 		  /*
2164 		   *	Make sure that our netmasks are restricted
2165 		   *	to class-c networks and subnets of those
2166 		   *	networks - we don't want to be probing
2167 		   *	more than a couple of hundred hosts!
2168 		   */
2169 		  if ((mask[iface].s_addr | class_c_mask.s_addr)
2170 			!= mask[iface].s_addr)
2171 		    {
2172 		      snprintf(ebuf, sizeof(ebuf), "netmask %s will be "
2173 			"treated as 255.255.255.0 for ",
2174 			inet_ntoa(mask[iface]));
2175 		      strncat(ebuf, inet_ntoa(addr[iface]),
2176 			sizeof(ebuf) - strlen(ebuf) - 1);
2177 		      gdomap_log(LOG_WARNING);
2178 		      hm |= ~255;
2179 		    }
2180 		  net = ha & hm & ~255;		/* class-c net number.	*/
2181 		  low = ha & hm & 255;		/* low end of subnet.	*/
2182 		  high = low | (255 & ~hm);	/* high end of subnet.	*/
2183 		  elen = other_addresses_on_net(sin, &other);
2184 		}
2185 	      break;
2186 	    }
2187 	}
2188 
2189       if (plist)
2190 	{
2191 	  plentry	*p;
2192 
2193 	  /*
2194 	   *	Now start probes for servers on machines in our probe config
2195 	   *	list for which we have a direct connection.
2196 	   */
2197 	  for (p = plist; p != 0; p = p->next)
2198 	    {
2199 	      if ((p->addr.s_addr & mask[iface].s_addr) ==
2200 		    (addr[iface].s_addr & mask[iface].s_addr))
2201 		{
2202 		  unsigned int	len = elen;
2203 
2204 		  p->direct = 1;
2205 		  /* Kick off probe.	*/
2206 		  if (is_local_host(p->addr))
2207 		    {
2208 		      continue;	/* Don't probe self.	*/
2209 		    }
2210 		  while (len > MAX_EXTRA)
2211 		    {
2212 		      len -= MAX_EXTRA;
2213 		      queue_probe(&p->addr, &sin, MAX_EXTRA, &other[len], 0);
2214 		    }
2215 		  queue_probe(&p->addr, &sin, len, other, 0);
2216 		}
2217 	    }
2218 	}
2219       else if (broadcast)
2220 	{
2221 	  /*
2222 	   *	Now broadcast probe on this network.
2223 	   */
2224 	  queue_probe(&b, &sin, 0, 0, 0);
2225 	}
2226       else
2227 	{
2228 	  /*
2229 	   *	Now start probes for servers on machines which may be on
2230 	   *	any network for which we have an interface.
2231 	   *
2232 	   *	Assume 'low' and 'high' are not valid host addresses as 'low'
2233 	   *	is the network address and 'high' is the broadcast address.
2234 	   */
2235 	  for (j = low + 1; j < high; j++)
2236 	    {
2237 	      struct in_addr	a;
2238 	      unsigned int	len = elen;
2239 
2240 	      a.s_addr = htonl(net + j);
2241 	      if (is_local_host(a))
2242 		{
2243 		  continue;	/* Don't probe self - that's silly.	*/
2244 		}
2245 	      /* Kick off probe.	*/
2246 	      while (len > MAX_EXTRA)
2247 		{
2248 		  len -= MAX_EXTRA;
2249 		  queue_probe(&a, &sin, MAX_EXTRA, &other[len], 0);
2250 		}
2251 	      queue_probe(&a, &sin, len, other, 0);
2252 	    }
2253 	}
2254 
2255       if (other != NULL)
2256 	{
2257 	  free(other);
2258 	}
2259     }
2260 
2261   if (plist)
2262     {
2263       plentry	*p;
2264       int	indirect = 0;
2265 
2266       /*
2267        *	Are there any hosts for which we do not have a direct
2268        *	network connection, and to which we have therefore not
2269        *	queued a probe?
2270        */
2271       for (p = plist; p != 0; p = p->next)
2272 	{
2273 	  if (p->direct == 0)
2274 	    {
2275 	      indirect = 1;
2276 	    }
2277 	}
2278       if (indirect)
2279 	{
2280 	  struct in_addr	*other = 0;
2281 	  int			elen;
2282 
2283 	  /*
2284 	   *	Queue probes for indirect connections to hosts from our
2285 	   *	primary interface and let the routing system handle it.
2286 	   */
2287 	  elen = other_addresses_on_net(addr[0], &other);
2288 	  for (p = plist; p != 0; p = p->next)
2289 	    {
2290 	      if (p->direct == 0)
2291 		{
2292 		  unsigned int	len = elen;
2293 
2294 		  if (is_local_host(p->addr))
2295 		    {
2296 		      continue;	/* Don't probe self.	*/
2297 		    }
2298 		  /* Kick off probe.	*/
2299 		  while (len > MAX_EXTRA)
2300 		    {
2301 		      len -= MAX_EXTRA;
2302 		      queue_probe(&p->addr, addr, MAX_EXTRA, &other[len], 0);
2303 		    }
2304 		  queue_probe(&p->addr, addr, len, other, 0);
2305 		}
2306 	    }
2307 	  if (0 != other)
2308 	    {
2309 	      free(other);
2310 	    }
2311 	}
2312     }
2313 
2314   if (debug > 2)
2315     {
2316       snprintf(ebuf, sizeof(ebuf), "Probe requests initiated.");
2317       gdomap_log(LOG_DEBUG);
2318     }
2319   last_probe = time(0);
2320 }
2321 
2322 /*
2323  *	Name -		handle_accept()
2324  *	Purpose -	Handle an incoming connection, setting up resources
2325  *			for the request. Ensure that the channel is in
2326  *			non-blocking mode so that we can't hang.
2327  */
2328 static void
handle_accept()2329 handle_accept()
2330 {
2331   struct sockaddr_in	sa;
2332   socklen_t		len = sizeof(sa);
2333   int			desc;
2334 
2335   memset(&sa, '\0', len);
2336   desc = accept(tcp_desc, (void*)&sa, &len);
2337   if (desc >= 0)
2338     {
2339       RInfo		*ri;
2340 #if	defined(__MINGW__)
2341       uint32_t	dummy = 1;
2342 #else
2343       int		r;
2344 #endif /* !__MINGW__ */
2345 
2346       FD_SET(desc, &read_fds);
2347       ri = getRInfo(desc, 1);
2348       ri->pos = 0;
2349       memcpy((char*)&ri->addr, (char*)&sa, sizeof(sa));
2350 
2351       if (debug)
2352 	{
2353 	  snprintf(ebuf, sizeof(ebuf), "accept from %s(%d) to chan %d",
2354 	    inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), desc);
2355 	  gdomap_log(LOG_DEBUG);
2356 	}
2357       /*
2358        *	Ensure that the connection is non-blocking.
2359        */
2360 #if	defined(__MINGW__)
2361       if (ioctlsocket(desc, FIONBIO, &dummy) < 0)
2362 	{
2363 	  if (debug)
2364 	    {
2365 	      snprintf(ebuf, sizeof(ebuf),
2366 		"failed to set chan %d non-blocking", desc);
2367 	      gdomap_log(LOG_DEBUG);
2368 	    }
2369 	  clear_chan(desc);
2370 	}
2371 #else /* !__MINGW__ */
2372       if ((r = fcntl(desc, F_GETFL, 0)) >= 0)
2373 	{
2374 	  r |= NBLK_OPT;
2375 	  if (fcntl(desc, F_SETFL, r) < 0)
2376 	    {
2377 	      if (debug)
2378 		{
2379 		  snprintf(ebuf, sizeof(ebuf),
2380 		    "failed to set chan %d non-blocking", desc);
2381 		  gdomap_log(LOG_DEBUG);
2382 		}
2383 	      clear_chan(desc);
2384 	    }
2385 	}
2386       else
2387 	{
2388 	  if (debug)
2389 	    {
2390 	      snprintf(ebuf, sizeof(ebuf),
2391 		"failed to set chan %d non-blocking", desc);
2392 	      gdomap_log(LOG_DEBUG);
2393 	    }
2394 	  clear_chan(desc);
2395 	}
2396 #endif /* __MINGW__ */
2397     }
2398   else if (debug)
2399     {
2400       snprintf(ebuf, sizeof(ebuf), "accept failed - errno %d",
2401 #if	defined(__MINGW__)
2402 	WSAGetLastError());
2403 #else
2404 	errno);
2405 #endif /* __MINGW__ */
2406       gdomap_log(LOG_DEBUG);
2407     }
2408 }
2409 
2410 /*
2411  *	Name -		handle_io()
2412  *	Purpose -	Main loop to handle I/O on multiple simultaneous
2413  *			connections.  All non-blocking stuff.
2414  */
2415 static void
handle_io()2416 handle_io()
2417 {
2418   struct timeval timeout;
2419   void		*to;
2420   int		rval = 0;
2421   int		i;
2422   fd_set	rfds;
2423   fd_set	wfds;
2424 
2425   while (rval >= 0)
2426     {
2427       rfds = read_fds;
2428       wfds = write_fds;
2429       to = 0;
2430 
2431       /*
2432        *	If there is anything waiting to be sent on the UDP socket
2433        *	we must check to see if it is writable.
2434        */
2435       if (u_queue != 0)
2436 	{
2437 	  FD_SET(udp_desc, &wfds);
2438 	}
2439 
2440       timeout.tv_sec = 10;
2441       timeout.tv_usec = 0;
2442       to = &timeout;
2443       soft_int = 0;
2444       rval = select(FD_SETSIZE, &rfds, &wfds, 0, to);
2445 
2446       if (rval < 0)
2447 	{
2448 	  /*
2449 	   *	Let's handle any error return.
2450 	   */
2451 	  if (errno == EBADF)
2452 	    {
2453 	      fd_set	efds;
2454 
2455 	      /*
2456 	       *	Almost certainly lost a connection - try each
2457 	       *	descriptor in turn to see which one it is.
2458 	       *	Remove descriptor from bitmask and close it.
2459 	       *	If the error is on the listener socket we die.
2460 	       */
2461 	      memset(&efds, '\0', sizeof(efds));
2462 	      for (i = 0; i < FD_SETSIZE; i++)
2463 		{
2464 		  if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds))
2465 		    {
2466 		      FD_SET(i, &efds);
2467 		      timeout.tv_sec = 0;
2468 		      timeout.tv_usec = 0;
2469 		      to = &timeout;
2470 		      rval = select(FD_SETSIZE, &efds, 0, 0, to);
2471 		      FD_CLR(i, &efds);
2472 		      if (rval < 0 && errno == EBADF)
2473 			{
2474 			  clear_chan(i);
2475 			  if (i == tcp_desc || i == udp_desc)
2476 			    {
2477 			      snprintf(ebuf, sizeof(ebuf),
2478 				"Fatal error on socket.");
2479 			      gdomap_log(LOG_CRIT);
2480 			      exit(EXIT_FAILURE);
2481 			    }
2482 			}
2483 		    }
2484 		}
2485 	      rval = 0;
2486 	    }
2487 	  else if (soft_int > 0)
2488 	    {
2489 	      /*
2490 	       * We were interrupted - but it was one we were expecting.
2491 	       */
2492 	      rval = 0;
2493 	    }
2494 	  else if (errno == EINTR)
2495             {
2496               rval = 0;
2497             }
2498 	  else
2499 	    {
2500 	      snprintf(ebuf, sizeof(ebuf),
2501 		"Interrupted in select: %s",strerror(errno));
2502 	      gdomap_log(LOG_CRIT);
2503 	      exit(EXIT_FAILURE);
2504 	    }
2505 	}
2506       else if (rval == 0)
2507 	{
2508 	  long		now = time(0);
2509 
2510 	  /*
2511 	   *	Let's handle a timeout.
2512 	   */
2513 	  prb_tim(now);	/* Remove dead servers	*/
2514 	  if (udp_pending == 0 && (now - last_probe) >= interval)
2515 	    {
2516 	      /*
2517 	       *	If there is no output pending on the udp channel and
2518 	       *	it is at least five minutes since we sent out a probe
2519 	       *	we can re-probe the network for other name servers.
2520 	       */
2521 	      init_probe();
2522 	    }
2523 	}
2524       else
2525 	{
2526 	  /*
2527 	   *	Got some descriptor activity - deal with it.
2528 	   */
2529 #if	defined(__MINGW__)
2530 	  /* read file descriptors */
2531 	  for (i = 0; i < rfds.fd_count; i++)
2532 	    {
2533 	      if (rfds.fd_array[i] == tcp_desc)
2534 		{
2535 		  handle_accept();
2536 		}
2537 	      else if (rfds.fd_array[i] == udp_desc)
2538 		{
2539 		  handle_recv();
2540 		}
2541 	      else
2542 		{
2543 		  handle_read(rfds.fd_array[i]);
2544 		}
2545 	      if (debug > 2)
2546 		{
2547 		  dump_stats();
2548 		}
2549 	    }
2550 	  for (i = 0; i < wfds.fd_count; i++)
2551 	    {
2552 	      if (wfds.fd_array[i] == udp_desc)
2553 		{
2554 		  handle_send();
2555 		}
2556 	      else
2557 		{
2558 		  handle_write(wfds.fd_array[i]);
2559 		}
2560 	    }
2561 #else /* !__MINGW__ */
2562 	  for (i = 0; i < FD_SETSIZE; i++)
2563 	    {
2564 	      if (FD_ISSET(i, &rfds))
2565 		{
2566 		  if (i == tcp_desc)
2567 		    {
2568 		      handle_accept();
2569 		    }
2570 		  else if (i == udp_desc)
2571 		    {
2572 		      handle_recv();
2573 		    }
2574 		  else
2575 		    {
2576 		      handle_read(i);
2577 		    }
2578 		  if (debug > 2)
2579 		    {
2580 		      dump_stats();
2581 		    }
2582 		}
2583               /* Look for a descriptor found to be writeable and which
2584                * was not closed (due to reading eof etc)
2585                */
2586 	      if (FD_ISSET(i, &wfds)
2587                 && (FD_ISSET(i, &write_fds) || i == udp_desc))
2588 		{
2589 		  if (i == udp_desc)
2590 		    {
2591 		      handle_send();
2592 		    }
2593 		  else
2594 		    {
2595 		      handle_write(i);
2596 		    }
2597 		}
2598 	    }
2599 #endif /* __MINGW__ */
2600 	}
2601     }
2602 }
2603 
2604 /*
2605  *	Name -		handle_read()
2606  *	Purpose -	Read a request from a channel.  This may be called in
2607  *			many stages if the read is blocking.
2608  */
2609 static void
handle_read(int desc)2610 handle_read(int desc)
2611 {
2612   RInfo	*ri;
2613   uptr	ptr;
2614   int	nothingRead = 1;
2615   int	done = 0;
2616   int	r;
2617 
2618   ri = getRInfo(desc, 0);
2619   if (0 == ri)
2620     {
2621       snprintf(ebuf, sizeof(ebuf),
2622 	"request not found on descriptor %d", desc);
2623       gdomap_log(LOG_DEBUG);
2624       return;
2625     }
2626   ptr = ri->buf.b;
2627 
2628   while (ri->pos < GDO_REQ_SIZE && done == 0)
2629     {
2630 #if	defined(__MINGW__)
2631       r = recv(desc, (char *)&ptr[ri->pos], GDO_REQ_SIZE - ri->pos, 0);
2632 #else
2633       r = read(desc, &ptr[ri->pos], GDO_REQ_SIZE - ri->pos);
2634 #endif
2635       if (r > 0)
2636 	{
2637 	  nothingRead = 0;
2638 	  ri->pos += r;
2639 	}
2640       else
2641 	{
2642 	  done = 1;
2643 	}
2644     }
2645   if (ri->pos == GDO_REQ_SIZE)
2646     {
2647       tcp_read++;
2648       handle_request(desc);
2649     }
2650 #if	defined(__MINGW__)
2651   else if (WSAGetLastError() != WSAEWOULDBLOCK || nothingRead == 1)
2652 #else
2653   else if (errno != EWOULDBLOCK || nothingRead == 1)
2654 #endif
2655     {
2656       /*
2657        *	If there is an error or end-of-file on the descriptor then
2658        *	we must close it down.
2659        */
2660       clear_chan(desc);
2661     }
2662 }
2663 
2664 /*
2665  *	Name -		handle_recv()
2666  *	Purpose -	Read a request from the UDP socket.
2667  */
2668 static void
handle_recv()2669 handle_recv()
2670 {
2671   RInfo	*ri;
2672   uptr	ptr;
2673   struct sockaddr_in* addr;
2674   socklen_t len = sizeof(struct sockaddr_in);
2675   int	r;
2676 
2677   ri = getRInfo(udp_desc, 0);
2678   if (0 == ri)
2679     {
2680       snprintf(ebuf, sizeof(ebuf),
2681 	"request not found on descriptor %d", udp_desc);
2682       gdomap_log(LOG_DEBUG);
2683       return;
2684     }
2685   addr = &(ri->addr);
2686   ptr = ri->buf.b;
2687 
2688   r = recvfrom(udp_desc, (char *)ptr, GDO_REQ_SIZE, 0, (void*)addr, &len);
2689   if (r == GDO_REQ_SIZE)
2690     {
2691       udp_read++;
2692       ri->pos = GDO_REQ_SIZE;
2693       if (debug)
2694 	{
2695 	  snprintf(ebuf, sizeof(ebuf),
2696 	    "recvfrom %s", inet_ntoa(addr->sin_addr));
2697 	  gdomap_log(LOG_DEBUG);
2698 	}
2699       if (is_local_host(addr->sin_addr) == 1)
2700 	{
2701 	  if (debug)
2702 	    {
2703 	      snprintf(ebuf, sizeof(ebuf),
2704 		"recvfrom packet from self discarded");
2705 	      gdomap_log(LOG_DEBUG);
2706 	    }
2707 	  return;
2708 	}
2709       handle_request(udp_desc);
2710     }
2711   else
2712     {
2713       if (debug)
2714 	{
2715 	  snprintf(ebuf, sizeof(ebuf),
2716 	    "recvfrom returned %d - %s", r, lastErr());
2717 	  gdomap_log(LOG_DEBUG);
2718 	}
2719     }
2720 }
2721 
2722 /*
2723  *	Name -		handle_request()
2724  *	Purpose -	Once we have read a full request, we come here
2725  *			to take action depending on the request type.
2726  */
2727 static void
handle_request(int desc)2728 handle_request(int desc)
2729 {
2730   RInfo		*ri;
2731   WInfo		*wi;
2732   unsigned char	type;
2733   unsigned char	size;
2734   unsigned char	ptype;
2735   uint32_t	port;
2736   unsigned char	*buf;
2737   map_ent	*m;
2738 
2739   ri = getRInfo(desc, 0);
2740   if (0 == ri)
2741     {
2742       snprintf(ebuf, sizeof(ebuf), "request not found on descriptor %d", desc);
2743       gdomap_log(LOG_DEBUG);
2744       return;
2745     }
2746   type = ri->buf.r.rtype;
2747   size = ri->buf.r.nsize;
2748   ptype = ri->buf.r.ptype;
2749   port = ntohl(ri->buf.r.port);
2750   buf = (unsigned char*)ri->buf.r.name;
2751 
2752   FD_CLR(desc, &read_fds);
2753   FD_SET(desc, &write_fds);
2754 
2755   if (debug > 1)
2756     {
2757       if (desc == udp_desc)
2758 	{
2759 	  snprintf(ebuf, sizeof(ebuf), "request type '%c' on UDP chan", type);
2760 	  gdomap_log(LOG_DEBUG);
2761 	}
2762       else
2763 	{
2764 	  snprintf(ebuf, sizeof(ebuf),
2765 	    "request type '%c' from chan %d", type, desc);
2766 	  gdomap_log(LOG_DEBUG);
2767 	}
2768       if (type == GDO_PROBE || type == GDO_PREPLY || type == GDO_SERVERS
2769 	|| type == GDO_NAMES)
2770 	{
2771 	  /* fprintf(stderr, "\n"); */
2772 	}
2773       else
2774 	{
2775 	  snprintf(ebuf, sizeof(ebuf),
2776 	    "  name: '%.*s' port: %"PRIu32, size, buf, port);
2777 	  gdomap_log(LOG_DEBUG);
2778 	}
2779     }
2780 
2781   wi = getWInfo(desc, 1);
2782   wi->pos = 0;
2783 
2784   if (ptype != GDO_TCP_GDO && ptype != GDO_TCP_FOREIGN
2785     && ptype != GDO_UDP_GDO && ptype != GDO_UDP_FOREIGN)
2786     {
2787       if (ptype != 0 || (type != GDO_PROBE && type != GDO_PREPLY
2788 	&& type != GDO_SERVERS && type != GDO_NAMES))
2789 	{
2790 	  if (debug)
2791 	    {
2792 	      snprintf(ebuf, sizeof(ebuf), "Illegal port type in request");
2793 	      gdomap_log(LOG_DEBUG);
2794 	    }
2795 	  clear_chan(desc);
2796 	  return;
2797 	}
2798     }
2799 
2800   /*
2801    *	The default return value is a four byte number set to zero.
2802    *	We assume that malloc returns data aligned on a 4 byte boundary.
2803    */
2804   wi->len = 4;
2805   wi->buf = (char*)malloc(4);
2806   wi->buf[0] = 0;
2807   wi->buf[1] = 0;
2808   wi->buf[2] = 0;
2809   wi->buf[3] = 0;
2810 
2811   if (type == GDO_REGISTER)
2812     {
2813       /*
2814        *	See if this is a request from a local process.
2815        */
2816       if (is_local_host(ri->addr.sin_addr) == 0)
2817 	{
2818 	  snprintf(ebuf, sizeof(ebuf), "Illegal attempt to register!");
2819 	  gdomap_log(LOG_ERR);
2820 	  clear_chan(desc);		/* Only local progs may register. */
2821 	  return;
2822 	}
2823 
2824       /*
2825        *	What should we do if we already have the name registered?
2826        *	Simple algorithm -
2827        *		We check to see if we can bind to the old port,
2828        *		and if we can we assume that the original process
2829        *		has gone away and permit a new registration for the
2830        *		same name.
2831        *		This is not foolproof - if the machine has more
2832        *		than one IP address, we could bind to the port on
2833        *		one address even though the server is using it on
2834        *		another.
2835        *		Also - the operating system is not guaranteed to
2836        *		let us bind to the port if another process has only
2837        *		recently stopped using it.
2838        *		Also - what if an old server used the port that the
2839        *		new one is using?  In this case the registration
2840        *		attempt will be refused even though it shouldn't be!
2841        *		On the other hand - the occasional registration
2842        *		failure MUST be better than permitting a process to
2843        *		grab a name already in use! If a server fails to
2844        *		register a name/port combination, it can always be
2845        *		coded to retry on a different port.
2846        */
2847       m = map_by_name(buf, size);
2848       if (m != 0 && port == m->port)
2849 	{
2850 	  /*
2851 	   *	Special case - we already have this name registered for this
2852 	   *	port - so everything is already ok.
2853 	   */
2854 	  if (debug)
2855 	    {
2856 	      snprintf(ebuf, sizeof(ebuf), "Already registered ... success");
2857 	      gdomap_log(LOG_DEBUG);
2858 	    }
2859 	  *(uint32_t*)wi->buf = htonl(port);
2860 	}
2861       else if (m != 0)
2862 	{
2863 	  int	sock = -1;
2864 
2865 	  if ((ptype & GDO_NET_MASK) == GDO_NET_TCP)
2866 	    {
2867 	      sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
2868 	    }
2869 	  else if ((ptype & GDO_NET_MASK) == GDO_NET_UDP)
2870 	    {
2871 	      sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2872 	    }
2873 
2874 	  if (sock < 0)
2875 	    {
2876 	      perror("unable to create new socket");
2877 	    }
2878 	  else
2879 	    {
2880 #ifndef BROKEN_SO_REUSEADDR
2881 	      int	r = 1;
2882 
2883 	      /*
2884 	       * Under decent systems, SO_REUSEADDR means that the port can
2885 	       * be reused immediately that this process exits.  Under some
2886 	       * it means that multiple processes can serve the same port
2887 	       * simultaneously.
2888 	       * We don't want that broken behavior!
2889 	       */
2890 	      if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2891 		(char*)&r, sizeof(r)) < 0)
2892 		{
2893 		  perror("unable to set socket options");
2894 		}
2895 	      else
2896 #endif
2897 		{
2898 		  struct sockaddr_in	sa;
2899 		  int			result;
2900 		  short			p = m->port;
2901 
2902 		  memset(&sa, '\0', sizeof(sa));
2903 		  sa.sin_family = AF_INET;
2904 		  sa.sin_addr.s_addr = htonl(INADDR_ANY);
2905 		  sa.sin_port = htons(p);
2906 		  result = bind(sock, (void*)&sa, sizeof(sa));
2907 		  if (result == 0)
2908 		    {
2909 		      if (debug > 1)
2910 			{
2911 			  snprintf(ebuf, sizeof(ebuf),
2912 			    "re-register from %d to %"PRIu32,
2913 			    m->port, port);
2914 			  gdomap_log(LOG_DEBUG);
2915 			}
2916 		      m->port = port;
2917 		      m->net = (ptype & GDO_NET_MASK);
2918 		      m->svc = (ptype & GDO_SVC_MASK);
2919 		      port = htonl(m->port);
2920 		      *(uint32_t*)wi->buf = port;
2921 		    }
2922 		}
2923 #if	defined(__MINGW__)
2924 	      /* closesocket(sock); */
2925 #else
2926 	      close(sock);
2927 #endif
2928 	    }
2929 	}
2930       else if (port == 0)
2931 	{	/* Port not provided!	*/
2932 	  if (debug)
2933 	    {
2934 	      snprintf(ebuf, sizeof(ebuf), "Port not provided in request!");
2935 	      gdomap_log(LOG_DEBUG);
2936 	    }
2937 	  *(uint32_t*)wi->buf = 0;
2938 	}
2939       else
2940 	{		/* Use port provided in request.	*/
2941 	  if (debug)
2942 	    {
2943 	      snprintf(ebuf, sizeof(ebuf), "Registered on port %"PRIu32, port);
2944 	      gdomap_log(LOG_DEBUG);
2945 	    }
2946 	  m = map_add(buf, size, port, ptype);
2947 	  port = htonl(m->port);
2948 	  *(uint32_t*)wi->buf = port;
2949 	}
2950     }
2951   else if (type == GDO_LOOKUP)
2952     {
2953       m = map_by_name(buf, size);
2954       if (m != 0 && (m->net | m->svc) != ptype)
2955 	{
2956 	  if (debug > 1)
2957 	    {
2958 	      snprintf(ebuf, sizeof(ebuf),
2959 		"requested service is of wrong type");
2960 	      gdomap_log(LOG_DEBUG);
2961 	    }
2962 	  m = 0;	/* Name exists but is of wrong type.	*/
2963 	}
2964       if (m)
2965 	{
2966 	  int	sock = -1;
2967 
2968 	  /*
2969 	   *	We check to see if we can bind to the old port, and if we can
2970 	   *	we assume that the process has gone away and remove it from
2971 	   *	the map.
2972 	   *	This is not foolproof - if the machine has more
2973 	   *	than one IP address, we could bind to the port on
2974 	   *	one address even though the server is using it on
2975 	   *	another.
2976 	   */
2977 	  if ((ptype & GDO_NET_MASK) == GDO_NET_TCP)
2978 	    {
2979 	      sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
2980 	    }
2981 	  else if ((ptype & GDO_NET_MASK) == GDO_NET_UDP)
2982 	    {
2983 	      sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2984 	    }
2985 
2986 	  if (sock < 0)
2987 	    {
2988 	      perror("unable to create new socket");
2989 	    }
2990 	  else
2991 	    {
2992 #ifndef BROKEN_SO_REUSEADDR
2993 	      int	r = 1;
2994 
2995 	      /*
2996 	       * Under decent systems, SO_REUSEADDR means that the port can
2997 	       * be reused immediately that this process exits.  Under some
2998 	       * it means that multiple processes can serve the same port
2999 	       * simultaneously.
3000 	       * We don't want that broken behavior!
3001 	       */
3002 	      if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
3003 		(char*)&r, sizeof(r)) < 0)
3004 		{
3005 		  perror("unable to set socket options");
3006 		}
3007 	      else
3008 #endif
3009 		{
3010 		  struct sockaddr_in	sa;
3011 		  int			result;
3012 		  unsigned short	p = (unsigned short)m->port;
3013 
3014 		  memset(&sa, '\0', sizeof(sa));
3015 		  sa.sin_family = AF_INET;
3016 
3017 #if	defined(__MINGW__)
3018 		  /* COMMENT:  (3 Nov 2004 by Wim Oudshoorn):
3019 		     The comment below might be true.  But
3020 		     using addr[0].s_addr has on windows 2003 server
3021 		     (and some other versions of windows.)
3022 		     exactly the same sympton as it tries to avoid.
3023 		     The funny thing is that the original line, just
3024 		     using INADDR_ANY seems to work on windows.
3025 		     However, I assume the FIXME below was put there
3026 		     for a reason.  But for now I just revert it because
3027 		     the platform independent code seems to work.
3028 		  */
3029  		  /* FIXME: This must not be INADDR_ANY on Win,
3030  		     otherwise the system will try to bind on any of
3031  		     the local addresses (including 127.0.0.1), which
3032  		     works. - bjoern */
3033 /*		  sa.sin_addr.s_addr = addr[0].s_addr; */
3034 		  sa.sin_addr.s_addr = htonl(INADDR_ANY);
3035 #else
3036  		  sa.sin_addr.s_addr = htonl(INADDR_ANY);
3037 #endif /* __MINGW__ */
3038 		  sa.sin_port = htons(p);
3039 		  result = bind(sock, (void*)&sa, sizeof(sa));
3040 		  if (result == 0)
3041 		    {
3042 		      map_del(m);
3043 		      m = 0;
3044 		    }
3045 		}
3046 #if	defined(__MINGW__)
3047 	      closesocket(sock);
3048 #else
3049 	      close(sock);
3050 #endif
3051 	    }
3052 	}
3053       if (m)
3054 	{	/* Lookup found live server.	*/
3055 	  *(uint32_t*)wi->buf = htonl(m->port);
3056 	}
3057       else
3058 	{		/* Not found.			*/
3059 	  if (debug > 1)
3060 	    {
3061 	      snprintf(ebuf, sizeof(ebuf), "requested service not found");
3062 	      gdomap_log(LOG_DEBUG);
3063 	    }
3064 	  *(unsigned short*)wi->buf = 0;
3065 	}
3066     }
3067   else if (type == GDO_UNREG)
3068     {
3069       /*
3070        *	See if this is a request from a local process.
3071        */
3072       if (is_local_host(ri->addr.sin_addr) == 0)
3073 	{
3074 	  snprintf(ebuf, sizeof(ebuf), "Illegal attempt to un-register!");
3075 	  gdomap_log(LOG_ERR);
3076 	  clear_chan(desc);
3077 	  return;
3078 	}
3079       if (port == 0 || size > 0)
3080 	{
3081 	  m = map_by_name(buf, size);
3082 	  if (m)
3083 	    {
3084 	      if ((m->net | m->svc) != ptype)
3085 		{
3086 		  if (debug)
3087 		    {
3088 		      snprintf(ebuf, sizeof(ebuf),
3089 			"Attempted unregister with wrong type");
3090 		      gdomap_log(LOG_DEBUG);
3091 		    }
3092 		}
3093 	      else
3094 		{
3095 		  *(uint32_t*)wi->buf = htonl(m->port);
3096 		  map_del(m);
3097 		}
3098 	    }
3099 	  else
3100 	    {
3101 	      if (debug > 1)
3102 		{
3103 		  snprintf(ebuf, sizeof(ebuf), "requested service not found");
3104 		  gdomap_log(LOG_DEBUG);
3105 		}
3106 	    }
3107 	}
3108       else
3109 	{
3110 	  *(uint32_t*)wi->buf = 0;
3111 
3112 	  while ((m = map_by_port(port, ptype)) != 0)
3113 	    {
3114 	      *(uint32_t*)wi->buf = htonl(m->port);
3115 	      map_del(m);
3116 	    }
3117 	}
3118     }
3119   else if (type == GDO_SERVERS)
3120     {
3121       unsigned int	i;
3122       unsigned int	j;
3123 
3124       /* See if this is a request from a local process.
3125        *
3126        * This request is only useful locally.  Do not allow remote
3127        * requests for the server list.  Our response can be large,
3128        * so it would make a great UDP amplification attack.
3129        */
3130       if (is_local_host(ri->addr.sin_addr) == 0)
3131 	{
3132 	  snprintf(ebuf, sizeof(ebuf), "Illegal attempt to list servers!");
3133 	  gdomap_log(LOG_ERR);
3134 	  clear_chan(desc);
3135 	  return;
3136 	}
3137 
3138       free(wi->buf);
3139       wi->buf = (char*)calloc(sizeof(uint32_t)
3140 	+ (prb_used+1)*IASIZE, 1);
3141       *(uint32_t*)wi->buf = htonl(prb_used+1);
3142       memcpy(&wi->buf[4], &ri->addr.sin_addr, IASIZE);
3143 
3144       /*
3145        * Copy the addresses of the hosts we have probed into the buffer.
3146        * During the copy, reverse the order of the addresses so that the
3147        * address we have contacted most recently is first.  This should
3148        * ensure that the client process will attempt to contact live
3149        * hosts before dead ones.
3150        */
3151       for (i = 0, j = prb_used; i < prb_used; i++)
3152 	{
3153 	  memcpy(&wi->buf[4+(i+1)*IASIZE], &prb[--j]->sin, IASIZE);
3154 	}
3155       wi->len = 4 + (prb_used+1)*IASIZE;
3156     }
3157   else if (type == GDO_NAMES)
3158     {
3159       int	bytes = 0;
3160       uptr	ptr;
3161       int	i;
3162 
3163       free(wi->buf);
3164 
3165       /*
3166        * Size buffer for names.
3167        */
3168       for (i = 0; i < map_used; i++)
3169 	{
3170 	  bytes += 2 + map[i]->size;
3171 	}
3172       /*
3173        * Allocate with space for number of names and set it up.
3174        */
3175       wi->buf = (char*)malloc(4 + bytes);
3176       *(uint32_t*)wi->buf = htonl(bytes);
3177       ptr = (uptr)wi->buf;
3178       ptr += 4;
3179       for (i = 0; i < map_used; i++)
3180 	{
3181 	  ptr[0] = (unsigned char)map[i]->size;
3182 	  ptr[1] = (unsigned char)(map[i]->net | map[i]->svc);
3183 	  memcpy(&ptr[2], map[i]->name, ptr[0]);
3184 	  ptr += 2 + ptr[0];
3185 	}
3186       wi->len = 4 + bytes;
3187     }
3188   else if (type == GDO_PROBE)
3189     {
3190       /*
3191        *	If the client is a name server, we add it to the list.
3192        */
3193       if (ri->addr.sin_port == my_port)
3194 	{
3195 	  struct in_addr	sin;
3196 
3197 	  memcpy(&sin, ri->buf.r.name, IASIZE);
3198 	  if (debug > 2)
3199 	    {
3200 	      snprintf(ebuf, sizeof(ebuf), "Probe from '%s'", inet_ntoa(sin));
3201 	      gdomap_log(LOG_DEBUG);
3202 	    }
3203 	  prb_add(&sin);
3204 
3205 	  /*
3206 	   *	Irrespective of what we are told to do - we also add the
3207 	   *	interface from which this packet arrived so we have a
3208 	   *	route we KNOW we can use.
3209 	   */
3210 	  prb_add(&ri->addr.sin_addr);
3211 
3212 #if 0
3213 	{
3214 	  struct in_addr	*ptr;
3215 	  uint32_t	net;
3216 	  int	c;
3217 
3218 #if	defined(__MINGW__)
3219 	  if (IN_CLASSA(sin.s_addr))
3220 	    {
3221 	      net = sin.s_addr & IN_CLASSA_NET;
3222 	    }
3223 	  else if (IN_CLASSB(sin.s_addr))
3224 	    {
3225 	      net = sin.s_addr & IN_CLASSB_NET;
3226 	    }
3227 	  else if (IN_CLASSC(sin.s_addr))
3228 	    {
3229 	      net = sin.s_addr & IN_CLASSC_NET;
3230 	    }
3231 #else
3232 	  net = inet_netof(sin);
3233 #endif
3234 	  ptr = (struct in_addr*)&ri->buf.r.name[2*IASIZE];
3235 	  c = (ri->buf.r.nsize - 2*IASIZE)/IASIZE;
3236 	  while (c-- > 0)
3237 	    {
3238 	      if (debug > 2)
3239 		{
3240 		  snprintf(ebuf, sizeof(ebuf),
3241 		    "Add server '%s'", inet_ntoa(*ptr));
3242 		  gdomap_log(LOG_DEBUG);
3243 		}
3244 	      prb_add(ptr);
3245 	      ptr++;
3246 	    }
3247 	}
3248 #endif
3249 	}
3250       /*
3251        *	For a UDP request from another name server, we send a reply
3252        *	packet.  We shouldn't be getting probes from anywhere else,
3253        *	but just to be nice, we send back our port number anyway.
3254        */
3255       if (desc == udp_desc && ri->addr.sin_port == my_port)
3256 	{
3257 	  struct in_addr	laddr;
3258 	  struct in_addr	raddr;
3259 	  struct in_addr	*other = 0;
3260 	  unsigned int		elen;
3261 	  void			*rbuf = ri->buf.r.name;
3262 	  void			*wbuf;
3263 	  int			i;
3264 	  gdo_req		*r;
3265 
3266 	  free(wi->buf);
3267 	  r = (gdo_req*)calloc(GDO_REQ_SIZE, 1);
3268 	  wi->buf = (char*)r;
3269 	  wbuf = r->name;
3270 	  r->rtype = GDO_PREPLY;
3271 	  r->nsize = IASIZE*2;
3272 
3273 	  memcpy(&raddr, rbuf, IASIZE);
3274 	  memcpy(&laddr, rbuf+IASIZE, IASIZE);
3275 	  if (debug > 2)
3276 	    {
3277 	      snprintf(ebuf, sizeof(ebuf),
3278 		"Probe sent remote '%s'", inet_ntoa(raddr));
3279 	      snprintf(ebuf, sizeof(ebuf),
3280 		"Probe sent local  '%s'", inet_ntoa(laddr));
3281 	    }
3282 
3283 	  memcpy(wbuf+IASIZE, &raddr, IASIZE);
3284 	  /*
3285 	   *	If the other end did not tell us which of our addresses it was
3286 	   *	probing, try to select one on the same network to send back.
3287 	   *	otherwise, respond with the address it was probing.
3288 	   */
3289 	  if (is_local_host(laddr) == 0
3290 	    || laddr.s_addr == loopback.s_addr)
3291 	    {
3292 	      for (i = 0; i < interfaces; i++)
3293 		{
3294 		  if (addr[i].s_addr == loopback.s_addr)
3295 		    {
3296 		      continue;
3297 		    }
3298 		  if ((mask[i].s_addr & addr[i].s_addr) ==
3299 			(mask[i].s_addr & ri->addr.sin_addr.s_addr))
3300 		    {
3301 		      laddr = addr[i];
3302 		      memcpy(wbuf, &laddr, IASIZE);
3303 		      break;
3304 		    }
3305 		}
3306 	    }
3307 	  else
3308 	    {
3309 	      memcpy(wbuf, &laddr, IASIZE);
3310 	    }
3311 	  wi->len = GDO_REQ_SIZE;
3312 
3313 	  elen = other_addresses_on_net(laddr, &other);
3314 	  if (elen > 0)
3315 	    {
3316 	      while (elen > MAX_EXTRA)
3317 		{
3318 		  elen -= MAX_EXTRA;
3319 		  queue_probe(&raddr, &laddr, MAX_EXTRA, &other[elen], 1);
3320 		}
3321 	      queue_probe(&raddr, &laddr, elen, other, 1);
3322 	    }
3323 	  if (0 != other)
3324 	    {
3325 	      free(other);
3326 	    }
3327 	}
3328       else
3329 	{
3330 	  port = my_port;
3331 	  *(uint32_t*)wi->buf = htonl(port);
3332 	}
3333     }
3334   else if (type == GDO_PREPLY)
3335     {
3336       /*
3337        *	This should really be a reply by UDP to a probe we sent
3338        *	out earlier.  We should add the name server to our list.
3339        */
3340       if (ri->addr.sin_port == my_port)
3341 	{
3342 	  struct in_addr	sin;
3343 
3344 	  memcpy(&sin, &ri->buf.r.name, IASIZE);
3345 	  if (debug > 2)
3346 	    {
3347 	      snprintf(ebuf, sizeof(ebuf),
3348 		"Probe reply from '%s'", inet_ntoa(sin));
3349 	      gdomap_log(LOG_DEBUG);
3350 	    }
3351 	  prb_add(&sin);
3352 	  /*
3353 	   *	Irrespective of what we are told to do - we also add the
3354 	   *	interface from which this packet arrived so we have a
3355 	   *	route we KNOW we can use.
3356 	   */
3357 	  prb_add(&ri->addr.sin_addr);
3358 	}
3359       /*
3360        *	Because this is really a reply to us, we don't want to reply
3361        *	to it or we would get a feedback loop.
3362        */
3363       clear_chan(desc);
3364       return;
3365     }
3366   else
3367     {
3368       snprintf(ebuf, sizeof(ebuf), "Illegal operation code received!");
3369       gdomap_log(LOG_ERR);
3370       clear_chan(desc);
3371       return;
3372     }
3373 
3374   /*
3375    *	If the request was via UDP, we send a response back by queuing
3376    *	rather than letting the normal 'write_handler()' function do it.
3377    */
3378   if (desc == udp_desc)
3379     {
3380       queue_msg(&ri->addr, (unsigned char*)wi->buf, wi->len);
3381       clear_chan(desc);
3382     }
3383 }
3384 
3385 /*
3386  *	Name -		handle_send()
3387  *	Purpose -	Send any pending message on UDP socket.
3388  *			The code is designed to send the message in parts if
3389  *			the 'sendto()' function returns a positive integer
3390  *			indicating that only part of the message has been
3391  *			written.  This should never happen - but I coded it
3392  *			this way in case we have to run on a system which
3393  *			implements sendto() badly (I used such a system
3394  *			many years ago).
3395  */
3396 static void
handle_send()3397 handle_send()
3398 {
3399   struct u_data*	entry = u_queue;
3400 
3401   if (entry)
3402     {
3403       int	r;
3404 
3405       r = sendto(udp_desc, (const char *)&entry->dat[entry->pos],
3406       entry->len - entry->pos, 0, (void*)&entry->addr, sizeof(entry->addr));
3407       /*
3408        *	'r' is the number of bytes sent. This should be the number
3409        *	of bytes we asked to send, or -1 to indicate failure.
3410        */
3411       if (r > 0)
3412 	{
3413 	  entry->pos += r;
3414 	}
3415 
3416       /*
3417        *	If we haven't written all the data, it should have been
3418        *	because we blocked.  Anything else is a major problem
3419        *	so we remove the message from the queue.
3420        */
3421       if (entry->pos != entry->len)
3422 	{
3423 #if	defined(__MINGW__)
3424 	  if (WSAGetLastError() != WSAEWOULDBLOCK)
3425 #else
3426 	  if (errno != EWOULDBLOCK)
3427 #endif
3428 	    {
3429 	      if (debug)
3430 		{
3431 		  snprintf(ebuf, sizeof(ebuf),
3432 		    "failed sendto on %d for %s - %s",
3433 		    udp_desc, inet_ntoa(entry->addr.sin_addr), strerror(errno));
3434 		  gdomap_log(LOG_DEBUG);
3435 		}
3436 	      queue_pop();
3437 	    }
3438 	}
3439       else
3440 	{
3441 	  udp_sent++;
3442 	  if (debug > 1)
3443 	    {
3444 	      snprintf(ebuf, sizeof(ebuf), "performed sendto for %s",
3445 		inet_ntoa(entry->addr.sin_addr));
3446 	      gdomap_log(LOG_DEBUG);
3447 	    }
3448 	  /*
3449 	   *	If we have sent the entire message - remove it from queue.
3450 	   */
3451 	  if (entry->pos == entry->len)
3452 	    {
3453 	      queue_pop();
3454 	    }
3455 	}
3456     }
3457 }
3458 
3459 /*
3460  *	Name -		handle_write()
3461  *	Purpose -	Write data to a channel.  When all writing for the
3462  *			channel is complete, close the channel down.
3463  *
3464  *			This is all probably totally paranoid - the reply
3465  *			to any request is so short that the write operation
3466  *			should not block so there shouldn't be any need to
3467  *			handle non-blocking I/O.
3468  */
3469 static void
handle_write(int desc)3470 handle_write(int desc)
3471 {
3472   WInfo	*wi;
3473   char	*ptr;
3474   int	len;
3475   int	r;
3476 
3477   wi = getWInfo(desc, 0);
3478   if (wi == 0)
3479     {
3480       snprintf(ebuf, sizeof(ebuf),
3481 	"handle_write for unknown descriptor (%d)", desc);
3482       gdomap_log(LOG_ERR);
3483       return;
3484     }
3485   ptr = wi->buf;
3486   len = wi->len;
3487 
3488 #if	defined(__MINGW__)
3489   r = send(desc, &ptr[wi->pos], len - wi->pos, 0);
3490 #else
3491   r = write(desc, &ptr[wi->pos], len - wi->pos);
3492 #endif
3493   if (r < 0)
3494     {
3495       if (debug > 1)
3496 	{
3497 	  snprintf(ebuf, sizeof(ebuf),
3498 	    "Failed write on chan %d - closing", desc);
3499 	  gdomap_log(LOG_DEBUG);
3500 	}
3501       /*
3502        *	Failure - close connection silently.
3503        */
3504       clear_chan(desc);
3505     }
3506   else
3507     {
3508       wi->pos += r;
3509       if (wi->pos >= len)
3510 	{
3511 	  tcp_sent++;
3512 	  if (debug > 1)
3513 	    {
3514 	      snprintf(ebuf, sizeof(ebuf),
3515 		"Completed write on chan %d - closing", desc);
3516 	      gdomap_log(LOG_DEBUG);
3517 	    }
3518 	  /*
3519 	   *	Success - written all information.
3520 	   */
3521 	  clear_chan(desc);
3522 	}
3523     }
3524 }
3525 
3526 /*
3527  *	Name -		tryRead()
3528  *	Purpose -	Attempt to read from a non blocking channel.
3529  *			Time out in specified time.
3530  *			If length of data is zero then just wait for
3531  *			descriptor to be readable.
3532  *			If the length is negative then attempt to
3533  *			read the absolute value of length but return
3534  *			as soon as anything is read.
3535  *
3536  *			Return -1 on failure
3537  *			Return -2 on timeout
3538  *			Return number of bytes read
3539  */
3540 static int
tryRead(int desc,int tim,unsigned char * dat,int len)3541 tryRead(int desc, int tim, unsigned char* dat, int len)
3542 {
3543   struct timeval timeout;
3544   fd_set	fds;
3545   void		*to;
3546   int		rval;
3547   int		pos = 0;
3548   time_t	when = 0;
3549   int		neg = 0;
3550 
3551   if (len < 0)
3552     {
3553       neg = 1;
3554       len = -len;
3555     }
3556 
3557   /*
3558    *	First time round we do a select with an instant timeout to see
3559    *	if the descriptor is already readable.
3560    */
3561   timeout.tv_sec = 0;
3562   timeout.tv_usec = 0;
3563 
3564   for (;;)
3565     {
3566       to = &timeout;
3567       memset(&fds, '\0', sizeof(fds));
3568       FD_SET(desc, &fds);
3569 
3570       rval = select(FD_SETSIZE, &fds, 0, 0, to);
3571       if (rval == 0)
3572 	{
3573 	  time_t	now = time(0);
3574 
3575 	  if (when == 0)
3576 	    {
3577 	      when = now;
3578 	    }
3579 	  else if (now - when >= tim)
3580 	    {
3581 	      return -2;		/* Timed out.		*/
3582 	    }
3583 	  else
3584 	    {
3585 	      /*
3586 	       *	Set the timeout for a new call to select next time
3587 	       *	round the loop.
3588 	       */
3589 	      timeout.tv_sec = tim - (now - when);
3590 	      timeout.tv_usec = 0;
3591 	    }
3592 	}
3593       else if (rval < 0)
3594 	{
3595 	  return -1;		/* Error in select.	*/
3596 	}
3597       else if (len > 0)
3598 	{
3599 #if	defined(__MINGW__)
3600 	  rval = recv(desc, (char *)&dat[pos], len - pos, 0);
3601 #else
3602 	  rval = read(desc, &dat[pos], len - pos);
3603 #endif
3604 	  if (rval < 0)
3605 	    {
3606 #if	defined(__MINGW__)
3607 	      if (WSAGetLastError() != WSAEWOULDBLOCK)
3608 #else
3609 	      if (errno != EWOULDBLOCK)
3610 #endif
3611 		{
3612 		  return -1;		/* Error in read.	*/
3613 		}
3614 	    }
3615 	  else if (rval == 0)
3616 	    {
3617 	      return -1;		/* End of file.		*/
3618 	    }
3619 	  else
3620 	    {
3621 	      pos += rval;
3622 	      if (pos == len || neg == 1)
3623 		{
3624 		  return pos;	/* Read as needed.	*/
3625 		}
3626 	    }
3627 	}
3628       else
3629 	{
3630 	  return 0;	/* Not actually asked to read.	*/
3631 	}
3632     }
3633 }
3634 
3635 /*
3636  *	Name -		tryWrite()
3637  *	Purpose -	Attempt to write to a non blocking channel.
3638  *			Time out in specified time.
3639  *			If length of data is zero then just wait for
3640  *			descriptor to be writable.
3641  *			If the length is negative then attempt to
3642  *			write the absolute value of length but return
3643  *			as soon as anything is written.
3644  *
3645  *			Return -1 on failure
3646  *			Return -2 on timeout
3647  *			Return number of bytes written
3648  */
3649 static int
tryWrite(int desc,int tim,unsigned char * dat,int len)3650 tryWrite(int desc, int tim, unsigned char* dat, int len)
3651 {
3652   struct timeval timeout;
3653   fd_set	fds;
3654   void		*to;
3655   int		rval;
3656   int		pos = 0;
3657   time_t	when = 0;
3658   int		neg = 0;
3659 
3660   if (len < 0) {
3661     neg = 1;
3662     len = -len;
3663   }
3664 
3665   /*
3666    *	First time round we do a select with an instant timeout to see
3667    *	if the descriptor is already writable.
3668    */
3669   timeout.tv_sec = 0;
3670   timeout.tv_usec = 0;
3671 
3672   for (;;)
3673     {
3674       to = &timeout;
3675       memset(&fds, '\0', sizeof(fds));
3676       FD_SET(desc, &fds);
3677 
3678       rval = select(FD_SETSIZE, 0, &fds, 0, to);
3679       if (rval == 0)
3680 	{
3681 	  time_t	now = time(0);
3682 
3683 	  if (when == 0)
3684 	    {
3685 	      when = now;
3686 	    }
3687 	  else if (now - when >= tim)
3688 	    {
3689 	      return -2;		/* Timed out.		*/
3690 	    }
3691 	  else
3692 	    {
3693 	      /* Set the timeout for a new call to select next time round
3694 	       * the loop. */
3695 	      timeout.tv_sec = tim - (now - when);
3696 	      timeout.tv_usec = 0;
3697 	    }
3698 	}
3699       else if (rval < 0)
3700 	{
3701 	  return -1;		/* Error in select.	*/
3702 	}
3703       else if (len > 0)
3704 	{
3705 #if	defined(__MINGW__) /* FIXME: Is this correct? */
3706 	  rval = send(desc, (const char*)&dat[pos], len - pos, 0);
3707 #else
3708 	  void	(*ifun)();
3709 
3710 	  /*
3711 	   *	Should be able to write this short a message immediately, but
3712 	   *	if the connection is lost we will get a signal we must trap.
3713 	   */
3714 	  ifun = signal(SIGPIPE, (void(*)(int))SIG_IGN);
3715 	  rval = write(desc, &dat[pos], len - pos);
3716 	  signal(SIGPIPE, ifun);
3717 #endif
3718 
3719 	  if (rval <= 0)
3720 	    {
3721 #if	defined(__MINGW__)
3722 	      if (WSAGetLastError() != WSAEWOULDBLOCK)
3723 #else
3724 	      if (errno != EWOULDBLOCK)
3725 #endif
3726 		{
3727 		  return -1;		/* Error in write.	*/
3728 		}
3729 	    }
3730 	  else
3731 	    {
3732 	      pos += rval;
3733 	      if (pos == len || neg == 1)
3734 		{
3735 		  return pos;	/* Written as needed.	*/
3736 		}
3737 	    }
3738 	}
3739       else
3740 	{
3741 	  return 0;	/* Not actually asked to write.	*/
3742 	}
3743     }
3744 }
3745 
3746 /*
3747  *	Name -		tryHost()
3748  *	Purpose -	Perform a name server operation with a given
3749  *			request packet to a server at specified address.
3750  *			On error - return non-zero with reason in 'errno'
3751  */
3752 static int
tryHost(unsigned char op,unsigned char len,const unsigned char * name,int ptype,struct sockaddr_in * addr,unsigned short * p,uptr * v)3753 tryHost(unsigned char op, unsigned char len, const unsigned char *name,
3754 int ptype, struct sockaddr_in *addr, unsigned short *p, uptr *v)
3755 {
3756   int           desc = socket(AF_INET, SOCK_STREAM, 0);
3757   int	        e = 0;
3758   uint32_t	port = *p;
3759   gdo_req	msg;
3760   struct sockaddr_in sin;
3761 #if	defined(__MINGW__)
3762   uint32_t dummy;
3763 #endif /* __MINGW__ */
3764 
3765   *p = 0;
3766   if (desc < 0)
3767     {
3768       return 1;	/* Couldn't create socket.	*/
3769     }
3770 
3771 #if	defined(__MINGW__)
3772   dummy = 1;
3773   if (ioctlsocket(desc, FIONBIO, &dummy) < 0)
3774     {
3775       e = WSAGetLastError();
3776       closesocket(desc);
3777       WSASetLastError(e);
3778       return 2;	/* Couldn't set non-blocking.	*/
3779     }
3780 #else /* !__MINGW__ */
3781   if ((e = fcntl(desc, F_GETFL, 0)) >= 0)
3782     {
3783       e |= NBLK_OPT;
3784       if (fcntl(desc, F_SETFL, e) < 0)
3785 	{
3786 	  e = errno;
3787 	  close(desc);
3788 	  errno = e;
3789 	  return 2;	/* Couldn't set non-blocking.	*/
3790 	}
3791     }
3792   else
3793     {
3794       e = errno;
3795       close(desc);
3796       errno = e;
3797       return 2;	/* Couldn't set non-blocking.	*/
3798     }
3799 #endif /* __MINGW__ */
3800 
3801   memcpy(&sin, addr, sizeof(sin));
3802   if (connect(desc, (struct sockaddr*)&sin, sizeof(sin)) != 0)
3803     {
3804 #if	defined(__MINGW__)
3805       if (WSAGetLastError() == WSAEWOULDBLOCK)
3806 #else
3807       if (errno == EINPROGRESS)
3808 #endif
3809 	{
3810 	  e = tryWrite(desc, 10, 0, 0);
3811 	  if (e == -2)
3812 	    {
3813 	      e = errno;
3814 #if	defined(__MINGW__)
3815 	      closesocket(desc);
3816 #else
3817 	      close(desc);
3818 #endif
3819 	      errno = e;
3820 	      return 3;	/* Connect timed out.	*/
3821 	    }
3822 	  else if (e == -1)
3823 	    {
3824 	      e = errno;
3825 #if	defined(__MINGW__)
3826 	      closesocket(desc);
3827 #else
3828 	      close(desc);
3829 #endif
3830 	      errno = e;
3831 	      return 3;	/* Select failed.	*/
3832 	    }
3833 	}
3834       else
3835 	{
3836 	  e = errno;
3837 #if	defined(__MINGW__)
3838 	  closesocket(desc);
3839 #else
3840 	  close(desc);
3841 #endif
3842 	  errno = e;
3843 	  return 3;		/* Failed connect.	*/
3844 	}
3845     }
3846 
3847   memset((char*)&msg, '\0', GDO_REQ_SIZE);
3848   msg.rtype = op;
3849   msg.nsize = len;
3850   msg.ptype = ptype;
3851   if (op != GDO_REGISTER)
3852     {
3853       port = 0;
3854     }
3855   msg.port = htonl(port);
3856   if (name && len)
3857     {
3858       memcpy(msg.name, name, len);
3859     }
3860 
3861   e = tryWrite(desc, 10, (uptr)&msg, GDO_REQ_SIZE);
3862   if (e != GDO_REQ_SIZE)
3863     {
3864 #if	defined(__MINGW__)
3865       e = WSAGetLastError();
3866       closesocket(desc);
3867       WSASetLastError(e);
3868 #else
3869       e = errno;
3870       close(desc);
3871       errno = e;
3872 #endif
3873       return 4;
3874     }
3875   e = tryRead(desc, 3, (uptr)&port, 4);
3876   if (e != 4)
3877     {
3878 #if	defined(__MINGW__)
3879       e = WSAGetLastError();
3880       closesocket(desc);
3881       WSASetLastError(e);
3882 #else
3883       e = errno;
3884       close(desc);
3885       errno = e;
3886 #endif
3887       return 5;	/* Read timed out.	*/
3888     }
3889   port = ntohl(port);
3890 
3891   if (port > 0xffff)
3892     {
3893       if (GDO_NAMES == op)
3894         {
3895           if (port > 10000000)
3896             {
3897               snprintf(ebuf, sizeof(ebuf),
3898                 "Insanely large list of registered names");
3899               gdomap_log(LOG_ERR);
3900               close(desc);
3901               return 5;     // Unreasonable number of registrations
3902             }
3903         }
3904       else
3905         {
3906           snprintf(ebuf, sizeof(ebuf),
3907             "Port number of incoming message is out of range");
3908           gdomap_log(LOG_ERR);
3909           close(desc);
3910           return 5;     // Unreasonable port number
3911         }
3912     }
3913 
3914   /*
3915    *	Special case for GDO_SERVERS - allocate buffer and read list.
3916    */
3917   if (op == GDO_SERVERS)
3918     {
3919       int	len = port * sizeof(struct in_addr);
3920       uptr	b;
3921 
3922       b = (uptr)malloc(len);
3923       if (tryRead(desc, 3, b, len) != len)
3924 	{
3925 	  free(b);
3926 #if	defined(__MINGW__)
3927 	  e = WSAGetLastError();
3928 	  closesocket(desc);
3929 	  WSASetLastError(e);
3930 #else
3931 	  e = errno;
3932 	  close(desc);
3933 	  errno = e;
3934 #endif
3935 	  return 5;
3936 	}
3937       if (0 != v)
3938 	{
3939           *v = b;
3940 	}
3941     }
3942   /*
3943    *	Special case for GDO_NAMES - allocate buffer and read list.
3944    */
3945   else if (op == GDO_NAMES)
3946     {
3947       int	len = port;
3948       uptr	ptr;
3949       uptr	b;
3950 
3951       b = (uptr)malloc(len);
3952       if (tryRead(desc, 3, b, len) != len)
3953 	{
3954 	  free(b);
3955 #if	defined(__MINGW__)
3956 	  e = WSAGetLastError();
3957 	  closesocket(desc);
3958 	  WSASetLastError(e);
3959 #else
3960 	  e = errno;
3961 	  close(desc);
3962 	  errno = e;
3963 #endif
3964 	  return 5;
3965 	}
3966       /*
3967        * Count the number of registered names and return them.
3968        */
3969       ptr = b;
3970       port = 0;
3971       while (ptr < &b[len])
3972 	{
3973 	  ptr += 2 + ptr[0];
3974 	  port++;
3975 	}
3976       if ((port & 0xffff) != port)
3977 	{
3978 	  snprintf(ebuf, sizeof(ebuf),
3979 	    "Insanely large number of registered names");
3980 	  gdomap_log(LOG_ERR);
3981 	  port = 0;
3982 	}
3983       if (0 != v)
3984 	{
3985 	  *v = b;
3986 	}
3987     }
3988 
3989   *p = (unsigned short)port;
3990 #if	defined(__MINGW__)
3991   closesocket(desc);
3992 #else
3993   close(desc);
3994 #endif
3995   errno = 0;
3996   return 0;
3997 }
3998 
3999 /*
4000  *	Name -		nameFail()
4001  *	Purpose -	If given a failure status from tryHost()
4002  *			raise an appropriate exception.
4003  */
4004 static void
nameFail(int why)4005 nameFail(int why)
4006 {
4007   switch (why)
4008     {
4009       case 0:	break;
4010 
4011       case 1:
4012 	snprintf(ebuf, sizeof(ebuf),
4013 	  "failed to contact name server - socket - %s",
4014 	  strerror(errno));
4015 	gdomap_log(LOG_ERR);
4016         break;
4017 
4018       case 2:
4019 	snprintf(ebuf, sizeof(ebuf),
4020 	  "failed to contact name server - socket - %s",
4021 	  strerror(errno));
4022 	gdomap_log(LOG_ERR);
4023         break;
4024 
4025       case 3:
4026 	snprintf(ebuf, sizeof(ebuf),
4027 	  "failed to contact name server - socket - %s",
4028 	  strerror(errno));
4029 	gdomap_log(LOG_ERR);
4030         break;
4031 
4032       case 4:
4033 	snprintf(ebuf, sizeof(ebuf),
4034 	  "failed to contact name server - socket - %s",
4035 	  strerror(errno));
4036 	gdomap_log(LOG_ERR);
4037         break;
4038     }
4039 }
4040 
4041 /*
4042  *	Name -		nameServer()
4043  *	Purpose -	Perform name server lookup or registration.
4044  *			Return success/failure status and set up an
4045  *			address structure for use in bind or connect.
4046  *	Restrictions -	0xffff byte name limit
4047  *			Uses old style host lookup - only handles the
4048  *			primary network interface for each host!
4049  */
4050 static int
nameServer(const char * name,const char * host,int op,int ptype,struct sockaddr_in * addr,int pnum,int max)4051 nameServer(const char* name, const char* host, int op, int ptype, struct sockaddr_in* addr, int pnum, int max)
4052 {
4053   struct sockaddr_in	sin;
4054   unsigned short	p;
4055   unsigned short	port = 0;
4056   int			len = strlen(name);
4057   int			multi = 0;
4058   int			found = 0;
4059   int			rval;
4060   char			*first_dot = 0;
4061 
4062   if (len == 0)
4063     {
4064       snprintf(ebuf, sizeof(ebuf), "no name specified.");
4065       gdomap_log(LOG_ERR);
4066       return -1;
4067     }
4068   if (len > 0xffff)
4069     {
4070       snprintf(ebuf, sizeof(ebuf), "name length to large.");
4071       gdomap_log(LOG_ERR);
4072       return -1;
4073     }
4074 
4075   memset((char*)&sin, '\0', sizeof(sin));
4076   sin.sin_family = AF_INET;
4077 
4078 #if	GDOMAP_PORT_OVERRIDE
4079   p = htons(GDOMAP_PORT_OVERRIDE);
4080 #else
4081 {
4082   struct servent        *sp;
4083   /*
4084    *	Ensure we have port number to connect to name server.
4085    *	The TCP service name 'gdomap' overrides the default port.
4086    */
4087   if ((sp = getservbyname("gdomap", "tcp")) != 0)
4088     {
4089       p = sp->s_port;		/* Network byte order.	*/
4090     }
4091   else
4092     {
4093       p = htons(GDOMAP_PORT);
4094     }
4095 }
4096 #endif
4097   sin.sin_port = p;
4098 
4099   /*
4100    *	The host name '*' matches any host on the local network.
4101    */
4102   if (host && host[0] == '*' && host[1] == '\0')
4103     {
4104       multi = 1;
4105     }
4106   /*
4107    *	If no host name is given, we use the name of the local host.
4108    *	NB. This should always be the case for operations other than lookup.
4109    */
4110   if (multi || host == 0 || *host == '\0')
4111     {
4112       first_dot = strchr(local_hostname, '.');
4113       if (first_dot)
4114 	{
4115 	  *first_dot = '\0';
4116 	}
4117       host = local_hostname;
4118     }
4119 
4120 #if     HAVE_GETADDRINFO
4121   {
4122     struct addrinfo       hints;
4123     struct addrinfo       *info;
4124     int                   err;
4125 
4126     memset(&hints, '\0', sizeof(hints));
4127     hints.ai_family = AF_INET;
4128 
4129     if (getaddrinfo(host, NULL, &hints, &info) != 0 && first_dot != 0)
4130       {
4131         *first_dot = '.';
4132         if ((err = getaddrinfo(host, NULL, &hints, &info)) != 0)
4133           {
4134             snprintf(ebuf, sizeof(ebuf),
4135               "getaddrinfo('%s') failed: %s", host, gai_strerror(err));
4136             gdomap_log(LOG_ERR);
4137             return -1;
4138           }
4139       }
4140     sin.sin_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
4141     freeaddrinfo(info);
4142   }
4143 #else
4144   {
4145     struct hostent        *hp;
4146 
4147     if ((hp = gethostbyname(host)) == 0 && first_dot != 0)
4148       {
4149         *first_dot = '.';
4150         hp = gethostbyname(host);
4151       }
4152     if (hp == 0)
4153       {
4154         snprintf(ebuf, sizeof(ebuf),
4155           "gethostbyname('%s') failed: %s", host, strerror(errno));
4156         gdomap_log(LOG_ERR);
4157         return -1;
4158       }
4159     if (hp->h_addrtype != AF_INET)
4160       {
4161         snprintf(ebuf, sizeof(ebuf),
4162           "non-internet network not supported for %s", host);
4163         gdomap_log(LOG_ERR);
4164         return -1;
4165       }
4166     memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
4167   }
4168 #endif
4169 
4170   if (multi)
4171     {
4172       unsigned short	num;
4173       struct in_addr	*b;
4174 
4175       /*
4176        * A host name of '*' is a special case which should do lookup on
4177        * all machines on the local network until one is found which has
4178        * the specified server on it.
4179        */
4180       rval = tryHost(GDO_SERVERS, 0, 0, ptype, &sin, &num, (uptr*)&b);
4181       if (0 == rval)
4182 	{
4183 	  int	i;
4184 
4185 	  for (i = 0; found == 0 && i < num; i++)
4186 	    {
4187 	      memset((char*)&sin, '\0', sizeof(sin));
4188 	      sin.sin_family = AF_INET;
4189 	      sin.sin_port = p;
4190 	      memcpy(&sin.sin_addr, &b[i], sizeof(struct in_addr));
4191 	      if (sin.sin_addr.s_addr == 0)
4192 		{
4193 		  continue;
4194 		}
4195 
4196 	      if (tryHost(GDO_LOOKUP, len, (unsigned char*)name,
4197 		ptype, &sin, &port, 0)==0)
4198 		{
4199 		  if (port != 0)
4200 		    {
4201 		      memset((char*)&addr[found], '\0', sizeof(*addr));
4202 		      memcpy(&addr[found].sin_addr, &sin.sin_addr,
4203 			sizeof(sin.sin_addr));
4204 		      addr[found].sin_family = AF_INET;
4205 		      addr[found].sin_port = htons(port);
4206 		      found++;
4207 		      if (found == max)
4208 			{
4209 			  break;
4210 			}
4211 		    }
4212 		}
4213 	    }
4214 	  free(b);
4215 	  return found;
4216 	}
4217       else
4218 	{
4219 	  snprintf(ebuf, sizeof(ebuf),
4220 	    "failed to contact gdomap on %s(%s) - %s",
4221 	    local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4222 	  gdomap_log(LOG_ERR);
4223 	  return -1;
4224 	}
4225     }
4226   else
4227     {
4228       if (op == GDO_REGISTER)
4229 	{
4230 	  port = (unsigned short)pnum;
4231 	  if (port == 0 || htons(port) == p)
4232 	    {
4233 	      snprintf(ebuf, sizeof(ebuf),
4234 	        "attempted registration with bad port (%d).", port);
4235 	      gdomap_log(LOG_ERR);
4236 	      return -1;
4237 	    }
4238 	}
4239       rval = tryHost(op, len, (unsigned char*)name, ptype, &sin, &port, 0);
4240       if (rval != 0)
4241 	{
4242 	  snprintf(ebuf, sizeof(ebuf),
4243 	    "failed to contact gdomap on %s(%s) - %s",
4244 	    local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4245 	  gdomap_log(LOG_ERR);
4246 	  return -1;
4247 	}
4248       nameFail(rval);
4249     }
4250 
4251   if (op == GDO_REGISTER)
4252     {
4253       if (port == 0 || (pnum != 0 && port != pnum))
4254 	{
4255 	  snprintf(ebuf, sizeof(ebuf),
4256 	    "service already registered.");
4257 	  gdomap_log(LOG_ERR);
4258 	  return -1;
4259 	}
4260     }
4261   if (port == 0)
4262     {
4263       return 0;
4264     }
4265   memset((char*)addr, '\0', sizeof(*addr));
4266   memcpy(&addr->sin_addr, &sin.sin_addr, sizeof(sin.sin_addr));
4267   addr->sin_family = AF_INET;
4268   addr->sin_port = htons(port);
4269   return 1;
4270 }
4271 
4272 static void
lookup(const char * name,const char * host,int ptype)4273 lookup(const char *name, const char *host, int ptype)
4274 {
4275   struct sockaddr_in	sin[100];
4276   int			found;
4277   int			i;
4278 
4279   found = nameServer(name, host, GDO_LOOKUP, ptype, sin, 0, 100);
4280   for (i = 0; i < found; i++)
4281     {
4282       snprintf(ebuf, sizeof(ebuf), "Found %s on '%s' port %d", name,
4283 	inet_ntoa(sin[i].sin_addr), ntohs(sin[i].sin_port));
4284       gdomap_log(LOG_INFO);
4285     }
4286   if (found == 0)
4287     {
4288       snprintf(ebuf, sizeof(ebuf), "Unable to find %s.", name);
4289       gdomap_log(LOG_INFO);
4290     }
4291 }
4292 
4293 static void
donames(const char * host)4294 donames(const char *host)
4295 {
4296   struct sockaddr_in	sin;
4297   unsigned short	p;
4298   unsigned short	num = 0;
4299   int			rval;
4300   uptr			b;
4301   char			*first_dot = 0;
4302 
4303   if (host == 0 || *host == '\0')
4304     {
4305       /*
4306        * If no host name is given, we use the name of the local host.
4307        */
4308       first_dot = strchr(local_hostname, '.');
4309       if (first_dot)
4310 	{
4311 	  *first_dot = '\0';
4312 	}
4313       host = local_hostname;
4314     }
4315 
4316   memset((char*)&sin, '\0', sizeof(sin));
4317   sin.sin_family = AF_INET;
4318 
4319 #if	GDOMAP_PORT_OVERRIDE
4320   p = htons(GDOMAP_PORT_OVERRIDE);
4321 #else
4322   {
4323     struct servent      *sp;
4324     /*
4325      *	Ensure we have port number to connect to name server.
4326      *	The TCP service name 'gdomap' overrides the default port.
4327      */
4328     if ((sp = getservbyname("gdomap", "tcp")) != 0)
4329       {
4330         p = sp->s_port;		/* Network byte order.	*/
4331       }
4332     else
4333       {
4334         p = htons(GDOMAP_PORT);
4335       }
4336   }
4337 #endif
4338 
4339   sin.sin_port = p;
4340 
4341 #if     HAVE_GETADDRINFO
4342   {
4343     struct addrinfo       hints;
4344     struct addrinfo       *info;
4345     int                   err;
4346 
4347     memset(&hints, '\0', sizeof(hints));
4348     hints.ai_family = AF_INET;
4349 
4350     if ((err = getaddrinfo(host, NULL, &hints, &info) != 0) && first_dot != 0)
4351       {
4352         *first_dot = '.';
4353         err = getaddrinfo(host, NULL, &hints, &info);
4354       }
4355     if (err != 0)
4356     {
4357         snprintf(ebuf, sizeof(ebuf),
4358           "getaddrinfo('%s') failed: %s", host, gai_strerror(err));
4359         gdomap_log(LOG_ERR);
4360         return;
4361     }
4362     sin.sin_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
4363     freeaddrinfo(info);
4364   }
4365 #else
4366   {
4367     struct hostent        *hp;
4368 
4369     if ((hp = gethostbyname(host)) == 0 && first_dot != 0)
4370       {
4371         *first_dot = '.';
4372         hp = gethostbyname(host);
4373       }
4374     if (hp == 0)
4375       {
4376         snprintf(ebuf, sizeof(ebuf),
4377           "gethostbyname('%s') failed: %s", host, strerror(errno));
4378         gdomap_log(LOG_ERR);
4379         return;
4380       }
4381     if (hp->h_addrtype != AF_INET)
4382       {
4383         snprintf(ebuf, sizeof(ebuf),
4384           "non-internet network not supported for %s", host);
4385         gdomap_log(LOG_ERR);
4386         return;
4387       }
4388 
4389     memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
4390   }
4391 #endif
4392 
4393   rval = tryHost(GDO_NAMES, 0, 0, 0, &sin, &num, (uptr*)&b);
4394   if (rval != 0)
4395     {
4396       snprintf(ebuf, sizeof(ebuf), "failed to contact gdomap on %s(%s) - %s",
4397         local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4398       gdomap_log(LOG_ERR);
4399       return;
4400     }
4401   if (num == 0)
4402     {
4403       snprintf(ebuf, sizeof(ebuf), "No names currently registered with gdomap");
4404       gdomap_log(LOG_INFO);
4405     }
4406   else
4407     {
4408       uptr	p = b;
4409 
4410       snprintf(ebuf, sizeof(ebuf), "Registered names are -");
4411       gdomap_log(LOG_INFO);
4412       while (num-- > 0)
4413 	{
4414 	  char	buf[256];
4415 
4416 	  memcpy(buf, &p[2], p[0]);
4417 	  buf[p[0]] = '\0';
4418 	  snprintf(ebuf, sizeof(ebuf), "  %s", buf);
4419 	  gdomap_log(LOG_INFO);
4420 	  p += 2 + p[0];
4421 	}
4422     }
4423   free(b);
4424 }
4425 
4426 static void
doservers(const char * host)4427 doservers(const char *host)
4428 {
4429   struct sockaddr_in	sin;
4430   unsigned short	p;
4431   unsigned short	num = 0;
4432   int			rval;
4433   uptr			b;
4434   char			*first_dot = 0;
4435 
4436   if (host == 0 || *host == '\0')
4437     {
4438       /*
4439        * If no host name is given, we use the name of the local host.
4440        */
4441       first_dot = strchr(local_hostname, '.');
4442       if (first_dot)
4443 	{
4444 	  *first_dot = '\0';
4445 	}
4446       host = local_hostname;
4447     }
4448 
4449   memset((char*)&sin, '\0', sizeof(sin));
4450   sin.sin_family = AF_INET;
4451 
4452 #if	GDOMAP_PORT_OVERRIDE
4453   p = htons(GDOMAP_PORT_OVERRIDE);
4454 #else
4455   {
4456     struct servent      *sp;
4457     /*
4458      *	Ensure we have port number to connect to name server.
4459      *	The TCP service name 'gdomap' overrides the default port.
4460      */
4461     if ((sp = getservbyname("gdomap", "tcp")) != 0)
4462       {
4463         p = sp->s_port;		/* Network byte order.	*/
4464       }
4465     else
4466       {
4467         p = htons(GDOMAP_PORT);
4468       }
4469   }
4470 #endif
4471 
4472   sin.sin_port = p;
4473 
4474 #if     HAVE_GETADDRINFO
4475   {
4476     struct addrinfo       hints;
4477     struct addrinfo       *info;
4478     int                   err;
4479 
4480     memset(&hints, '\0', sizeof(hints));
4481     hints.ai_family = AF_INET;
4482 
4483     if ((err = getaddrinfo(host, NULL, &hints, &info) != 0) && first_dot != 0)
4484       {
4485         *first_dot = '.';
4486         err = getaddrinfo(host, NULL, &hints, &info);
4487       }
4488     if (err != 0)
4489     {
4490         snprintf(ebuf, sizeof(ebuf),
4491           "getaddrinfo('%s') failed: %s", host, gai_strerror(err));
4492         gdomap_log(LOG_ERR);
4493         return;
4494     }
4495     sin.sin_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
4496     freeaddrinfo(info);
4497   }
4498 #else
4499   {
4500     struct hostent        *hp;
4501 
4502     if ((hp = gethostbyname(host)) == 0 && first_dot != 0)
4503       {
4504         *first_dot = '.';
4505         hp = gethostbyname(host);
4506       }
4507     if (hp == 0)
4508       {
4509         snprintf(ebuf, sizeof(ebuf),
4510           "gethostbyname('%s') failed: %s", host, strerror(errno));
4511         gdomap_log(LOG_ERR);
4512         return;
4513       }
4514     if (hp->h_addrtype != AF_INET)
4515       {
4516         snprintf(ebuf, sizeof(ebuf),
4517           "non-internet network not supported for %s", host);
4518         gdomap_log(LOG_ERR);
4519         return;
4520       }
4521 
4522     memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
4523   }
4524 #endif
4525 
4526   rval = tryHost(GDO_SERVERS, 0, 0, 0, &sin, &num, (uptr*)&b);
4527   if (rval != 0)
4528     {
4529       snprintf(ebuf, sizeof(ebuf), "failed to contact gdomap on %s(%s) - %s",
4530         local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4531       gdomap_log(LOG_ERR);
4532       return;
4533     }
4534   if (num == 0)
4535     {
4536       snprintf(ebuf, sizeof(ebuf), "No servers currently known to gdomap");
4537       gdomap_log(LOG_INFO);
4538     }
4539   else
4540     {
4541       struct in_addr	*p = (struct in_addr*)(b + 4);
4542 
4543       snprintf(ebuf, sizeof(ebuf), "Known servers are -");
4544       gdomap_log(LOG_INFO);
4545       while (num-- > 0)
4546 	{
4547 	  snprintf(ebuf, sizeof(ebuf), "  %s", inet_ntoa(*p));
4548 	  gdomap_log(LOG_INFO);
4549 	  p++;
4550 	}
4551     }
4552   free(b);
4553 }
4554 
4555 static void
doregister(const char * name,int port,int ptype)4556 doregister(const char *name, int port, int ptype)
4557 {
4558   struct sockaddr_in	sin;
4559   int			found;
4560   int			i;
4561 
4562   found = nameServer(name, 0, GDO_REGISTER, ptype, &sin, port, 1);
4563   for (i = 0; i < found; i++)
4564     {
4565       snprintf(ebuf, sizeof(ebuf), "Registered %s on '%s' port %d", name,
4566 	inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
4567       gdomap_log(LOG_INFO);
4568     }
4569   if (found == 0)
4570     {
4571       snprintf(ebuf, sizeof(ebuf),
4572 	"Unable to register %s on port %d.", name, port);
4573       gdomap_log(LOG_ERR);
4574     }
4575 }
4576 
4577 static void
unregister(const char * name,int port,int ptype)4578 unregister(const char *name, int port, int ptype)
4579 {
4580   struct sockaddr_in	sin;
4581   int			found;
4582   int			i;
4583 
4584   found = nameServer(name, 0, GDO_UNREG, ptype, &sin, port, 1);
4585   for (i = 0; i < found; i++)
4586     {
4587       snprintf(ebuf, sizeof(ebuf), "Unregistered %s on '%s' port %d", name,
4588 	inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
4589       gdomap_log(LOG_INFO);
4590     }
4591   if (found == 0)
4592     {
4593       snprintf(ebuf, sizeof(ebuf), "Unable to unregister %s.", name);
4594       gdomap_log(LOG_INFO);
4595     }
4596 }
4597 
do_help(int argc,char ** argv,char * options)4598 static void do_help(int argc, char **argv, char *options)
4599 {
4600   /*
4601    * Where argc > 0 we check to see if there is a '--help' argument
4602    * and do nothing if there isn't.
4603    */
4604   if (argc > 0)
4605     {
4606       int	i;
4607 
4608       for (i = 1; i < argc; i++)
4609 	{
4610 	  if (strcmp(argv[i], "--help") == 0)
4611 	    {
4612 	      break;
4613 	    }
4614 	}
4615       if (i == argc)
4616 	{
4617 	  return;	// --help not found ...
4618 	}
4619     }
4620   printf("%s -[%s]\n", argv[0], options);
4621   printf("GNU Distributed Objects name server\n");
4622   printf("-C		help about interfaces and configuration\n");
4623   printf("-H		general help\n");
4624   printf("-I		pid file to write pid\n");
4625   printf("-L name		perform lookup for name then quit.\n");
4626   printf("-M name		machine name for -L and -N\n");
4627   printf("-N		list all names registered on host\n");
4628   printf("-P number	port number required for R option.\n");
4629   printf("-R name		register name locally then quit.\n");
4630   printf("-S		list all gdomap servers known to host\n");
4631   printf("-T type		port type for L, R and U options -\n");
4632   printf("		tcp_gdo, udp_gdo,\n");
4633   printf("		tcp_foreign, udp_foreign.\n");
4634   printf("-U name		unregister name locally then quit.\n");
4635   printf("-a file		use config file for interface list.\n");
4636   printf("-c file		use config file for probe.\n");
4637   printf("-d		extra debug logging (normally via syslog).\n");
4638   printf("-f		avoid fork() to make debugging easy\n");
4639   printf("-i seconds	re-probe at this interval (roughly), min 60\n");
4640 #if	!defined(__MINGW__)
4641   printf("-j path		specify a jail directory the process is to\n");
4642   printf("		run in (if omitted, /tmp is used).\n");
4643 #endif
4644   printf("-p		disable probing for other servers\n");
4645   printf("\n");
4646   printf("Kill with SIGUSR1 to obtain a dump of all known peers\n");
4647   printf("in /tmp/gdomap.dump\n");
4648   printf("\n");
4649   exit(EXIT_SUCCESS);
4650 }
4651 
4652 #if	defined(__MINGW__)
4653 static char*
quoteArg(const char * arg)4654 quoteArg(const char *arg)
4655 {
4656   int	len = strlen(arg);
4657   int	in;
4658   int	out = 0;
4659   int	quote = 0;
4660   char	*ptr = malloc(len*2+3);
4661 
4662   /*
4663    * Check for white space ... if present, must quote argument.
4664    */
4665   for (in = 0; in < len; in++)
4666     {
4667       if (isspace(arg[in]))
4668 	{
4669 	  quote = 1;
4670 	  break;
4671 	}
4672     }
4673 
4674   if (quote)
4675     {
4676       ptr[out++] = '"';
4677     }
4678 
4679   for (in = 0; in < len; in++)
4680     {
4681       if (arg[in] == '\\')
4682 	{
4683 	  int	pos = in + 1;
4684 
4685 	  // Step past any backslashes
4686 	  while (pos < len && ptr[pos] == '\\')
4687 	    {
4688 	      pos++;
4689 	    }
4690 	  // If backslashes precede a quote ... double them.
4691 	  if (pos < len && ptr[pos] == '"')
4692 	    {
4693 	      int	num = pos - in;
4694 
4695 	      while (num-- > 0)
4696 		{
4697 		  ptr[out++] = '\\';
4698 		}
4699 	    }
4700 	  // Copy the original backslashes
4701 	  while (in < pos)
4702 	    {
4703 	      ptr[out++] = arg[in++];
4704 	    }
4705 	  // Copy the character after the backslashes
4706 	  if (in < len)
4707 	    {
4708 	      ptr[out++] = arg[in];
4709 	    }
4710 	}
4711       else if (arg[in] == '"')
4712 	{
4713 	  ptr[out++] = '\\';	// Escape the quote.
4714 	  ptr[out++] = arg[in];
4715 	}
4716       else
4717 	{
4718 	  ptr[out++] = arg[in];
4719 	}
4720     }
4721 
4722 
4723   if (quote)
4724     {
4725       ptr[out++] = '"';
4726     }
4727 
4728   ptr[out] = '\0';
4729 
4730   return ptr;
4731 }
4732 #endif
4733 
4734 /**
4735  * (A dummy comment to help autogsdoc realize this is a command-line tool.)
4736  */
4737 #if	GS_FAKE_MAIN
4738 /* Since we don't link gnustep-base, the main function below has to be
4739  * the real main function. */
4740 #undef	main
4741 #endif
4742 int
main(int argc,char ** argv)4743 main(int argc, char** argv)
4744 {
4745   extern char	*optarg;
4746 #if	defined(__MINGW__)
4747   char	*options = "-CHI:L:M:NP:R:ST:U:a:bc:dfi:p";
4748 #else
4749   char	*options = "-CHI:L:M:NP:R:ST:U:a:bc:dfi:j:p";
4750   const char    *jail = 0;
4751 #endif
4752   int		c;
4753   int		ptype = GDO_TCP_GDO;
4754   int		port = 0;
4755   const char	*machine = 0;
4756   const char	*lookupf = 0;
4757   int		donamesf = 0;
4758   int		doserversf = 0;
4759 
4760 #if	defined(__MINGW__)
4761   WORD wVersionRequested;
4762   WSADATA wsaData;
4763 
4764   wVersionRequested = MAKEWORD(2, 2);
4765   WSAStartup(wVersionRequested, &wsaData);
4766 #else
4767   int           forked = 0;
4768 #endif
4769 
4770   local_hostname = xgethostname();
4771   if (!local_hostname)
4772     {
4773       snprintf(ebuf, sizeof(ebuf),
4774 	"gethostname() failed: %s", strerror(errno));
4775       gdomap_log(LOG_CRIT);
4776       exit(EXIT_FAILURE);
4777     }
4778 
4779   /*
4780    *	Would use inet_aton(), but older systems don't have it.
4781    */
4782   loopback.s_addr = inet_addr("127.0.0.1");
4783 #if	defined(__MINGW__)
4784   class_a_net = IN_CLASSA_NET;
4785   class_a_mask.s_addr = class_a_net;
4786   class_b_net = IN_CLASSB_NET;
4787   class_b_mask.s_addr = class_b_net;
4788   class_c_net = IN_CLASSC_NET;
4789   class_c_mask.s_addr = class_c_net;
4790 #else
4791   class_a_net = inet_network("255.0.0.0");
4792   class_a_mask = inet_makeaddr(class_a_net, 0);
4793   class_b_net = inet_network("255.255.0.0");
4794   class_b_mask = inet_makeaddr(class_b_net, 0);
4795   class_c_net = inet_network("255.255.255.0");
4796   class_c_mask = inet_makeaddr(class_c_net, 0);
4797 #endif
4798 
4799   do_help(argc, argv, options);
4800   while ((c = getopt(argc, argv, options)) != -1)
4801     {
4802       switch(c)
4803 	{
4804 	  case 'H':
4805 	    do_help(0, argv, options);
4806 	    exit(EXIT_SUCCESS);
4807 
4808 	  case 'C':
4809 	    printf("\n");
4810 	    printf(
4811 "Gdomap normally probes every machine on the local network to see if there\n"
4812 "is a copy of gdomap running on it.  This is done for class-C networks and\n"
4813 "subnets of class-C networks.  If your host is on a class-B or class-A net\n"
4814 "then the default behaviour is to treat it as a class-C net and probe only\n"
4815 "the hosts that would be expected on a class-C network of the same number.\n");
4816 	    printf("\n");
4817 	    printf(
4818 "If you are running on a class-A or class-B network, or if your net has a\n"
4819 "large number of hosts which will not have gdomap on them - you may want to\n"
4820 "supply a configuration file listing the hosts to be probed explicitly,\n"
4821 "rather than getting gdomap to probe all hosts on the local net.\n");
4822 	    printf("\n");
4823 	    printf(
4824 "You may also want to supply the configuration file so that hosts which are\n"
4825 "not actually on your local network can still be found when your code tries\n"
4826 "to connect to a host using @\"*\" as the host name.  NB. this functionality\n"
4827 "does not exist in OpenStep.\n");
4828 	    printf("\n");
4829 	    printf(
4830 "A configuration file consists of a list of IP addresses to be probed.\n"
4831 "The IP addresses should be in standard 'dot' notation, one per line.\n"
4832 "Empty lines are permitted in the configuration file.\n"
4833 "Anything on a line after a hash ('#') is ignored.\n"
4834 "You tell gdomap about the config file with the '-c' command line option.\n");
4835 	    printf("\n");
4836 	    printf("\n");
4837 printf(
4838 "gdomap uses the SIOCGIFCONF ioctl to build a list of IP addresses and\n"
4839 "netmasks for the network interface cards on your machine.  On some operating\n"
4840 "systems, this facility is not available (or is broken), so you must tell\n"
4841 "gdomap the addresses and masks of the interfaces using the '-a' command line\n"
4842 "option.  The file named with '-a' should contain a series of lines with\n"
4843 "space separated pairs of addresses and masks in 'dot' notation, eg.\n"
4844 "192.168.1.2 255.255.255.0\n"
4845 "You must NOT include loopback interfaces in this list.\n"
4846 "If you want to support broadcasting of probe information on a network,\n"
4847 "you may supply the broadcast address as a third item on the line, eg.\n"
4848 "192.168.1.9 255.255.255.0 192.168.1.255\n"
4849 "If your operating system has some other method of giving you a list of\n"
4850 "network interfaces and masks, please send me example code so that I can\n"
4851 "implement it in gdomap.\n");
4852 	    printf("\n");
4853 	    exit(EXIT_SUCCESS);
4854 
4855 	  case 'L':
4856 	    lookupf = optarg;
4857 	    break;
4858 
4859 	  case 'M':
4860 	    machine = optarg;
4861 	    break;
4862 
4863 	  case 'N':
4864 	    donamesf = 1;
4865 	    break;
4866 
4867 	  case 'P':
4868 	    port = atoi(optarg);
4869 	    break;
4870 
4871 	  case 'R':
4872 	    if (machine && *machine)
4873 	      {
4874 		fprintf(stderr, "-M flag is ignored for registration.\n");
4875 		fprintf(stderr, "Registration will take place locally.\n");
4876 	      }
4877 	    doregister(optarg, port, ptype);
4878 	    exit(EXIT_SUCCESS);
4879 
4880 	  case 'S':
4881 	    doserversf = 1;
4882 	    break;
4883 
4884 	  case 'T':
4885 	    if (strcmp(optarg, "tcp_gdo") == 0)
4886 	      {
4887 		ptype = GDO_TCP_GDO;
4888 	      }
4889 	    else if (strcmp(optarg, "udp_gdo") == 0)
4890 	      {
4891 		ptype = GDO_UDP_GDO;
4892 	      }
4893 	    else if (strcmp(optarg, "tcp_foreign") == 0)
4894 	      {
4895 		ptype = GDO_TCP_FOREIGN;
4896 	      }
4897 	    else if (strcmp(optarg, "udp_foreign") == 0)
4898 	      {
4899 		ptype = GDO_UDP_FOREIGN;
4900 	      }
4901 	    else
4902 	      {
4903 		fprintf(stderr, "Warning - -P selected unknown type -");
4904 		fprintf(stderr, " using tcp_gdo.\n");
4905 		ptype = GDO_TCP_GDO;
4906 	      }
4907 	    break;
4908 
4909 	  case 'U':
4910 	    if (machine && *machine)
4911 	      {
4912 		fprintf(stderr, "-M flag is ignored for unregistration.\n");
4913 		fprintf(stderr, "Operation will take place locally.\n");
4914 	      }
4915 	    unregister(optarg, port, ptype);
4916 	    exit(EXIT_SUCCESS);
4917 
4918 	  case 'a':
4919 	    load_iface(optarg);
4920 	    break;
4921 
4922 	  case 'b':
4923 	    nobcst++;
4924 	    break;
4925 
4926 	  case 'c':
4927 	    {
4928 	      FILE	*fptr;
4929 	      int	line = 0;
4930 	      int	count = 0;
4931 	      char	buf[128];
4932 
4933 	      in_config = 1;
4934               /* First see if we *can* access the file.
4935                */
4936 	      fptr = fopen(optarg, "rt");
4937 	      if (fptr == 0)
4938 		{
4939 		  snprintf(ebuf, sizeof(ebuf),
4940 		    "Unable to open probe config - '%s'\n",
4941 		    optarg);
4942 		  gdomap_log(LOG_CRIT);
4943 		  exit(EXIT_FAILURE);
4944 		}
4945               /* Now check that we *should* be accessing it.
4946                */
4947 	      if (access(optarg, R_OK) != 0)
4948 		{
4949                   fclose(fptr);
4950 		  snprintf(ebuf, sizeof(ebuf),
4951 		    "Unable to access probe config - '%s'\n",
4952 		    optarg);
4953 		  gdomap_log(LOG_CRIT);
4954 		  exit(EXIT_FAILURE);
4955 		}
4956 	      while (fgets(buf, sizeof(buf), fptr) != 0)
4957 		{
4958 		  char		*ptr = buf;
4959 		  plentry	*prb;
4960 
4961 		  line++;
4962 		  /*
4963 		   *	Strip leading white space.
4964 		   */
4965 		  while (isspace(*ptr))
4966 		    {
4967 		      ptr++;
4968 		    }
4969 		  if (ptr != buf)
4970 		    {
4971 		      strcpy(buf, ptr);
4972 		    }
4973 		  /*
4974 		   *	Strip comments.
4975 		   */
4976 		  ptr = strchr(buf, '#');
4977 		  if (ptr)
4978 		    {
4979 		      *ptr = '\0';
4980 		    }
4981 		  /*
4982 		   *	Strip trailing white space.
4983 		   */
4984 		  ptr = buf;
4985 		  while (*ptr)
4986 		    {
4987 		      ptr++;
4988 		    }
4989 		  while (ptr > buf && isspace(ptr[-1]))
4990 		    {
4991 		      ptr--;
4992 		    }
4993 		  *ptr = '\0';
4994 		  /*
4995 		   *	Ignore blank lines.
4996 		   */
4997 		  if (*buf == '\0')
4998 		    {
4999 		      continue;
5000 		    }
5001 
5002 		  if (count++ > 1000)
5003 		    {
5004 		      snprintf(ebuf, sizeof(ebuf),
5005 			"Too many probe configurations found");
5006 		      gdomap_log(LOG_CRIT);
5007 		      exit(EXIT_FAILURE);
5008 		    }
5009 		  prb = (plentry*)malloc(sizeof(plentry));
5010 		  memset((char*)prb, '\0', sizeof(plentry));
5011 		  prb->addr.s_addr = inet_addr(buf);
5012 		  if (prb->addr.s_addr == (uint32_t)-1)
5013 		    {
5014 		      snprintf(ebuf, sizeof(ebuf),
5015 			"line %d of '%s' (%s) is not a valid address\n",
5016 			line, optarg, buf);
5017 		      free(prb);
5018 		      gdomap_log(LOG_CRIT);
5019 		      exit(EXIT_FAILURE);
5020 		    }
5021 		  else
5022 		    {
5023 		      /*
5024 		       *	Add this address at the end of the list.
5025 		       */
5026 		      if (plist == 0)
5027 			{
5028 			  plist = prb;
5029 			}
5030 		      else
5031 			{
5032 			  plentry	*tmp = plist;
5033 
5034 			  while (tmp->next)
5035 			    {
5036 			      if (tmp->addr.s_addr == prb->addr.s_addr)
5037 				{
5038 				  snprintf(ebuf, sizeof(ebuf),
5039 				    "'%s' repeat in '%s'\n",
5040 				    buf, optarg);
5041 				  free(prb);
5042 				  gdomap_log(LOG_CRIT);
5043 				  exit(EXIT_FAILURE);
5044 				  break;
5045 				}
5046 			      tmp = tmp->next;
5047 			    }
5048 			  if (tmp->next == 0)
5049 			    {
5050 			      tmp->next = prb;
5051 			    }
5052 			}
5053 		    }
5054 		}
5055 	      fclose(fptr);
5056 	      in_config = 0;
5057 	    }
5058 	    break;
5059 
5060 	  case 'I':
5061 	    pidfile = optarg;
5062 	    break;
5063 
5064 	  case 'd':
5065 	    debug++;
5066 	    break;
5067 
5068 	  case 'f':
5069 	    nofork++;
5070 	    break;
5071 
5072 	  case 'i':
5073 	    interval = atoi(optarg);
5074 	    if (interval < 60)
5075 	      {
5076 		interval = 60;
5077 	      }
5078 	    break;
5079 
5080 #if	!defined(__MINGW__)
5081 	  case 'j':
5082 	    jail = optarg;
5083             break;
5084 #endif
5085 
5086 	  case 'p':
5087 	    noprobe++;
5088 	    break;
5089 
5090 	  default:
5091 	    printf("%s - GNU Distributed Objects name server\n", argv[0]);
5092 	    printf("-H	for help\n");
5093 	    exit(EXIT_SUCCESS);
5094 	}
5095     }
5096   if (donamesf || doserversf || lookupf)
5097     {
5098       if (donamesf)
5099 	{
5100 	  donames(machine);
5101 	}
5102       if (doserversf)
5103 	{
5104 	  doservers(machine);
5105 	}
5106       if (lookupf)
5107 	{
5108 	  lookup(lookupf, machine, ptype);
5109 	}
5110       exit (0);
5111     }
5112 
5113 #if	defined(__MINGW__) /* On Win32, we don't fork */
5114   if (nofork == 0)
5115     {
5116       char	**a = malloc((argc+2) * sizeof(char*));
5117       int	i;
5118 
5119       for (i = 0; i < argc; i++)
5120 	{
5121 	  a[i] = quoteArg(argv[i]);
5122 	}
5123       a[argc] = "-f";
5124       a[argc+1] = 0;
5125       if (_spawnv(_P_NOWAIT, argv[0], (const char* const*)a) == -1)
5126 	{
5127 	  fprintf(stderr, "gdomap - spawn '%s' failed - bye.\n", argv[0]);
5128 	  exit(EXIT_FAILURE);
5129 	}
5130       if (debug)
5131         {
5132 	  snprintf(ebuf, sizeof(ebuf), "initialisation complete.");
5133 	  gdomap_log(LOG_DEBUG);
5134         }
5135       exit(EXIT_SUCCESS);
5136     }
5137 #else
5138   if (nofork == 0)
5139     {
5140       /*
5141        *	Now fork off child process to run in background.
5142        */
5143       switch (fork())
5144 	{
5145 	  case -1:
5146 	    fprintf(stderr, "gdomap - fork failed - bye.\n");
5147 	    exit(EXIT_FAILURE);
5148 
5149 	  case 0:
5150 	    /*
5151 	     *	Try to run in background.
5152 	     */
5153           forked = 1;
5154 #if	defined(NeXT)
5155 	    setpgrp(0, getpid());
5156 #else
5157 	    setsid();
5158 #endif
5159 	    break;
5160 
5161 	  default:
5162 	    if (debug)
5163 	      {
5164 		snprintf(ebuf, sizeof(ebuf), "initialisation complete.");
5165 		gdomap_log(LOG_DEBUG);
5166 	      }
5167 	    exit(EXIT_SUCCESS);
5168 	}
5169     }
5170 
5171   /*
5172    *	Ensure we don't have any open file descriptors which may refer
5173    *	to sockets bound to ports we may try to use.
5174    *
5175    *	Use '/dev/null' for stdin and stdout.  Assume stderr is ok.
5176    */
5177   for (c = 0; c < FD_SETSIZE; c++)
5178     {
5179       if (is_daemon || (c != 2))
5180 	{
5181 	  (void)close(c);
5182 	}
5183     }
5184   if (open("/dev/null", O_RDONLY) != 0)
5185     {
5186       snprintf(ebuf, sizeof(ebuf),
5187 	"failed to open stdin from /dev/null (%s)\n", strerror(errno));
5188       gdomap_log(LOG_CRIT);
5189       exit(EXIT_FAILURE);
5190     }
5191   if (open("/dev/null", O_WRONLY) != 1)
5192     {
5193       snprintf(ebuf, sizeof(ebuf),
5194 	"failed to open stdout from /dev/null (%s)\n", strerror(errno));
5195       gdomap_log(LOG_CRIT);
5196       exit(EXIT_FAILURE);
5197     }
5198   if (is_daemon && open("/dev/null", O_WRONLY) != 2)
5199     {
5200       snprintf(ebuf, sizeof(ebuf),
5201 	"failed to open stderr from /dev/null (%s)\n", strerror(errno));
5202       gdomap_log(LOG_CRIT);
5203       exit(EXIT_FAILURE);
5204     }
5205   if (debug)
5206     {
5207       snprintf(ebuf, sizeof(ebuf), "Closed descriptors");
5208       gdomap_log(LOG_DEBUG);
5209     }
5210 
5211   if (forked)
5212     {
5213       is_daemon = 1;
5214 #if	defined(HAVE_SYSLOG)
5215 #if	defined(SYSLOG_4_2)
5216       openlog ("gdomap", LOG_NDELAY);
5217       log_priority = LOG_DAEMON;
5218 #elif !defined(HAVE_SLOGF)
5219       openlog ("gdomap", LOG_NDELAY, LOG_DAEMON);
5220 #endif
5221 #endif
5222     }
5223 
5224 #endif /* !__MINGW__ */
5225 
5226   init_my_port();	/* Determine port to listen on.		*/
5227   init_ports();		/* Create ports to handle requests.	*/
5228 
5229   if (interfaces == 0)
5230     {
5231       init_iface();	/* Build up list of network interfaces.	*/
5232     }
5233 
5234   if (!is_local_host(loopback))
5235     {
5236       snprintf(ebuf, sizeof(ebuf),
5237 	 "I can't find the loopback interface on this machine.");
5238       gdomap_log(LOG_ERR);
5239       snprintf(ebuf, sizeof(ebuf),
5240 "Perhaps you should correct your machine configuration or use the -a flag.\n"
5241 "Try 'gdomap -C' for more information.\n");
5242       gdomap_log(LOG_INFO);
5243       if (interfaces < MAX_IFACE)
5244 	{
5245 	  addr[interfaces].s_addr = loopback.s_addr;
5246 	  mask[interfaces] = class_c_mask;
5247 	  interfaces++;
5248 	  snprintf(ebuf, sizeof(ebuf),
5249 	    "I am assuming loopback interface on 127.0.0.1");
5250 	  gdomap_log(LOG_INFO);
5251 	}
5252       else
5253 	{
5254 	  snprintf(ebuf, sizeof(ebuf),
5255 "You have too many network interfaces to add the loopback interface on "
5256 "127.0.0.1 - you need to change the 'MAX_IFACE' constant in gdomap.c and "
5257 "rebuild it.");
5258 	  gdomap_log(LOG_CRIT);
5259 	  exit(EXIT_FAILURE);
5260 	}
5261     }
5262 
5263   /* Write the pidfile, but only if the user is root. This allows us
5264      to write to restricted directories without allowing normal users
5265      to mess it up. Because we are writing as root, we must be careful
5266      to create/open the file in exclusive mode */
5267   if (pidfile)
5268     {
5269       FILE	*fptr;
5270 
5271 #ifndef __MINGW__
5272       if (getuid () == 0)
5273 #endif
5274 	{
5275 	  int	desc = open(pidfile, O_EXCL|O_CREAT|O_WRONLY, 0644);
5276 	  fptr = fdopen(desc, "w");
5277 
5278 	  if (fptr == 0)
5279 	    {
5280 	      snprintf(ebuf, sizeof(ebuf),
5281 		"Unable to create new pid file - '%s'", pidfile);
5282 	      gdomap_log(LOG_CRIT);
5283 	      exit(EXIT_FAILURE);
5284 	    }
5285 	  fprintf(fptr, "%d\n", (int) getpid());
5286 	  fclose(fptr);
5287 	  chmod(pidfile, 0644);
5288 	}
5289 #ifndef __MINGW__
5290       else
5291 	{
5292 	  snprintf(ebuf, sizeof(ebuf),
5293 	    "Only root user can write to pid file\n");
5294 	  gdomap_log(LOG_WARNING);
5295 	}
5296 #endif
5297     }
5298 {
5299 #ifndef __MINGW__
5300   uid_t uid = -2;
5301   gid_t gid = -2;
5302 #endif
5303 
5304 #if	defined(HAVE_PWD_H)
5305 #if	defined(HAVE_GETPWNAM)
5306   struct passwd *pw = getpwnam("nobody");
5307 
5308   if (pw != 0)
5309     {
5310       uid = pw->pw_uid;
5311       gid = pw->pw_gid;
5312     }
5313 #endif
5314 #endif
5315 
5316 #if	!defined(__svr4__)
5317   /*
5318    * As another level of paranoia - jail this process to a directory
5319    */
5320 #ifndef __MINGW__
5321   if (0 == jail)
5322     {
5323       jail = "/tmp";    /* Not great, but better than nothing */
5324     }
5325   if (chdir(jail) < 0)
5326     {
5327       snprintf(ebuf, sizeof(ebuf), "Unable to change directory to %s", jail);
5328       gdomap_log(LOG_CRIT);
5329       exit(EXIT_FAILURE);
5330     }
5331 
5332   if (geteuid() == 0)
5333     {
5334       if (chroot(jail) < 0)
5335 	{
5336 	  snprintf(ebuf, sizeof(ebuf), "Unable to change root to %s", jail);
5337 	  gdomap_log(LOG_CRIT);
5338 	  exit(EXIT_FAILURE);
5339 	}
5340       chdir("/");
5341     }
5342 #endif /* __MINGW__ */
5343 #endif /* __svr4__ */
5344 
5345 #ifndef __MINGW__
5346   /*
5347    * Try to become a 'safe' user now that we have
5348    * done everything that needs root priv.
5349    *
5350    * Try to be the user who launched us ... so they can kill us too.
5351    * Otherwise default to user nobody.
5352    */
5353   if (getuid () != 0)
5354     {
5355       uid = getuid();
5356       gid = getgid();
5357     }
5358   /* The call to setgroups may fail if we don't have that capability ...
5359    * but in that case we aren't too bothered anyway.
5360    */
5361   setgroups (1, &gid);
5362   if (setgid (gid) < 0)
5363     {
5364       snprintf(ebuf, sizeof(ebuf),
5365 	"Failed setgid(%d) - %s", gid, strerror(errno));
5366       gdomap_log(LOG_CRIT);
5367       exit(EXIT_FAILURE);
5368     }
5369   if (setuid (uid) < 0)
5370     {
5371       snprintf(ebuf, sizeof(ebuf),
5372 	"Failed setuid(%d) - %s", uid, strerror(errno));
5373       gdomap_log(LOG_CRIT);
5374       exit(EXIT_FAILURE);
5375     }
5376   if (getuid () == 0)
5377     {
5378       snprintf(ebuf, sizeof(ebuf),
5379 	"Still running as root after trying to change");
5380       gdomap_log(LOG_CRIT);
5381       exit(EXIT_FAILURE);
5382     }
5383 #endif /* __MINGW__ */
5384 }
5385 
5386   init_probe();	/* Probe other name servers on net.	*/
5387 
5388   if (debug)
5389     {
5390       snprintf(ebuf, sizeof(ebuf), "entering main loop.\n");
5391       gdomap_log(LOG_DEBUG);
5392     }
5393   handle_io();
5394   return 0;
5395 }
5396 
5397 /*
5398  *	Name -		queue_probe()
5399  *	Purpose -	Send a probe request to a specified host so we
5400  *			can see if a name server is running on it.
5401  *			We don't bother to check to see if it worked.
5402  */
5403 static void
queue_probe(struct in_addr * to,struct in_addr * from,int l,struct in_addr * e,int f)5404 queue_probe(struct in_addr* to, struct in_addr* from, int l, struct in_addr* e, int f)
5405 {
5406   struct sockaddr_in	sin;
5407   gdo_req	msg;
5408 
5409   if (debug > 2)
5410     {
5411       snprintf(ebuf, sizeof(ebuf),
5412 	"Probing for server on '%s' from '", inet_ntoa(*to));
5413       strncat(ebuf, inet_ntoa(*from), sizeof(ebuf) - strlen(ebuf) - 1);
5414       strncat(ebuf, "'", sizeof(ebuf) - strlen(ebuf) - 1);
5415       gdomap_log(LOG_DEBUG);
5416       if (l > 0)
5417 	{
5418 	  int	i;
5419 
5420 	  snprintf(ebuf, sizeof(ebuf),
5421 	    " %d additional local addresses sent -", l);
5422 	  gdomap_log(LOG_DEBUG);
5423 	  for (i = 0; i < l; i++)
5424 	    {
5425 	      snprintf(ebuf, sizeof(ebuf), " '%s'", inet_ntoa(e[i]));
5426 	      gdomap_log(LOG_DEBUG);
5427 	    }
5428 	}
5429     }
5430   memset(&sin, '\0', sizeof(sin));
5431   sin.sin_family = AF_INET;
5432   memcpy(&sin.sin_addr, to, sizeof(*to));
5433   sin.sin_port = my_port;
5434 
5435   memset((char*)&msg, '\0', GDO_REQ_SIZE);
5436   if (f)
5437     {
5438       msg.rtype = GDO_PREPLY;
5439     }
5440   else
5441     {
5442       msg.rtype = GDO_PROBE;
5443     }
5444   msg.nsize = 2*IASIZE;
5445   msg.ptype = 0;
5446   msg.dummy = 0;
5447   msg.port = 0;
5448   memcpy(msg.name, from, IASIZE);
5449   memcpy(&msg.name[IASIZE], to, IASIZE);
5450   if (l > 0)
5451     {
5452       memcpy(&msg.name[msg.nsize], e, l*IASIZE);
5453       msg.nsize += l*IASIZE;
5454     }
5455 
5456   queue_msg(&sin, (uptr)&msg, GDO_REQ_SIZE);
5457 }
5458 
5459 /* Copyright (c) 2001 Neal H Walfield <neal@cs.uml.edu>.
5460 
5461    This file is placed into the public domain.  Its distribution
5462    is unlimited.
5463 
5464    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
5465    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5466    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5467    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
5468    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5469    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
5470    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5471    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
5472    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
5473    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
5474    IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5475  */
5476 
5477 /* NAME
5478 
5479 	xgethostname - get the host name.
5480 
5481    SYNOPSIS
5482 
5483    	char *xgethostname (void);
5484 
5485    DESCRIPTION
5486 
5487 	The xhostname function is intended to replace gethostname(2), a
5488 	function used to access the host name.  The old interface is
5489 	inflexable given that it assumes the existance of the
5490 	MAXHOSTNAMELEN macro, which neither POSIX nor the proposed
5491 	Single Unix Specification version 3 guarantee to be defined.
5492 
5493    RETURN VALUE
5494 
5495 	On success, a malloced, null terminated (possibly truncated)
5496 	string containing the host name is returned.  On failure,
5497 	NULL is returned and errno is set.
5498  */
5499 
5500 char *
xgethostname(void)5501 xgethostname (void)
5502 {
5503   int size = 0;
5504   int addnull = 0;
5505   char *buf;
5506   int err;
5507 
5508 #if	defined(MAXHOSTNAMELEN)
5509   size = MAXHOSTNAMELEN;
5510   addnull = 1;
5511 #else /* MAXHOSTNAMELEN */
5512 #if	defined(_SC_HOST_NAME_MAX)
5513   size = sysconf (_SC_HOST_NAME_MAX);
5514   addnull = 1;
5515 #endif /* _SC_HOST_NAME_MAX */
5516 #if	defined(INTERNET_MAX_HOST_NAME_LENGTH)
5517   size = INTERNET_MAX_HOST_NAME_LENGTH;
5518   addnull = 1;
5519 #endif
5520   if (size <= 0)
5521     size = 256;
5522 #endif /* MAXHOSTNAMELEN */
5523 
5524   buf = malloc (size + addnull);
5525   if (! buf)
5526     {
5527       errno = ENOMEM;
5528       return NULL;
5529     }
5530 
5531   err = gethostname (buf, size);
5532   while (err == -1 && errno == ENAMETOOLONG)
5533     {
5534       free (buf);
5535 
5536       size *= 2;
5537       buf = malloc (size + addnull);
5538       if (! buf)
5539 	{
5540 	  errno = ENOMEM;
5541 	  return NULL;
5542 	}
5543 
5544       err = gethostname (buf, size);
5545     }
5546 
5547   if (err)
5548     {
5549       if (buf)
5550         free (buf);
5551       errno = err;
5552       return NULL;
5553     }
5554 
5555   if (addnull)
5556     buf[size] = '\0';
5557 
5558   return buf;
5559 }
5560