1 /*
2  *  Copyright conserver.com, 2000
3  *
4  *  Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com)
5  */
6 
7 #include <compat.h>
8 
9 #include <cutil.h>
10 #include <version.h>
11 
12 #include <net/if.h>
13 #if USE_IPV6
14 # include <ifaddrs.h>
15 #endif
16 #if HAVE_SYS_SOCKIO_H
17 # include <sys/sockio.h>
18 #endif
19 #if HAVE_OPENSSL
20 # include <openssl/ssl.h>
21 #endif
22 
23 
24 int fVerbose = 0, fErrorPrinted = 0;
25 int isMultiProc = 0;
26 char *progname = "conserver package";
27 pid_t thepid = 0;
28 int fDebug = 0;
29 STRING *allStrings = (STRING *)0;
30 int stringCount = 0;		/* count of allStrings list */
31 #if !USE_IPV6
32 struct in_addr *myAddrs = (struct in_addr *)0;
33 #endif
34 char myHostname[MAXHOSTNAME];	/* staff.cc.purdue.edu                  */
35 fd_set rinit;
36 fd_set winit;
37 int maxfd = 0;
38 int debugLineNo = 0;
39 char *debugFileName = (char *)0;
40 int isMaster = 1;
41 
42 /* in the routines below (the init code) we can bomb if malloc fails	(ksb)
43  */
44 void
OutOfMem(void)45 OutOfMem(void)
46 {
47     static char acNoMem[] = ": out of memory\n";
48 
49     write(2, progname, strlen(progname));
50     write(2, acNoMem, sizeof(acNoMem) - 1);
51     exit(EX_UNAVAILABLE);
52 }
53 
54 /* do a general cleanup and exit */
55 void
Bye(int status)56 Bye(int status)
57 {
58     DestroyDataStructures();
59 #if HAVE_OPENSSL
60 # if OPENSSL_VERSION_NUMBER < 0x10100000L
61     ERR_free_strings();
62 # endif
63 #endif
64     exit(status);
65 }
66 
67 /* This returns a string with the current time in ascii form.
68  * (same as ctime() but without the \n)
69  * optionally returns the time in time_t form (pass in NULL if you don't care).
70  * It's overwritten each time, so use it and forget it.
71  */
72 const char *
StrTime(time_t * ltime)73 StrTime(time_t *ltime)
74 {
75     static char curtime[40];	/* just in case ctime() varies */
76     time_t tyme;
77 
78     tyme = time((time_t *)0);
79     StrCpy(curtime, ctime(&tyme), sizeof(curtime));
80     curtime[24] = '\000';	/* might need to adjust this at some point */
81     if (ltime != NULL)
82 	*ltime = tyme;
83     return (const char *)curtime;
84 }
85 
86 #define STRING_ALLOC_SIZE 64
87 
88 char *
BuildStringChar(const char ch,STRING * msg)89 BuildStringChar(const char ch, STRING *msg)
90 {
91     if (msg->used + 1 >= msg->allocated) {
92 	if (0 == msg->allocated) {
93 	    msg->allocated = STRING_ALLOC_SIZE * sizeof(char);
94 	    msg->string = (char *)calloc(1, msg->allocated);
95 	} else {
96 	    msg->allocated += STRING_ALLOC_SIZE * sizeof(char);
97 	    msg->string = (char *)realloc(msg->string, msg->allocated);
98 	}
99 	CONDDEBUG((3,
100 		   "BuildStringChar(): 0x%lx tried allocating %lu bytes",
101 		   (void *)msg, msg->allocated));
102 	if (msg->string == (char *)0)
103 	    OutOfMem();
104     }
105     if (msg->used) {
106 	msg->string[msg->used - 1] = ch;	/* overwrite NULL and */
107 	msg->string[msg->used++] = '\000';	/* increment by one */
108 	CONDDEBUG((3, "BuildStringChar(): 0x%lx added 1 char (%d/%d now)",
109 		   (void *)msg, msg->used, msg->allocated));
110     } else {
111 	msg->string[msg->used++] = ch;	/* no NULL, so store stuff */
112 	msg->string[msg->used++] = '\000';	/* and increment by two */
113 	CONDDEBUG((3, "BuildStringChar(): 0x%lx added 2 chars (%d/%d now)",
114 		   (void *)msg, msg->used, msg->allocated));
115     }
116     return msg->string;
117 }
118 
119 char *
BuildString(const char * str,STRING * msg)120 BuildString(const char *str, STRING *msg)
121 {
122     int len;
123 
124     if ((char *)0 == str) {
125 	msg->used = 0;
126 	if (msg->string != (char *)0)
127 	    msg->string[0] = '\000';
128 	CONDDEBUG((3, "BuildString(): 0x%lx reset", (void *)msg));
129 	return msg->string;
130     }
131     if (msg->used)		/* string or string + null? */
132 	len = strlen(str);
133     else
134 	len = strlen(str) + 1;
135     if (msg->used + len >= msg->allocated) {
136 	if (0 == msg->allocated) {
137 	    msg->allocated =
138 		(len / STRING_ALLOC_SIZE +
139 		 1) * STRING_ALLOC_SIZE * sizeof(char);
140 	    msg->string = (char *)calloc(1, msg->allocated);
141 	} else {
142 	    msg->allocated +=
143 		((msg->used + len - msg->allocated) / STRING_ALLOC_SIZE +
144 		 1) * STRING_ALLOC_SIZE * sizeof(char);
145 	    msg->string = (char *)realloc(msg->string, msg->allocated);
146 	}
147 	CONDDEBUG((3, "BuildString(): 0x%lx tried allocating %lu bytes",
148 		   (void *)msg, msg->allocated));
149 	if (msg->string == (char *)0)
150 	    OutOfMem();
151     }
152     /* if msg->used, then len = strlen(), so we need to copy len + 1 to
153      * get the NULL which we overwrote with the copy */
154 #if HAVE_MEMCPY
155     if (msg->used)
156 	memcpy(msg->string + msg->used - 1, str, len + 1);
157     else
158 	memcpy(msg->string, str, len);
159 #else
160     if (msg->used)
161 	bcopy(str, msg->string + msg->used - 1, len + 1);
162     else
163 	bcopy(str, msg->string, len);
164 #endif
165     msg->used += len;
166     CONDDEBUG((3, "BuildString(): 0x%lx added %d chars (%d/%d now)",
167 	       (void *)msg, len, msg->used, msg->allocated));
168     return msg->string;
169 }
170 
171 char *
BuildStringN(const char * str,int n,STRING * msg)172 BuildStringN(const char *str, int n, STRING *msg)
173 {
174     int len;
175 
176     if ((char *)0 == str) {
177 	msg->used = 0;
178 	if (msg->string != (char *)0)
179 	    msg->string[0] = '\000';
180 	CONDDEBUG((3, "BuildStringN(): 0x%lx reset", (void *)msg));
181 	return msg->string;
182     }
183     if (n <= 0)
184 	return msg->string;
185     if (msg->used)
186 	len = n;
187     else
188 	len = n + 1;
189     if (msg->used + len >= msg->allocated) {
190 	if (0 == msg->allocated) {
191 	    msg->allocated =
192 		(len / STRING_ALLOC_SIZE +
193 		 1) * STRING_ALLOC_SIZE * sizeof(char);
194 	    msg->string = (char *)calloc(1, msg->allocated);
195 	} else {
196 	    msg->allocated +=
197 		((msg->used + len - msg->allocated) / STRING_ALLOC_SIZE +
198 		 1) * STRING_ALLOC_SIZE * sizeof(char);
199 	    msg->string = (char *)realloc(msg->string, msg->allocated);
200 	}
201 	CONDDEBUG((3, "BuildStringN(): 0x%lx tried allocating %lu bytes",
202 		   (void *)msg, msg->allocated));
203 	if (msg->string == (char *)0)
204 	    OutOfMem();
205     }
206 #if HAVE_MEMCPY
207     memcpy(msg->string + (msg->used ? msg->used - 1 : 0), str, n);
208 #else
209     bcopy(str, msg->string + (msg->used ? msg->used - 1 : 0), n);
210 #endif
211     /* add a NULL */
212     msg->string[(msg->used ? msg->used - 1 : 0) + n] = '\000';
213     msg->used += len;
214     CONDDEBUG((3, "BuildStringN(): 0x%lx added %d chars (%d/%d now)",
215 	       (void *)msg, len, msg->used, msg->allocated));
216     return msg->string;
217 }
218 
219 void *
MemMove(void * dest,void * src,size_t n)220 MemMove(void *dest, void *src, size_t n)
221 {
222 #if HAVE_MEMMOVE
223     return memmove(dest, src, n);
224 #else
225     char *s = src;
226     char *d = dest;
227 
228     if (s < d) {
229 	/* Moving from low mem to hi mem; start at end.  */
230 	for (s += n, d += n; n > 0; --n)
231 	    *--d = *--s;
232     } else if (s != d) {
233 	/* Moving from hi mem to low mem; start at beginning.  */
234 	for (; n > 0; --n)
235 	    *d++ = *s++;
236     }
237     return dest;
238 #endif
239 }
240 
241 char *
ShiftString(STRING * msg,int n)242 ShiftString(STRING *msg, int n)
243 {
244     if (msg == (STRING *)0 || n <= 0 || n > msg->used - 1)
245 	return (char *)0;
246 
247     MemMove(msg->string, msg->string + n, msg->used - n);
248 
249     msg->used -= n;
250     return msg->string;
251 }
252 
253 void
InitString(STRING * msg)254 InitString(STRING *msg)
255 {
256     msg->string = (char *)0;
257     msg->used = msg->allocated = 0;
258 }
259 
260 void
DestroyString(STRING * msg)261 DestroyString(STRING *msg)
262 {
263     if (msg->prev == (STRING *)0 && msg->next == (STRING *)0 &&
264 	allStrings != msg) {
265 	CONDDEBUG((1, "DestroyString(): 0x%lx non-pooled string destroyed",
266 		   (void *)msg, stringCount));
267     } else {
268 	if (msg->prev != (STRING *)0)
269 	    msg->prev->next = msg->next;
270 	if (msg->next != (STRING *)0)
271 	    msg->next->prev = msg->prev;
272 	if (msg == allStrings) {
273 	    allStrings = msg->next;
274 	}
275 	stringCount--;
276 	CONDDEBUG((1,
277 		   "DestroyString(): 0x%lx string destroyed (count==%d)",
278 		   (void *)msg, stringCount));
279     }
280     if (msg->allocated)
281 	free(msg->string);
282     free(msg);
283 }
284 
285 STRING *
AllocString(void)286 AllocString(void)
287 {
288     STRING *s;
289     if ((s = (STRING *)calloc(1, sizeof(STRING)))
290 	== (STRING *)0)
291 	OutOfMem();
292     if (allStrings != (STRING *)0) {
293 	allStrings->prev = s;
294 	s->next = allStrings;
295     }
296     allStrings = s;
297     InitString(s);
298     stringCount++;
299     CONDDEBUG((1, "AllocString(): 0x%lx created string #%d", (void *)s,
300 	       stringCount));
301     return s;
302 }
303 
304 void
DestroyStrings(void)305 DestroyStrings(void)
306 {
307     while (allStrings != (STRING *)0) {
308 	DestroyString(allStrings);
309     }
310 }
311 
312 static STRING *mymsg = (STRING *)0;
313 
314 char *
BuildTmpString(const char * str)315 BuildTmpString(const char *str)
316 {
317     if (mymsg == (STRING *)0)
318 	mymsg = AllocString();
319     return BuildString(str, mymsg);
320 }
321 
322 char *
BuildTmpStringChar(const char c)323 BuildTmpStringChar(const char c)
324 {
325     if (mymsg == (STRING *)0)
326 	mymsg = AllocString();
327     return BuildStringChar(c, mymsg);
328 }
329 
330 char *
ReadLine(FILE * fp,STRING * save,int * iLine)331 ReadLine(FILE *fp, STRING *save, int *iLine)
332 {
333     static char buf[1024];
334     char *wholeline = (char *)0;
335     char *ret = (char *)0;
336     int i, buflen, peek, commentCheck = 1, comment = 0;
337     static STRING *bufstr = (STRING *)0;
338     static STRING *wholestr = (STRING *)0;
339 
340     if (bufstr == (STRING *)0)
341 	bufstr = AllocString();
342     if (wholestr == (STRING *)0)
343 	wholestr = AllocString();
344     peek = 0;
345     wholeline = (char *)0;
346     BuildString((char *)0, bufstr);
347     BuildString((char *)0, wholestr);
348     while (save->used || ((ret = fgets(buf, sizeof(buf), fp)) != (char *)0)
349 	   || peek) {
350 	/* If we have a previously saved line, use it instead */
351 	if (save->used) {
352 	    StrCpy(buf, save->string, sizeof(buf));
353 	    BuildString((char *)0, save);
354 	}
355 
356 	if (peek) {
357 	    /* End of file?  Never mind. */
358 	    if (ret == (char *)0)
359 		break;
360 
361 	    /* If we don't have a line continuation and we've seen
362 	     * some worthy data
363 	     */
364 	    if (!isspace((int)buf[0]) && (wholeline != (char *)0)) {
365 		BuildString((char *)0, save);
366 		BuildString(buf, save);
367 		break;
368 	    }
369 
370 	    peek = 0;
371 	}
372 
373 	if (commentCheck) {
374 	    for (i = 0; buf[i] != '\000'; i++)
375 		if (!isspace((int)buf[i]))
376 		    break;
377 	    if (buf[i] == '#') {
378 		comment = 1;
379 		commentCheck = 0;
380 	    } else if (buf[i] != '\000') {
381 		commentCheck = 0;
382 	    }
383 	}
384 
385 	/* Check for EOL */
386 	buflen = strlen(buf);
387 	if ((buflen >= 1) && (buf[buflen - 1] == '\n')) {
388 	    (*iLine)++;		/* Finally have a whole line */
389 	    if (comment == 0 && commentCheck == 0) {
390 		/* Finish off the chunk without the \n */
391 		buf[buflen - 1] = '\000';
392 		BuildString(buf, bufstr);
393 		wholeline = BuildString(bufstr->string, wholestr);
394 	    }
395 	    peek = 1;
396 	    comment = 0;
397 	    commentCheck = 1;
398 	    BuildString((char *)0, bufstr);
399 	} else {
400 	    /* Save off the partial chunk */
401 	    BuildString(buf, bufstr);
402 	}
403     }
404 
405     /* If we hit the EOF and weren't peeking ahead
406      * and it's not a comment
407      */
408     if (!peek && (ret == (char *)0) && (comment == 0) &&
409 	(commentCheck == 0)) {
410 	(*iLine)++;
411 	wholeline = BuildString(bufstr->string, wholestr);
412     }
413 
414     CONDDEBUG((1, "ReadLine(): returning <%s>",
415 	       (wholeline != (char *)0) ? wholeline : "<NULL>"));
416     return wholeline;
417 }
418 
419 /* show a character as a string so the user cannot mistake it for	(ksb)
420  * another
421  */
422 char *
FmtCtl(int ci,STRING * pcIn)423 FmtCtl(int ci, STRING *pcIn)
424 {
425     unsigned char c;
426 
427     BuildString((char *)0, pcIn);
428     c = ci & 0xff;
429     if (c > 127) {
430 	c -= 128;
431 	BuildString("M-", pcIn);
432     }
433 
434     if (c < ' ' || c == '\177') {
435 	BuildStringChar('^', pcIn);
436 	BuildStringChar(c ^ 0100, pcIn);
437     } else if (c == ' ') {
438 	BuildString("<space>", pcIn);
439     } else if (c == '^') {
440 	BuildString("<circumflex>", pcIn);
441     } else if (c == '\\') {
442 	BuildString("<backslash>", pcIn);
443     } else {
444 	BuildStringChar(c, pcIn);
445     }
446     return pcIn->string;
447 }
448 
449 void
FmtCtlStr(char * pcIn,int len,STRING * pcOut)450 FmtCtlStr(char *pcIn, int len, STRING *pcOut)
451 {
452     unsigned char c;
453 
454     BuildString((char *)0, pcOut);
455 
456     if (pcIn == (char *)0)
457 	return;
458 
459     if (len < 0)
460 	len = strlen(pcIn);
461 
462     for (; len; len--, pcIn++) {
463 	c = *pcIn & 0xff;
464 	if (c > 127) {
465 	    c -= 128;
466 	    BuildString("M-", pcOut);
467 	}
468 
469 	if (c < ' ' || c == '\177') {
470 	    BuildStringChar('^', pcOut);
471 	    BuildStringChar(c ^ 0100, pcOut);
472 	} else {
473 	    BuildStringChar(c, pcOut);
474 	}
475     }
476 }
477 
478 void
Debug(int level,char * fmt,...)479 Debug(int level, char *fmt, ...)
480 {
481     va_list ap;
482 
483     if (fDebug < level)
484 	return;
485     va_start(ap, fmt);
486     if (isMultiProc)
487 	fprintf(stderr, "[%s] %s (%lu): DEBUG: [%s:%d] ",
488 		StrTime((time_t *)0), progname, (unsigned long)thepid,
489 		debugFileName, debugLineNo);
490     else
491 	fprintf(stderr, "%s: DEBUG: [%s:%d] ", progname, debugFileName,
492 		debugLineNo);
493     vfprintf(stderr, fmt, ap);
494     fprintf(stderr, "\n");
495     va_end(ap);
496 }
497 
498 void
Error(char * fmt,...)499 Error(char *fmt, ...)
500 {
501     va_list ap;
502     va_start(ap, fmt);
503     if (isMultiProc)
504 	fprintf(stderr, "[%s] %s (%lu): ERROR: ", StrTime((time_t *)0),
505 		progname, (unsigned long)thepid);
506     else
507 	fprintf(stderr, "%s: ", progname);
508     vfprintf(stderr, fmt, ap);
509     fprintf(stderr, "\n");
510     va_end(ap);
511     fErrorPrinted = 1;
512 }
513 
514 void
Msg(char * fmt,...)515 Msg(char *fmt, ...)
516 {
517     va_list ap;
518     va_start(ap, fmt);
519     if (isMultiProc)
520 	fprintf(stdout, "[%s] %s (%lu): ", StrTime((time_t *)0), progname,
521 		(unsigned long)thepid);
522     else
523 	fprintf(stdout, "%s: ", progname);
524     vfprintf(stdout, fmt, ap);
525     fprintf(stdout, "\n");
526     va_end(ap);
527 }
528 
529 void
Verbose(char * fmt,...)530 Verbose(char *fmt, ...)
531 {
532     va_list ap;
533 
534     if (!fVerbose)
535 	return;
536 
537     va_start(ap, fmt);
538     if (isMultiProc)
539 	fprintf(stdout, "[%s] %s (%lu): INFO: ", StrTime((time_t *)0),
540 		progname, (unsigned long)thepid);
541     else
542 	fprintf(stdout, "%s: ", progname);
543     vfprintf(stdout, fmt, ap);
544     fprintf(stdout, "\n");
545     va_end(ap);
546 }
547 
548 void
SimpleSignal(int sig,RETSIGTYPE (* disp)(int))549 SimpleSignal(int sig, RETSIGTYPE(*disp) (int))
550 {
551 #if HAVE_SIGACTION
552     struct sigaction sa;
553 
554     sa.sa_handler = disp;
555     sa.sa_flags = 0;
556     sigemptyset(&sa.sa_mask);
557     sigaction(sig, &sa, NULL);
558 #else
559     signal(sig, disp);
560 #endif
561 }
562 
563 int
GetMaxFiles(void)564 GetMaxFiles(void)
565 {
566     int mf;
567 #if HAVE_SYSCONF
568     mf = sysconf(_SC_OPEN_MAX);
569 #else
570 # if HAVE_GETRLIMIT
571     struct rlimit rl;
572 
573     getrlimit(RLIMIT_NOFILE, &rl);
574     mf = rl.rlim_cur;
575 # else
576 #  if HAVE_GETDTABLESIZE
577     mf = getdtablesize();
578 #  else
579 #   ifndef OPEN_MAX
580 #    define OPEN_MAX 64
581 #   endif
582     /* !OPEN_MAX */
583     mf = OPEN_MAX;
584 #  endif
585     /* HAVE_GETDTABLESIZE */
586 # endif/* HAVE_GETRLIMIT */
587 #endif /* HAVE_SYSCONF */
588 #ifdef FD_SETSIZE
589     if (FD_SETSIZE <= mf) {
590 	mf = (FD_SETSIZE - 1);
591     }
592 #endif
593     CONDDEBUG((1, "GetMaxFiles(): maxfiles=%d", mf));
594     return mf;
595 }
596 
597 /* Routines for the generic I/O stuff for conserver.  This will handle
598  * all open(), close(), read(), and write() calls.
599  */
600 
601 /* This encapsulates a regular file descriptor in a CONSFILE
602  * object.  Returns a CONSFILE pointer to that object.
603  */
604 CONSFILE *
FileOpenFD(int fd,enum consFileType type)605 FileOpenFD(int fd, enum consFileType type)
606 {
607     CONSFILE *cfp;
608 
609     if ((cfp = (CONSFILE *)calloc(1, sizeof(CONSFILE)))
610 	== (CONSFILE *)0)
611 	OutOfMem();
612     cfp->ftype = type;
613     cfp->fd = fd;
614     cfp->wbuf = AllocString();
615 #if HAVE_OPENSSL
616     cfp->ssl = (SSL *)0;
617     cfp->waitForRead = cfp->waitForWrite = FLAGFALSE;
618 #endif
619 #if DEBUG_CONSFILE_IO
620     {
621 	char buf[1024];
622 	sprintf(buf, "CONSFILE-%s-%lu-%d.w", progname,
623 		(unsigned long)thepid, fd);
624 	if ((cfp->debugwfd =
625 	     open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) {
626 	    sprintf(buf, "[---- STARTED - %s ----]\n",
627 		    StrTime((time_t *)0));
628 	    write(cfp->debugwfd, buf, strlen(buf));
629 	}
630 	sprintf(buf, "CONSFILE-%s-%lu-%d.r", progname,
631 		(unsigned long)thepid, fd);
632 	if ((cfp->debugrfd =
633 	     open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) {
634 	    sprintf(buf, "[---- STARTED - %s ----]\n",
635 		    StrTime((time_t *)0));
636 	    write(cfp->debugrfd, buf, strlen(buf));
637 	}
638     }
639 #endif
640 
641     CONDDEBUG((2, "FileOpenFD(): encapsulated fd %d type %d", fd, type));
642     return cfp;
643 }
644 
645 /* This encapsulates a pipe pair in a CONSFILE
646  * object.  Returns a CONSFILE pointer to that object.
647  */
648 CONSFILE *
FileOpenPipe(int fd,int fdout)649 FileOpenPipe(int fd, int fdout)
650 {
651     CONSFILE *cfp;
652 
653     if ((cfp = (CONSFILE *)calloc(1, sizeof(CONSFILE)))
654 	== (CONSFILE *)0)
655 	OutOfMem();
656     cfp->ftype = simplePipe;
657     cfp->fd = fd;
658     cfp->fdout = fdout;
659     cfp->wbuf = AllocString();
660 #if HAVE_OPENSSL
661     cfp->ssl = (SSL *)0;
662     cfp->waitForRead = cfp->waitForWrite = FLAGFALSE;
663 #endif
664 #if DEBUG_CONSFILE_IO
665     {
666 	char buf[1024];
667 	sprintf(buf, "CONSFILE-%s-%lu-%d.w", progname,
668 		(unsigned long)thepid, fdout);
669 	if ((cfp->debugwfd =
670 	     open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) {
671 	    sprintf(buf, "[---- STARTED - %s ----]\n",
672 		    StrTime((time_t *)0));
673 	    write(cfp->debugwfd, buf, strlen(buf));
674 	}
675 	sprintf(buf, "CONSFILE-%s-%lu-%d.r", progname,
676 		(unsigned long)thepid, fd);
677 	if ((cfp->debugrfd =
678 	     open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) {
679 	    sprintf(buf, "[---- STARTED - %s ----]\n",
680 		    StrTime((time_t *)0));
681 	    write(cfp->debugrfd, buf, strlen(buf));
682 	}
683     }
684 #endif
685 
686     CONDDEBUG((2, "FileOpenPipe(): encapsulated pipe pair fd %d and fd %d",
687 	       fd, fdout));
688     return cfp;
689 }
690 
691 /* This is to "unencapsulate" the file descriptor */
692 int
FileUnopen(CONSFILE * cfp)693 FileUnopen(CONSFILE *cfp)
694 {
695     int retval = 0;
696 
697     if (cfp == (CONSFILE *)0)
698 	return 0;
699 
700     switch (cfp->ftype) {
701 	case simpleFile:
702 	    retval = cfp->fd;
703 	    break;
704 	case simplePipe:
705 	    retval = cfp->fd;
706 	    break;
707 	case simpleSocket:
708 	    retval = cfp->fd;
709 	    break;
710 #if HAVE_OPENSSL
711 	case SSLSocket:
712 	    retval = -1;
713 	    break;
714 #endif
715 	default:
716 	    retval = -1;
717 	    break;
718     }
719     CONDDEBUG((2, "FileUnopen(): unopened fd %d", cfp->fd));
720     DestroyString(cfp->wbuf);
721 #if DEBUG_CONSFILE_IO
722     if (cfp->debugwfd != -1)
723 	close(cfp->debugwfd);
724     if (cfp->debugrfd != -1)
725 	close(cfp->debugrfd);
726 #endif
727     free(cfp);
728 
729     return retval;
730 }
731 
732 /* This opens a file like open(2).  Returns a CONSFILE pointer
733  * or a (CONSFILE *)0 on error
734  */
735 CONSFILE *
FileOpen(const char * path,int flag,int mode)736 FileOpen(const char *path, int flag, int mode)
737 {
738     CONSFILE *cfp;
739     int fd;
740 
741     if (-1 == (fd = open(path, flag, mode))) {
742 	CONDDEBUG((2, "FileOpen(): failed to open `%s'", path));
743 	return (CONSFILE *)0;
744     }
745     if ((cfp = (CONSFILE *)calloc(1, sizeof(CONSFILE)))
746 	== (CONSFILE *)0)
747 	OutOfMem();
748     cfp->ftype = simpleFile;
749     cfp->fd = fd;
750     cfp->wbuf = AllocString();
751 #if HAVE_OPENSSL
752     cfp->ssl = (SSL *)0;
753     cfp->waitForRead = cfp->waitForWrite = FLAGFALSE;
754 #endif
755 #if DEBUG_CONSFILE_IO
756     {
757 	char buf[1024];
758 	sprintf(buf, "CONSFILE-%s-%lu-%d.w", progname,
759 		(unsigned long)thepid, fd);
760 	if ((cfp->debugwfd =
761 	     open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) {
762 	    sprintf(buf, "[---- STARTED - %s ----]\n",
763 		    StrTime((time_t *)0));
764 	    write(cfp->debugwfd, buf, strlen(buf));
765 	}
766 	sprintf(buf, "CONSFILE-%s-%lu-%d.r", progname,
767 		(unsigned long)thepid, fd);
768 	if ((cfp->debugrfd =
769 	     open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) {
770 	    sprintf(buf, "[---- STARTED - %s ----]\n",
771 		    StrTime((time_t *)0));
772 	    write(cfp->debugrfd, buf, strlen(buf));
773 	}
774     }
775 #endif
776 
777     CONDDEBUG((2, "FileOpen(): opened `%s' as fd %d", path, fd));
778     return cfp;
779 }
780 
781 /* Unless otherwise stated, returns the same values as close(2).
782  * The CONSFILE object passed in *CANNOT* be used once calling
783  * this function - even if there was an error.
784  */
785 int
FileClose(CONSFILE ** pcfp)786 FileClose(CONSFILE **pcfp)
787 {
788     CONSFILE *cfp;
789     int retval = 0;
790 #if defined(__CYGWIN__)
791     struct linger lingeropt;
792 #endif
793 
794     cfp = *pcfp;
795     if (cfp == (CONSFILE *)0)
796 	return 0;
797 
798     switch (cfp->ftype) {
799 	case simpleFile:
800 	    do {
801 		retval = close(cfp->fd);
802 	    } while (retval == -1 && errno == EINTR);
803 	    break;
804 	case simplePipe:
805 	    do {
806 		retval = close(cfp->fd);
807 	    } while (retval == -1 && errno == EINTR);
808 	    do {
809 		retval = close(cfp->fdout);
810 	    } while (retval == -1 && errno == EINTR);
811 	    break;
812 	case simpleSocket:
813 #if defined(__CYGWIN__)
814 	    /* flush out the client socket - set it to blocking,
815 	     * then write to it
816 	     */
817 	    SetFlags(cfp->fd, 0, O_NONBLOCK);
818 
819 	    /* sent it a byte - guaranteed to block - ensure delivery
820 	     * of prior data yeah - this is a bit paranoid - try
821 	     * without this at first
822 	     */
823 	    /* write(cfp->fd, "\n", 1); */
824 	    /* this is the guts of the workaround for Winsock close bug */
825 	    shutdown(cfp->fd, 1);
826 
827 	    /* enable lingering */
828 	    lingeropt.l_onoff = 1;
829 	    lingeropt.l_linger = 15;
830 	    setsockopt(cfp->fd, SOL_SOCKET, SO_LINGER, &lingeropt,
831 		       sizeof(lingeropt));
832 #endif
833 	    do {
834 		retval = close(cfp->fd);
835 	    } while (retval == -1 && errno == EINTR);
836 
837 	    break;
838 #if HAVE_OPENSSL
839 	case SSLSocket:
840 	    CONDDEBUG((2,
841 		       "FileClose(): performing a SSL_shutdown() on fd %d",
842 		       cfp->fd));
843 	    SSL_shutdown(cfp->ssl);
844 	    CONDDEBUG((2, "FileClose(): performing a SSL_free() on fd %d",
845 		       cfp->fd));
846 	    SSL_free(cfp->ssl);
847 	    /* set the sucker back to a simpleSocket and recall so we
848 	     * do all that special stuff we oh so love...and make sure
849 	     * we return so we don't try and free(0).  -bryan
850 	     */
851 	    cfp->ftype = simpleSocket;
852 	    return FileClose(pcfp);
853 #endif
854 	default:
855 	    retval = -1;
856 	    break;
857     }
858 
859     if (cfp->ftype == simplePipe) {
860 	CONDDEBUG((2, "FileClose(): closed fd %d/%d", cfp->fd,
861 		   cfp->fdout));
862     } else {
863 	CONDDEBUG((2, "FileClose(): closed fd %d", cfp->fd));
864     }
865     DestroyString(cfp->wbuf);
866 #if DEBUG_CONSFILE_IO
867     if (cfp->debugwfd != -1)
868 	close(cfp->debugwfd);
869     if (cfp->debugrfd != -1)
870 	close(cfp->debugrfd);
871 #endif
872     free(cfp);
873     *pcfp = (CONSFILE *)0;
874 
875     return retval;
876 }
877 
878 /* returns: -1 on error or eof, >= 0 for valid reads */
879 int
FileRead(CONSFILE * cfp,void * buf,int len)880 FileRead(CONSFILE *cfp, void *buf, int len)
881 {
882     int retval = -1;
883 
884     if (cfp->errored == FLAGTRUE)
885 	return -1;
886 
887     switch (cfp->ftype) {
888 	case simpleFile:
889 	case simplePipe:
890 	case simpleSocket:
891 	    while (retval < 0) {
892 		if ((retval = read(cfp->fd, buf, len)) <= 0) {
893 		    if (retval == 0) {
894 			retval = -1;
895 			break;
896 		    }
897 		    if (errno == EINTR)
898 			continue;
899 		    if (errno == EAGAIN) {
900 			/* must be non-blocking - so stop */
901 			retval = 0;
902 			break;
903 		    }
904 		    Error("FileRead(): fd %d: %s", cfp->fd,
905 			  strerror(errno));
906 		    retval = -1;
907 		    break;
908 		}
909 #if DEBUG_CONSFILE_IO
910 		if (cfp->debugrfd != -1)
911 		    write(cfp->debugrfd, buf, retval);
912 #endif
913 	    }
914 	    break;
915 #if HAVE_OPENSSL
916 	case SSLSocket:
917 	    if (cfp->waitForWrite == FLAGTRUE) {
918 		cfp->waitForWrite = FLAGFALSE;
919 		if (cfp->wbuf->used <= 1)
920 		    FD_CLR(cfp->fd, &winit);
921 	    }
922 	    retval = SSL_read(cfp->ssl, buf, len);
923 	    switch (SSL_get_error(cfp->ssl, retval)) {
924 		case SSL_ERROR_NONE:
925 		    break;
926 		case SSL_ERROR_WANT_READ:
927 		    retval = 0;
928 		    break;
929 		case SSL_ERROR_WANT_WRITE:
930 		    cfp->waitForWrite = FLAGTRUE;
931 		    FD_SET(cfp->fd, &winit);
932 		    retval = 0;
933 		    break;
934 		default:
935 		    Error("FileRead(): SSL error on fd %d", cfp->fd);
936 		    /* fall through */
937 		case SSL_ERROR_ZERO_RETURN:
938 		    retval = -1;
939 		    CONDDEBUG((2,
940 			       "FileRead(): performing a SSL_shutdown() on fd %d",
941 			       cfp->fd));
942 		    SSL_shutdown(cfp->ssl);
943 		    CONDDEBUG((2,
944 			       "FileRead(): performing a SSL_free() on fd %d",
945 			       cfp->fd));
946 		    SSL_free(cfp->ssl);
947 		    cfp->ssl = (SSL *)0;
948 		    cfp->ftype = simpleSocket;
949 		    break;
950 	    }
951 # if DEBUG_CONSFILE_IO
952 	    if (cfp->debugrfd != -1)
953 		write(cfp->debugrfd, buf, retval);
954 # endif
955 	    break;
956 #endif
957 	default:
958 	    retval = -1;
959 	    break;
960     }
961 
962     if (retval >= 0) {
963 	CONDDEBUG((2, "FileRead(): read %d byte%s from fd %d", retval,
964 		   (retval == 1) ? "" : "s", cfp->fd));
965 	if (fDebug && buf != (char *)0) {
966 	    static STRING *tmpString = (STRING *)0;
967 	    if (tmpString == (STRING *)0)
968 		tmpString = AllocString();
969 	    BuildString((char *)0, tmpString);
970 	    if (retval > 30) {
971 		FmtCtlStr(buf, 30, tmpString);
972 		CONDDEBUG((2, "FileRead(): read `%s'... from fd %d",
973 			   tmpString->string, cfp->fd));
974 	    } else {
975 		FmtCtlStr(buf, retval, tmpString);
976 		CONDDEBUG((2, "FileRead(): read `%s' from fd %d",
977 			   tmpString->string, cfp->fd));
978 	    }
979 	}
980     } else {
981 	CONDDEBUG((2,
982 		   "FileRead(): failed attempted read of %d byte%s from fd %d",
983 		   len, (len == 1) ? "" : "s", cfp->fd));
984     }
985 
986     if (retval < 0)
987 	cfp->errored = FLAGTRUE;
988 
989     return retval;
990 }
991 
992 /* returns: -1 on error or eof, >= 0 for valid reads */
993 int
FileWrite(CONSFILE * cfp,FLAG bufferonly,char * buf,int len)994 FileWrite(CONSFILE *cfp, FLAG bufferonly, char *buf, int len)
995 {
996     int len_orig = len;
997     int len_out = 0;
998     int retval = 0;
999     int fdout = 0;
1000 
1001     if (cfp->ftype == simplePipe)
1002 	fdout = cfp->fdout;
1003     else
1004 	fdout = cfp->fd;
1005 
1006     if (cfp->errored == FLAGTRUE) {
1007 	if (cfp->wbuf->used > 1)
1008 	    BuildString((char *)0, cfp->wbuf);
1009 	FD_CLR(fdout, &winit);
1010 	return -1;
1011     }
1012 
1013     if (len < 0 && buf != (char *)0)
1014 	len = strlen(buf);
1015 
1016     if (fDebug && len > 0 && buf != (char *)0) {
1017 	static STRING *tmpString = (STRING *)0;
1018 	if (tmpString == (STRING *)0)
1019 	    tmpString = AllocString();
1020 	BuildString((char *)0, tmpString);
1021 	if (len > 30) {
1022 	    FmtCtlStr(buf, 30, tmpString);
1023 	    CONDDEBUG((2, "FileWrite(): sending `%s'... to fd %d",
1024 		       tmpString->string, fdout));
1025 	} else {
1026 	    FmtCtlStr(buf, len, tmpString);
1027 	    CONDDEBUG((2, "FileWrite(): sending `%s' to fd %d",
1028 		       tmpString->string, fdout));
1029 	}
1030     }
1031 
1032     /* save the data */
1033     if (len > 0 && buf != (char *)0) {
1034 	if (cfp->quoteiac == FLAGTRUE) {
1035 	    int l, o;
1036 	    for (o = l = 0; l < len; l++) {
1037 		if (buf[l] == (char)OB_IAC) {
1038 		    BuildStringN(buf + o, l + 1 - o, cfp->wbuf);
1039 		    BuildStringChar((char)OB_IAC, cfp->wbuf);
1040 		    o = l + 1;
1041 		}
1042 	    }
1043 	    if (o < len)
1044 		BuildStringN(buf + o, len - o, cfp->wbuf);
1045 	} else
1046 	    BuildStringN(buf, len, cfp->wbuf);
1047     }
1048 
1049     if (bufferonly == FLAGTRUE)
1050 	return 0;
1051 
1052     /* point at the local data */
1053     buf = cfp->wbuf->string;
1054     len = cfp->wbuf->used - 1;
1055 
1056     /* if we don't have any, forget it */
1057     if (buf == (char *)0 || len <= 0)
1058 	return 0;
1059 
1060     /* so, we could be blocking or non-blocking.  since we may be able
1061      * to block, we'll just keep trying to write while we have data and
1062      * stop when we hit an error or flush all the data.
1063      */
1064     switch (cfp->ftype) {
1065 	case simplePipe:
1066 	case simpleFile:
1067 	case simpleSocket:
1068 	    while (len > 0) {
1069 		if ((retval = write(fdout, buf, len)) < 0) {
1070 		    if (errno == EINTR)
1071 			continue;
1072 		    if (errno == EAGAIN) {
1073 			/* must be non-blocking - so stop */
1074 			retval = 0;
1075 			break;
1076 		    }
1077 		    retval = -1;
1078 		    /* i believe, as of 8.0.8, we need to just ignore
1079 		     * this and actually produce the error message
1080 		     * below.  perhaps we'll have a lot of extra
1081 		     * FileWrite() errors, perhaps not.  things shouldn't
1082 		     * just close down and cause errors in normal cases,
1083 		     * right?!?  -bryan
1084 		     * maybe not right now, actually.  i'm going to check
1085 		     * the return code of FileWrite() on the "important"
1086 		     * things and let the others silently fail and have
1087 		     * the FileRead() catch problems - like it has been
1088 		     * doing.  i really should be checking all the return
1089 		     * codes...and i'm sure i'll get there eventually.
1090 		     */
1091 		    if (errno == EPIPE)
1092 			break;
1093 		    Error("FileWrite(): fd %d: %s", fdout,
1094 			  strerror(errno));
1095 		    break;
1096 		}
1097 #if DEBUG_CONSFILE_IO
1098 		if (cfp->debugwfd != -1)
1099 		    write(cfp->debugwfd, buf, retval);
1100 #endif
1101 		buf += retval;
1102 		len -= retval;
1103 		len_out += retval;
1104 	    }
1105 	    break;
1106 #if HAVE_OPENSSL
1107 	case SSLSocket:
1108 	    if (cfp->waitForRead == FLAGTRUE)
1109 		cfp->waitForRead = FLAGFALSE;
1110 	    while (len > 0) {
1111 		/* in theory, SSL_write always returns 'len' on success
1112 		 * so the while() loop is a noop.  but, just in case i
1113 		 * read something wrong, we treat SSL_write like write().
1114 		 */
1115 		retval = SSL_write(cfp->ssl, buf, len);
1116 		switch (SSL_get_error(cfp->ssl, retval)) {
1117 		    case SSL_ERROR_NONE:
1118 			break;
1119 		    case SSL_ERROR_WANT_READ:
1120 			cfp->waitForRead = FLAGTRUE;
1121 			retval = len_out = 0;
1122 			break;
1123 		    case SSL_ERROR_WANT_WRITE:
1124 			retval = len_out = 0;
1125 			break;
1126 		    default:
1127 			Error("FileWrite(): SSL error on fd %d", cfp->fd);
1128 			/* fall through */
1129 		    case SSL_ERROR_ZERO_RETURN:
1130 			retval = -1;
1131 			CONDDEBUG((2,
1132 				   "FileWrite(): performing a SSL_shutdown() on fd %d",
1133 				   cfp->fd));
1134 			SSL_shutdown(cfp->ssl);
1135 			CONDDEBUG((2,
1136 				   "FileWrite(): performing a SSL_free() on fd %d",
1137 				   cfp->fd));
1138 			SSL_free(cfp->ssl);
1139 			cfp->ssl = (SSL *)0;
1140 			cfp->ftype = simpleSocket;
1141 			break;
1142 		}
1143 		if (retval <= 0)
1144 		    break;
1145 # if DEBUG_CONSFILE_IO
1146 		if (cfp->debugwfd != -1)
1147 		    write(cfp->debugwfd, buf, retval);
1148 # endif
1149 		buf += retval;
1150 		len -= retval;
1151 		len_out += retval;
1152 	    }
1153 	    break;
1154 #endif
1155 	default:
1156 	    retval = -1;
1157 	    break;
1158     }
1159 
1160     /* so, if we saw an error, just bail...all is done anyway */
1161     if (retval >= 0) {
1162 	if (len_out > 0) {
1163 	    /* save the rest for later */
1164 	    if (len > 0) {
1165 		ShiftString(cfp->wbuf, len_out);
1166 	    } else {
1167 		BuildString((char *)0, cfp->wbuf);
1168 	    }
1169 	}
1170 	retval = len_out;
1171     }
1172 
1173     if (retval < 0) {
1174 	if (cfp->wbuf->used > 1)
1175 	    BuildString((char *)0, cfp->wbuf);
1176 	cfp->errored = FLAGTRUE;
1177     }
1178 
1179     if (cfp->wbuf->used <= 1)
1180 	FD_CLR(fdout, &winit);
1181     else {
1182 	FD_SET(fdout, &winit);
1183 	CONDDEBUG((2, "FileWrite(): buffered %d byte%s for fd %d",
1184 		   (cfp->wbuf->used <= 1) ? 0 : cfp->wbuf->used,
1185 		   (cfp->wbuf->used <= 1) ? "" : "s", fdout));
1186     }
1187 
1188     if (retval >= 0) {
1189 	CONDDEBUG((2, "FileWrite(): wrote %d byte%s to fd %d", retval,
1190 		   (retval == 1) ? "" : "s", fdout));
1191     } else {
1192 	CONDDEBUG((2, "FileWrite(): write of %d byte%s to fd %d: %s",
1193 		   len_orig, (retval == -1) ? "" : "s", fdout,
1194 		   strerror(errno)));
1195     }
1196 
1197     return retval;
1198 }
1199 
1200 int
FileCanRead(CONSFILE * cfp,fd_set * prfd,fd_set * pwfd)1201 FileCanRead(CONSFILE *cfp, fd_set *prfd, fd_set *pwfd)
1202 {
1203 #if HAVE_OPENSSL
1204     int fdout;
1205 #endif
1206 
1207     if (cfp == (CONSFILE *)0)
1208 	return 0;
1209 
1210 #if HAVE_OPENSSL
1211     if (cfp->ftype == simplePipe)
1212 	fdout = cfp->fdout;
1213     else
1214 	fdout = cfp->fd;
1215 #endif
1216 
1217     return ((FD_ISSET(cfp->fd, prfd)
1218 #if HAVE_OPENSSL
1219 	     && cfp->waitForRead != FLAGTRUE) || (fdout >= 0 &&
1220 						  FD_ISSET(fdout, pwfd)
1221 						  && cfp->waitForWrite ==
1222 						  FLAGTRUE
1223 #endif
1224 	    ));
1225 }
1226 
1227 int
FileCanWrite(CONSFILE * cfp,fd_set * prfd,fd_set * pwfd)1228 FileCanWrite(CONSFILE *cfp, fd_set *prfd, fd_set *pwfd)
1229 {
1230     int fdout;
1231 
1232     if (cfp == (CONSFILE *)0)
1233 	return 0;
1234 
1235     if (cfp->ftype == simplePipe)
1236 	fdout = cfp->fdout;
1237     else
1238 	fdout = cfp->fd;
1239 
1240     return ((FD_ISSET(fdout, pwfd)
1241 #if HAVE_OPENSSL
1242 	     && cfp->waitForWrite != FLAGTRUE) || (FD_ISSET(cfp->fd, prfd)
1243 						   && cfp->waitForRead ==
1244 						   FLAGTRUE
1245 #endif
1246 	    ));
1247 }
1248 
1249 int
FileBufEmpty(CONSFILE * cfp)1250 FileBufEmpty(CONSFILE *cfp)
1251 {
1252     if (cfp == (CONSFILE *)0)
1253 	return 1;
1254     return (cfp->wbuf->used <= 1);
1255 }
1256 
1257 void
VWrite(CONSFILE * cfp,FLAG bufferonly,STRING * str,char * fmt,va_list ap)1258 VWrite(CONSFILE *cfp, FLAG bufferonly, STRING *str, char *fmt, va_list ap)
1259 {
1260     int s, l, e;
1261     char c;
1262     int fmtlen = 0;
1263     int fmtpre = 0;
1264     short padzero = 0;
1265     short sawdot = 0;
1266     static STRING *msg = (STRING *)0;
1267     static STRING *output = (STRING *)0;
1268     short flong = 0, fneg = 0, fminus = 0;
1269 
1270     if (fmt == (char *)0 || (cfp == (CONSFILE *)0 && str == (STRING *)0))
1271 	return;
1272 
1273     if (msg == (STRING *)0)
1274 	msg = AllocString();
1275     if (output == (STRING *)0)
1276 	output = AllocString();
1277 
1278     BuildString((char *)0, output);
1279 
1280     for (e = s = l = 0; (c = fmt[s + l]) != '\000'; l++) {
1281 	if (e == 0 && c == '%') {
1282 	    e = 1;
1283 	    BuildStringN(fmt + s, l, output);
1284 	    s += l;
1285 	    l = 0;
1286 	    continue;
1287 	}
1288 	if (e) {
1289 	    unsigned long i;
1290 	    int u;
1291 	    char *p;
1292 	    char cc;
1293 	    if (c >= '0' && c <= '9') {
1294 		if (sawdot == 0) {
1295 		    if (c == '0' && fmtlen == 0)
1296 			padzero = 1;
1297 		    fmtlen = fmtlen * 10 + (c - '0');
1298 		} else {
1299 		    fmtpre = fmtpre * 10 + (c - '0');
1300 		}
1301 	    } else {
1302 		switch (c) {
1303 		    case '.':
1304 			sawdot = 1;
1305 			continue;
1306 		    case '-':
1307 			fminus = 1;
1308 			continue;
1309 		    case 'h':
1310 			/* noop since shorts are promoted to int in va_arg */
1311 			continue;
1312 		    case 'l':
1313 			flong = 1;
1314 			continue;
1315 		    case '%':
1316 			BuildStringChar('%', output);
1317 			break;
1318 		    case 'c':
1319 			cc = (char)va_arg(ap, int);
1320 			BuildStringChar(cc, output);
1321 			break;
1322 		    case 's':
1323 			p = va_arg(ap, char *);
1324 			if (p == (char *)0)
1325 			    p = "(null)";
1326 			{
1327 			    int l = strlen(p);
1328 			    int c;
1329 			    if (fmtpre > 0 && fmtpre < l)
1330 				l = fmtpre;
1331 			    if (fminus != 0)
1332 				BuildStringN(p, l, output);
1333 			    for (c = l; c < fmtlen; c++)
1334 				BuildStringChar(' ', output);
1335 			    if (fminus == 0)
1336 				BuildStringN(p, l, output);
1337 			}
1338 			break;
1339 		    case 'd':
1340 			i = (flong ? va_arg(ap, long) : (long)
1341 			     va_arg(ap, int));
1342 			if ((long)i < 0) {
1343 			    fneg = 1;
1344 			    i = -i;
1345 			}
1346 			goto number;
1347 		    case 'u':
1348 			i = (flong ? va_arg(ap, unsigned long)
1349 			     : (unsigned long)va_arg(ap, unsigned int));
1350 		      number:
1351 			BuildString((char *)0, msg);
1352 			while (i >= 10) {
1353 			    BuildStringChar((i % 10) + '0', msg);
1354 			    i /= 10;
1355 			}
1356 			BuildStringChar(i + '0', msg);
1357 			if (fneg)
1358 			    BuildStringChar('-', msg);
1359 
1360 			if (fmtpre > 0) {
1361 			    padzero = 0;
1362 			    if (fmtpre > fmtlen)
1363 				fmtlen = fmtpre;
1364 			    while (msg->used - 1 < fmtpre)
1365 				BuildStringChar('0', msg);
1366 			}
1367 
1368 			/* reverse the text to put it in forward order
1369 			 */
1370 			u = msg->used - 1;
1371 			for (i = 0; i < u / 2; i++) {
1372 			    char temp;
1373 
1374 			    temp = msg->string[i];
1375 			    msg->string[i]
1376 				= msg->string[u - i - 1];
1377 			    msg->string[u - i - 1] = temp;
1378 			}
1379 
1380 			{
1381 			    int l = msg->used - 1;
1382 			    if (fminus != 0)
1383 				BuildString(msg->string, output);
1384 			    for (; l < fmtlen; l++) {
1385 				if (padzero == 0 || fminus != 0)
1386 				    BuildStringChar(' ', output);
1387 				else
1388 				    BuildStringChar('0', output);
1389 			    }
1390 			    if (fminus == 0)
1391 				BuildString(msg->string, output);
1392 			}
1393 			break;
1394 		    case 'X':
1395 		    case 'x':
1396 			i = (flong ? va_arg(ap, unsigned long)
1397 			     : (unsigned long)va_arg(ap, unsigned int));
1398 			BuildString((char *)0, msg);
1399 			while (i >= 16) {
1400 			    if (i % 16 >= 10)
1401 				BuildStringChar((i % 16) - 10 +
1402 						(c == 'x' ? 'a' : 'A'),
1403 						msg);
1404 			    else
1405 				BuildStringChar((i % 16) + '0', msg);
1406 			    i /= 16;
1407 			}
1408 			if (i >= 10)
1409 			    BuildStringChar(i - 10 +
1410 					    (c == 'x' ? 'a' : 'A'), msg);
1411 			else
1412 			    BuildStringChar(i + '0', msg);
1413 
1414 			if (fmtpre > 0) {
1415 			    padzero = 0;
1416 			    if (fmtpre > fmtlen)
1417 				fmtlen = fmtpre;
1418 			    while (msg->used - 1 < fmtpre)
1419 				BuildStringChar('0', msg);
1420 			}
1421 
1422 			/* reverse the text to put it in forward order
1423 			 */
1424 			u = msg->used - 1;
1425 			for (i = 0; i < u / 2; i++) {
1426 			    char temp;
1427 
1428 			    temp = msg->string[i];
1429 			    msg->string[i]
1430 				= msg->string[u - i - 1];
1431 			    msg->string[u - i - 1] = temp;
1432 			}
1433 
1434 			{
1435 			    int l = msg->used - 1;
1436 			    if (fminus != 0)
1437 				BuildString(msg->string, output);
1438 			    for (; l < fmtlen; l++) {
1439 				if (padzero == 0 || fminus != 0)
1440 				    BuildStringChar(' ', output);
1441 				else
1442 				    BuildStringChar('0', output);
1443 			    }
1444 			    if (fminus == 0)
1445 				BuildString(msg->string, output);
1446 			}
1447 			break;
1448 		    default:
1449 			Error
1450 			    ("VWrite(): unknown conversion character `%c' in `%s'",
1451 			     c, fmt);
1452 			break;
1453 		}
1454 		s += l + 1;
1455 		l = -1;
1456 		e = flong = fneg = fminus = 0;
1457 		fmtlen = fmtpre = sawdot = padzero = 0;
1458 	    }
1459 	}
1460     }
1461     if (l)
1462 	BuildStringN(fmt + s, l, output);
1463 
1464     if (str != (STRING *)0)
1465 	BuildString((char *)0, str);
1466 
1467     if (output->used > 1) {
1468 	if (str != (STRING *)0)
1469 	    BuildStringN(output->string, output->used - 1, str);
1470 	if (cfp != (CONSFILE *)0)
1471 	    FileWrite(cfp, bufferonly, output->string, output->used - 1);
1472     }
1473 }
1474 
1475 char *
BuildStringPrint(STRING * str,char * fmt,...)1476 BuildStringPrint(STRING *str, char *fmt, ...)
1477 {
1478     va_list ap;
1479     va_start(ap, fmt);
1480     VWrite((CONSFILE *)0, FLAGFALSE, str, fmt, ap);
1481     va_end(ap);
1482     if (str == (STRING *)0)
1483 	return (char *)0;
1484     else
1485 	return str->string;
1486 }
1487 
1488 char *
BuildTmpStringPrint(char * fmt,...)1489 BuildTmpStringPrint(char *fmt, ...)
1490 {
1491     va_list ap;
1492     va_start(ap, fmt);
1493     if (mymsg == (STRING *)0)
1494 	mymsg = AllocString();
1495     VWrite((CONSFILE *)0, FLAGFALSE, mymsg, fmt, ap);
1496     va_end(ap);
1497     return mymsg->string;
1498 }
1499 
1500 void
FileVWrite(CONSFILE * cfp,FLAG bufferonly,char * fmt,va_list ap)1501 FileVWrite(CONSFILE *cfp, FLAG bufferonly, char *fmt, va_list ap)
1502 {
1503     VWrite(cfp, bufferonly, (STRING *)0, fmt, ap);
1504 }
1505 
1506 void
FilePrint(CONSFILE * cfp,FLAG bufferonly,char * fmt,...)1507 FilePrint(CONSFILE *cfp, FLAG bufferonly, char *fmt, ...)
1508 {
1509     va_list ap;
1510     va_start(ap, fmt);
1511     FileVWrite(cfp, bufferonly, fmt, ap);
1512     va_end(ap);
1513 }
1514 
1515 /* Unless otherwise stated, returns the same values as fstat(2) */
1516 int
FileStat(CONSFILE * cfp,struct stat * buf)1517 FileStat(CONSFILE *cfp, struct stat *buf)
1518 {
1519     int retval = 0;
1520 
1521     if (cfp->errored == FLAGTRUE)
1522 	return -1;
1523 
1524     switch (cfp->ftype) {
1525 	case simpleFile:
1526 	    retval = fstat(cfp->fd, buf);
1527 	    break;
1528 	case simplePipe:
1529 	    retval = -1;
1530 	    break;
1531 	case simpleSocket:
1532 	    retval = fstat(cfp->fd, buf);
1533 	    break;
1534 #if HAVE_OPENSSL
1535 	case SSLSocket:
1536 	    retval = -1;
1537 	    break;
1538 #endif
1539 	default:
1540 	    retval = -1;
1541 	    break;
1542     }
1543 
1544     if (retval < 0)
1545 	cfp->errored = FLAGTRUE;
1546 
1547     return retval;
1548 }
1549 
1550 /* Unless otherwise stated, returns the same values as lseek(2) */
1551 int
FileSeek(CONSFILE * cfp,off_t offset,int whence)1552 FileSeek(CONSFILE *cfp, off_t offset, int whence)
1553 {
1554     int retval = 0;
1555 
1556     if (cfp->errored == FLAGTRUE)
1557 	return -1;
1558 
1559     switch (cfp->ftype) {
1560 	case simpleFile:
1561 	    retval = lseek(cfp->fd, offset, whence);
1562 	    break;
1563 	case simplePipe:
1564 	    retval = -1;
1565 	    break;
1566 	case simpleSocket:
1567 	    retval = lseek(cfp->fd, offset, whence);
1568 	    break;
1569 #if HAVE_OPENSSL
1570 	case SSLSocket:
1571 	    retval = -1;
1572 	    break;
1573 #endif
1574 	default:
1575 	    retval = -1;
1576 	    break;
1577     }
1578 
1579     if (retval < 0)
1580 	cfp->errored = FLAGTRUE;
1581 
1582     return retval;
1583 }
1584 
1585 /* Returns the file descriptor number of the underlying file */
1586 int
FileFDNum(CONSFILE * cfp)1587 FileFDNum(CONSFILE *cfp)
1588 {
1589     int retval = 0;
1590 
1591     if (cfp == (CONSFILE *)0)
1592 	return -1;
1593 
1594     switch (cfp->ftype) {
1595 	case simpleFile:
1596 	    retval = cfp->fd;
1597 	    break;
1598 	case simplePipe:
1599 	    retval = cfp->fd;
1600 	    break;
1601 	case simpleSocket:
1602 	    retval = cfp->fd;
1603 	    break;
1604 #if HAVE_OPENSSL
1605 	case SSLSocket:
1606 	    retval = cfp->fd;
1607 	    break;
1608 #endif
1609 	default:
1610 	    retval = cfp->fd;
1611 	    break;
1612     }
1613 
1614     return retval;
1615 }
1616 
1617 /* Returns the file descriptor number of the underlying file */
1618 int
FileFDOutNum(CONSFILE * cfp)1619 FileFDOutNum(CONSFILE *cfp)
1620 {
1621     if (cfp == (CONSFILE *)0 || cfp->ftype != simplePipe)
1622 	return -1;
1623 
1624     return cfp->fdout;
1625 }
1626 
1627 /* Returns the file type */
1628 enum consFileType
FileGetType(CONSFILE * cfp)1629 FileGetType(CONSFILE *cfp)
1630 {
1631     switch (cfp->ftype) {
1632 	case simpleFile:
1633 	    return simpleFile;
1634 	case simplePipe:
1635 	    return simplePipe;
1636 	case simpleSocket:
1637 	    return simpleSocket;
1638 #if HAVE_OPENSSL
1639 	case SSLSocket:
1640 	    return SSLSocket;
1641 #endif
1642 	default:
1643 	    return nothing;
1644     }
1645 }
1646 
1647 /* Sets the file type */
1648 void
FileSetType(CONSFILE * cfp,enum consFileType type)1649 FileSetType(CONSFILE *cfp, enum consFileType type)
1650 {
1651     cfp->ftype = type;
1652 }
1653 
1654 /* Sets the file quoting method */
1655 void
FileSetQuoteIAC(CONSFILE * cfp,FLAG flag)1656 FileSetQuoteIAC(CONSFILE *cfp, FLAG flag)
1657 {
1658     cfp->quoteiac = flag;
1659 }
1660 
1661 FLAG
FileSawQuoteSusp(CONSFILE * cfp)1662 FileSawQuoteSusp(CONSFILE *cfp)
1663 {
1664     FLAG r = cfp->sawiacsusp;
1665     cfp->sawiacsusp = FLAGFALSE;
1666     return r;
1667 }
1668 
1669 FLAG
FileSawQuoteExec(CONSFILE * cfp)1670 FileSawQuoteExec(CONSFILE *cfp)
1671 {
1672     FLAG r = cfp->sawiacexec;
1673     cfp->sawiacexec = FLAGFALSE;
1674     return r;
1675 }
1676 
1677 FLAG
FileSawQuoteAbrt(CONSFILE * cfp)1678 FileSawQuoteAbrt(CONSFILE *cfp)
1679 {
1680     FLAG r = cfp->sawiacabrt;
1681     cfp->sawiacabrt = FLAGFALSE;
1682     return r;
1683 }
1684 
1685 FLAG
FileSawQuoteGoto(CONSFILE * cfp)1686 FileSawQuoteGoto(CONSFILE *cfp)
1687 {
1688     FLAG r = cfp->sawiacgoto;
1689     cfp->sawiacgoto = FLAGFALSE;
1690     return r;
1691 }
1692 
1693 #if HAVE_OPENSSL
1694 /* Get the SSL instance */
1695 SSL *
FileGetSSL(CONSFILE * cfp)1696 FileGetSSL(CONSFILE *cfp)
1697 {
1698     return cfp->ssl;
1699 }
1700 
1701 /* Sets the SSL instance */
1702 void
FileSetSSL(CONSFILE * cfp,SSL * ssl)1703 FileSetSSL(CONSFILE *cfp, SSL *ssl)
1704 {
1705     cfp->ssl = ssl;
1706 }
1707 
1708 /* return -1 on error, 0 for "wait" state, 1 for success */
1709 int
FileCanSSLAccept(CONSFILE * cfp,fd_set * prfd,fd_set * pwfd)1710 FileCanSSLAccept(CONSFILE *cfp, fd_set *prfd, fd_set *pwfd)
1711 {
1712     if (cfp == (CONSFILE *)0)
1713 	return 0;
1714 
1715     return ((FD_ISSET(cfp->fd, prfd) && cfp->waitForRead == FLAGTRUE) ||
1716 	    (FD_ISSET(cfp->fd, pwfd) && cfp->waitForWrite == FLAGTRUE) ||
1717 	    (cfp->waitForRead != FLAGTRUE &&
1718 	     cfp->waitForWrite != FLAGTRUE));
1719 }
1720 
1721 /* return -1 on error, 0 for "wait" state, 1 for success */
1722 int
FileSSLAccept(CONSFILE * cfp)1723 FileSSLAccept(CONSFILE *cfp)
1724 {
1725     int retval;
1726     if (cfp->waitForWrite == FLAGTRUE) {
1727 	cfp->waitForWrite = FLAGFALSE;
1728 	if (cfp->wbuf->used <= 1)
1729 	    FD_CLR(cfp->fd, &winit);
1730     }
1731     cfp->waitForRead = FLAGFALSE;
1732 
1733     CONDDEBUG((1, "FileSSLAccept(): about to SSL_accept() for fd %d",
1734 	       cfp->fd));
1735     retval = SSL_accept(cfp->ssl);
1736     switch (SSL_get_error(cfp->ssl, retval)) {
1737 	case SSL_ERROR_NONE:
1738 	    break;
1739 	case SSL_ERROR_WANT_READ:
1740 	    cfp->waitForRead = FLAGTRUE;
1741 	    return 0;
1742 	case SSL_ERROR_WANT_WRITE:
1743 	    cfp->waitForWrite = FLAGTRUE;
1744 	    FD_SET(cfp->fd, &winit);
1745 	    return 0;
1746 	default:
1747 	    Error("FileSSLAccept(): SSL error on fd %d", cfp->fd);
1748 	    /* fall through */
1749 	case SSL_ERROR_ZERO_RETURN:
1750 	    SSL_free(cfp->ssl);
1751 	    cfp->ssl = (SSL *)0;
1752 	    cfp->ftype = simpleSocket;
1753 	    return -1;
1754     }
1755     cfp->ftype = SSLSocket;
1756     CONDDEBUG((1, "FileSSLAccept(): SSL Connection: %s :: %s",
1757 	       SSL_get_cipher_version(cfp->ssl),
1758 	       SSL_get_cipher_name(cfp->ssl)));
1759     return 1;
1760 }
1761 #endif
1762 
1763 /* Unless otherwise stated, returns the same values as send(2) */
1764 int
FileSend(CONSFILE * cfp,const void * msg,size_t len,int flags)1765 FileSend(CONSFILE *cfp, const void *msg, size_t len, int flags)
1766 {
1767     int retval = 0;
1768     int fdout;
1769 
1770     if (cfp->ftype == simplePipe)
1771 	fdout = cfp->fdout;
1772     else
1773 	fdout = cfp->fd;
1774 
1775     if (cfp->errored == FLAGTRUE) {
1776 	FD_CLR(fdout, &winit);
1777 	return -1;
1778     }
1779 
1780     switch (cfp->ftype) {
1781 	case simpleFile:
1782 	    retval = send(fdout, msg, len, flags);
1783 	    break;
1784 	case simplePipe:
1785 	    retval = send(fdout, msg, len, flags);
1786 	    break;
1787 	case simpleSocket:
1788 	    retval = send(fdout, msg, len, flags);
1789 	    break;
1790 #if HAVE_OPENSSL
1791 	case SSLSocket:
1792 	    retval = send(fdout, msg, len, flags);
1793 	    break;
1794 #endif
1795 	default:
1796 	    retval = -1;
1797 	    break;
1798     }
1799 
1800     if (retval < 0) {
1801 	cfp->errored = FLAGTRUE;
1802 	FD_CLR(fdout, &winit);
1803     }
1804 
1805     return retval;
1806 }
1807 
1808 /* replace trailing space with '\000' in a string and return
1809  * a pointer to the start of the non-space part
1810  */
1811 char *
PruneSpace(char * string)1812 PruneSpace(char *string)
1813 {
1814     char *p;
1815     char *head = (char *)0;
1816     char *tail = (char *)0;
1817 
1818     /* Don't do much if it's crap */
1819     if (string == (char *)0 || *string == '\000')
1820 	return string;
1821 
1822     /* Now for the tricky part - search the string */
1823     for (p = string; *p != '\000'; p++) {
1824 	if (isspace((int)(*p))) {
1825 	    if (tail == (char *)0)
1826 		tail = p;	/* possible end of string */
1827 	} else {
1828 	    if (head == (char *)0)
1829 		head = p;	/* found the start */
1830 	    tail = (char *)0;	/* reset tail */
1831 	}
1832     }
1833 
1834     if (tail != (char *)0)
1835 	*tail = '\000';
1836 
1837     if (head != (char *)0)
1838 	return head;
1839     else
1840 	return string;
1841 }
1842 
1843 #if !USE_IPV6
1844 /* fills the myAddrs array with host interface addresses */
1845 void
ProbeInterfaces(in_addr_t bindAddr)1846 ProbeInterfaces(in_addr_t bindAddr)
1847 {
1848 # ifdef SIOCGIFCONF
1849     struct ifconf ifc;
1850     struct ifreq *ifr;
1851 #  ifdef SIOCGIFFLAGS
1852     struct ifreq ifrcopy;
1853 #  endif
1854 #  ifdef SIOCGIFNUM
1855     int nifr;
1856 #  endif
1857     int sock;
1858     int r = 0, m = 0;
1859     int bufsize = 2048;
1860     int count = 0;
1861 
1862     /* if we use -M, just fill the array with that interface */
1863     if (bindAddr != INADDR_ANY) {
1864 	myAddrs = (struct in_addr *)calloc(2, sizeof(struct in_addr));
1865 	if (myAddrs == (struct in_addr *)0)
1866 	    OutOfMem();
1867 #  if HAVE_MEMCPY
1868 	memcpy(&(myAddrs[0].s_addr), &bindAddr, sizeof(in_addr_t));
1869 #  else
1870 	bcopy(&bindAddr, &(myAddrs[0].s_addr), sizeof(in_addr_t));
1871 #  endif
1872 	Verbose("interface address %s (-M option)", inet_ntoa(myAddrs[0]));
1873 	return;
1874     }
1875 
1876     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
1877 	Error("ProbeInterfaces(): socket(): %s", strerror(errno));
1878 	Bye(EX_OSERR);
1879     }
1880 #  ifdef SIOCGIFNUM
1881     if (ioctl(sock, SIOCGIFNUM, &nifr) == 0)
1882 	bufsize = nifr * sizeof(struct ifreq) + 512;
1883 #  endif
1884 
1885     while (bufsize) {
1886 	ifc.ifc_len = bufsize;
1887 	ifc.ifc_req = (struct ifreq *)malloc(ifc.ifc_len);
1888 	if (ifc.ifc_req == (struct ifreq *)0)
1889 	    OutOfMem();
1890 	if (ioctl(sock, SIOCGIFCONF, &ifc) != 0 && errno != EINVAL) {
1891 	    free(ifc.ifc_req);
1892 	    close(sock);
1893 	    Error("ProbeInterfaces(): ioctl(SIOCGIFCONF): %s",
1894 		  strerror(errno));
1895 	    Bye(EX_OSERR);
1896 	}
1897 	/* if the return size plus a 512 byte "buffer zone" is less than
1898 	 * the buffer we passed in (bufsize), we're done.  otherwise
1899 	 * allocate a bigger buffer and try again.  with a too-small
1900 	 * buffer, some implementations (freebsd) will fill the buffer
1901 	 * best it can (leaving a gap - returning <=bufsize) and others
1902 	 * (linux) will return a buffer length the same size as passed
1903 	 * in (==bufsize).  so, we'll assume a 512 byte gap would have
1904 	 * been big enough to put one more record and as long as we have
1905 	 * that "buffer zone", we should have all the interfaces.
1906 	 * so, solaris returns EINVAL if it's too small, so we catch that
1907 	 * above and since if_len is bufsize, it'll loop again.
1908 	 */
1909 	if (ifc.ifc_len + 512 < bufsize)
1910 	    break;
1911 	free(ifc.ifc_req);
1912 	bufsize += 2048;
1913     }
1914 
1915     /* this is probably way overkill, but better to kill a few bytes
1916      * than loop through looking for valid interfaces that are up
1917      * twice, huh?
1918      */
1919     count = ifc.ifc_len / sizeof(*ifr);
1920     CONDDEBUG((1, "ProbeInterfaces(): ifc_len==%d max_count==%d",
1921 	       ifc.ifc_len, count));
1922 
1923     /* set up myAddrs array */
1924     if (myAddrs != (struct in_addr *)0)
1925 	free(myAddrs);
1926     myAddrs = (struct in_addr *)0;
1927     if (count == 0) {
1928 	free(ifc.ifc_req);
1929 	close(sock);
1930 	return;
1931     }
1932     myAddrs = (struct in_addr *)calloc(count + 1, sizeof(struct in_addr));
1933     if (myAddrs == (struct in_addr *)0)
1934 	OutOfMem();
1935 
1936     for (m = r = 0; r < ifc.ifc_len;) {
1937 	struct sockaddr *sa;
1938 	ifr = (struct ifreq *)&ifc.ifc_buf[r];
1939 	sa = (struct sockaddr *)&ifr->ifr_addr;
1940 	/* don't use less than a ifreq sized chunk */
1941 	if ((ifc.ifc_len - r) < sizeof(*ifr))
1942 	    break;
1943 #  ifdef HAVE_SA_LEN
1944 	if (sa->sa_len > sizeof(ifr->ifr_addr))
1945 	    r += sizeof(ifr->ifr_name) + sa->sa_len;
1946 	else
1947 #  endif
1948 	    r += sizeof(*ifr);
1949 
1950 	if (sa->sa_family == AF_INET) {
1951 	    struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1952 
1953 	    /* make sure the address isn't 0.0.0.0, which is how we
1954 	     * signal the end of our list
1955 	     */
1956 	    if (
1957 #  if HAVE_MEMCMP
1958 		   memcmp(&(myAddrs[m]), &(sin->sin_addr),
1959 			  sizeof(struct in_addr))
1960 #  else
1961 		   bcmp(&(myAddrs[m]), &(sin->sin_addr),
1962 			sizeof(struct in_addr))
1963 #  endif
1964 		   == 0)
1965 		continue;
1966 
1967 #  ifdef SIOCGIFFLAGS
1968 	    /* make sure the interface is up */
1969 	    ifrcopy = *ifr;
1970 	    if ((ioctl(sock, SIOCGIFFLAGS, &ifrcopy) == 0) &&
1971 		((ifrcopy.ifr_flags & IFF_UP) == 0))
1972 		continue;
1973 #  endif
1974 
1975 	    CONDDEBUG((1, "ProbeInterfaces(): name=%s addr=%s",
1976 		       ifr->ifr_name, inet_ntoa(sin->sin_addr)));
1977 
1978 #  if HAVE_MEMCPY
1979 	    memcpy(&myAddrs[m], &(sin->sin_addr), sizeof(struct in_addr));
1980 #  else
1981 	    bcopy(&(sin->sin_addr), &myAddrs[m], sizeof(struct in_addr));
1982 #  endif
1983 
1984 	    Verbose("interface address %s (%s)", inet_ntoa(myAddrs[m]),
1985 		    ifr->ifr_name);
1986 	    m++;
1987 	}
1988     }
1989     if (m == 0) {
1990 	free(myAddrs);
1991 	myAddrs = (struct in_addr *)0;
1992     }
1993     close(sock);
1994     free(ifc.ifc_req);
1995 # else/* use the hostname like the old code did (but use all addresses!) */
1996     int count;
1997     struct hostent *he;
1998 
1999     /* if we use -M, just fill the array with that interface */
2000     if (bindAddr != INADDR_ANY) {
2001 	myAddrs = (struct in_addr *)calloc(2, sizeof(struct in_addr));
2002 	if (myAddrs == (struct in_addr *)0)
2003 	    OutOfMem();
2004 #  if HAVE_MEMCPY
2005 	memcpy(&(myAddrs[0].s_addr), &bindAddr, sizeof(in_addr_t));
2006 #  else
2007 	bcopy(&bindAddr, &(myAddrs[0].s_addr), sizeof(in_addr_t));
2008 #  endif
2009 	Verbose("interface address %s (-M option)", inet_ntoa(myAddrs[0]));
2010 	return;
2011     }
2012 
2013     Verbose("using hostname for interface addresses");
2014     if ((struct hostent *)0 == (he = gethostbyname(myHostname))) {
2015 	Error("ProbeInterfaces(): gethostbyname(%s): %s", myHostname,
2016 	      hstrerror(h_errno));
2017 	return;
2018     }
2019     if (4 != he->h_length || AF_INET != he->h_addrtype) {
2020 	Error
2021 	    ("ProbeInterfaces(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)",
2022 	     myHostname, he->h_length, AF_INET, he->h_addrtype);
2023 	return;
2024     }
2025 
2026     for (count = 0; he->h_addr_list[count] != (char *)0; count++);
2027     if (myAddrs != (struct in_addr *)0)
2028 	free(myAddrs);
2029     myAddrs = (struct in_addr *)0;
2030     if (count == 0)
2031 	return;
2032     myAddrs = (struct in_addr *)calloc(count + 1, sizeof(struct in_addr));
2033     if (myAddrs == (struct in_addr *)0)
2034 	OutOfMem();
2035     for (count--; count >= 0; count--) {
2036 #  if HAVE_MEMCPY
2037 	memcpy(&(myAddrs[count].s_addr), he->h_addr_list[count],
2038 	       he->h_length);
2039 #  else
2040 	bcopy(he->h_addr_list[count], &(myAddrs[count].s_addr),
2041 	      he->h_length);
2042 #  endif
2043 	Verbose("interface address %s (hostname address)",
2044 		inet_ntoa(myAddrs[count]));
2045     }
2046 # endif
2047 }
2048 #endif /* USE_IPV6 */
2049 
2050 int
IsMe(char * id)2051 IsMe(char *id)
2052 {
2053 #if USE_IPV6
2054     int ret = 0;
2055     int error;
2056     struct addrinfo hints;
2057     struct addrinfo *res, *rp;
2058     struct ifaddrs *myAddrs, *ifa;
2059     void *a, *b;
2060     size_t len;
2061 
2062     memset(&hints, 0, sizeof(hints));
2063     hints.ai_family = PF_UNSPEC;
2064 
2065     /* get IP based on hostname */
2066     error = getaddrinfo(id, NULL, &hints, &res);
2067     if (error) {
2068 	perror(gai_strerror(error));
2069 	return 0;
2070     }
2071 
2072     /* get list of all addresses on system */
2073     error = getifaddrs(&myAddrs);
2074     if (error) {
2075 	perror("getifaddrs failed");
2076 	return 0;
2077     }
2078 
2079     /* try to find a match */
2080     for (ifa = myAddrs; ifa != NULL; ifa = ifa->ifa_next) {
2081 	/* skip interfaces without address or in down state */
2082 	if (ifa->ifa_addr == NULL || !(ifa->ifa_flags & IFF_UP))
2083 	    continue;
2084 
2085 	for (rp = res; rp != NULL; rp = rp->ai_next) {
2086 	    if (ifa->ifa_addr->sa_family == rp->ai_addr->sa_family) {
2087 		/* I really don't like to hardcode it but we have to */
2088 		if (ifa->ifa_addr->sa_family == AF_INET) {	/* IPv4 */
2089 		    a = &(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr);
2090 		    b = &(((struct sockaddr_in *)rp->ai_addr)->sin_addr);
2091 		    len = sizeof(struct in_addr);
2092 		} else {	/* IPv6 */
2093 		    a = &(((struct sockaddr_in6 *)ifa->
2094 			   ifa_addr)->sin6_addr);
2095 		    b = &(((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr);
2096 		    len = sizeof(struct in6_addr);
2097 		}
2098 
2099 		if (
2100 # if HAVE_MEMCMP
2101 		       memcmp(a, b, len)
2102 # else
2103 		       bcmp(a, b, len)
2104 # endif
2105 		       == 0) {
2106 		    ret = 1;
2107 		    goto done;
2108 		}
2109 	    }
2110 	}
2111     }
2112 
2113   done:
2114     freeaddrinfo(res);
2115     freeifaddrs(myAddrs);
2116     CONDDEBUG((1, "IsMe: ret %d id %s", ret, id));
2117     return ret;
2118 #else
2119     int j, i;
2120     struct hostent *he;
2121     in_addr_t addr;
2122 # if HAVE_INET_ATON
2123     struct in_addr inetaddr;
2124 # endif
2125 
2126     /* check for ip address match */
2127 # if HAVE_INET_ATON
2128     if (inet_aton(id, &inetaddr) != 0) {
2129 	addr = inetaddr.s_addr;
2130 # else
2131     addr = inet_addr(id);
2132     if (addr != (in_addr_t) (-1)) {
2133 # endif
2134 	for (i = 0;
2135 	     myAddrs != (struct in_addr *)0 &&
2136 	     myAddrs[i].s_addr != (in_addr_t) 0; i++) {
2137 	    if (
2138 # if HAVE_MEMCMP
2139 		   memcmp(&(myAddrs[i].s_addr), &addr, sizeof(addr))
2140 # else
2141 		   bcmp(&(myAddrs[i].s_addr), &addr, sizeof(addr))
2142 # endif
2143 		   == 0)
2144 		return 1;
2145 	}
2146 	return 0;
2147     }
2148 
2149     /* check for ip match of hostname */
2150     if ((struct hostent *)0 == (he = gethostbyname(id))) {
2151 	Error("IsMe(): gethostbyname(%s): %s", id, hstrerror(h_errno));
2152 	return 0;
2153     }
2154     if (4 != he->h_length || AF_INET != he->h_addrtype) {
2155 	Error
2156 	    ("IsMe(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)",
2157 	     id, he->h_length, AF_INET, he->h_addrtype);
2158 	return 0;
2159     }
2160 
2161     for (j = 0; he->h_addr_list[j] != (char *)0; j++) {
2162 	for (i = 0;
2163 	     myAddrs != (struct in_addr *)0 &&
2164 	     myAddrs[i].s_addr != (in_addr_t) 0; i++) {
2165 	    if (
2166 # if HAVE_MEMCMP
2167 		   memcmp(&(myAddrs[i].s_addr), he->h_addr_list[j],
2168 			  he->h_length)
2169 # else
2170 		   bcmp(&(myAddrs[i].s_addr), he->h_addr_list[j],
2171 			he->h_length)
2172 # endif
2173 		   == 0)
2174 		return 1;
2175 	}
2176     }
2177     return 0;
2178 #endif /* USE_IPV6 */
2179 }
2180 
2181 #if HAVE_OPENSSL
2182 /* Unless otherwise stated, returns the same values as send(2) */
2183 int
2184 SSLVerifyCallback(int ok, X509_STORE_CTX *store)
2185 {
2186     char data[256];
2187     if (ok) {
2188 	if (fDebug) {
2189 	    X509 *cert = X509_STORE_CTX_get_current_cert(store);
2190 	    int depth = X509_STORE_CTX_get_error_depth(store);
2191 
2192 	    CONDDEBUG((1,
2193 		       "SSLVerifyCallback(): info of certificate at depth: %d",
2194 		       depth));
2195 	    X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
2196 	    CONDDEBUG((1, "SSLVerifyCallback():   issuer  = %s", data));
2197 	    X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
2198 	    CONDDEBUG((1, "SSLVerifyCallback():   subject = %s", data));
2199 	}
2200     } else {
2201 	X509 *cert = X509_STORE_CTX_get_current_cert(store);
2202 	int depth = X509_STORE_CTX_get_error_depth(store);
2203 	int err = X509_STORE_CTX_get_error(store);
2204 
2205 	Error("SSLVerifyCallback(): error with certificate at depth: %d",
2206 	      depth);
2207 	X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
2208 	Error("SSLVerifyCallback():  issuer  = %s", data);
2209 	X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
2210 	Error("SSLVerifyCallback():  subject = %s", data);
2211 	Error("SSLVerifyCallback():  error #%d: %s", err,
2212 	      X509_verify_cert_error_string(err));
2213     }
2214     return ok;
2215 }
2216 #endif
2217 
2218 int
2219 SetFlags(int fd, int s, int c)
2220 {
2221     int flags;
2222 
2223     if ((flags = fcntl(fd, F_GETFL)) >= 0) {
2224 	flags |= s;
2225 	flags &= ~c;
2226 	if (fcntl(fd, F_SETFL, flags) < 0) {
2227 	    Error("SetFlags(): fcntl(%u,F_SETFL): %s", fd,
2228 		  strerror(errno));
2229 	    return 0;
2230 	}
2231     } else {
2232 	Error("SetFlags(): fcntl(%u,F_GETFL): %s", fd, strerror(errno));
2233 	return 0;
2234     }
2235     return 1;
2236 }
2237 
2238 char *
2239 StrDup(const char *msg)
2240 {
2241     int len;
2242     char *buf;
2243 
2244     if (msg == (char *)0)
2245 	return (char *)0;
2246     len = strlen(msg) + 1;
2247     buf = malloc(len);
2248     if (buf == (char *)0)
2249 	return (char *)0;
2250 #if HAVE_MEMCPY
2251     memcpy(buf, msg, len);
2252 #else
2253     bcopy(msg, buf, len);
2254 #endif
2255     return buf;
2256 }
2257 
2258 char *
2259 StringChar(STRING *msg, int offset, char c)
2260 {
2261     int o;
2262 
2263     if (msg == (STRING *)0 || msg->used <= 1 || offset < 0 ||
2264 	offset > msg->used)
2265 	return (char *)0;
2266 
2267     for (o = offset; o != msg->used; o++) {
2268 	if (msg->string[o] == c)
2269 	    return &(msg->string[o]);
2270     }
2271     return (char *)0;
2272 }
2273 
2274 /* this takes a buffer, and returns the number of characters to use,
2275  * which goes up to the first OB_IAC character sequence (that isn't
2276  * OB_IAC/OB_IAC).  if it is an OB_IAC sequence, it sets the flag and
2277  * returns zero.  if it's invalid args, we return -1.
2278  * so <0 == no data, 0 == check flags, >0 number of chars to use
2279  * this *WILL* modify the buffer (OB_IAC sequences get extracted/shrunk)
2280  */
2281 int
2282 ParseIACBuf(CONSFILE *cfp, void *msg, int *len)
2283 {
2284     int l = 0;
2285     unsigned char *b = msg;
2286 
2287     if (*len <= 0)
2288 	return -1;
2289 
2290     if (cfp->quoteiac != FLAGTRUE)
2291 	return *len;
2292 
2293     /* split OB_IAC/char pair OR OB_IAC at start */
2294     if (cfp->sawiac == FLAGTRUE || b[0] == OB_IAC) {
2295 	int i = 1;
2296 
2297 	if (cfp->sawiac == FLAGTRUE) {
2298 	    i = 0;
2299 	    cfp->sawiac = FLAGFALSE;
2300 	}
2301 	if (i == *len) {	/* only thing is OB_IAC */
2302 	    cfp->sawiac = FLAGTRUE;
2303 	    return -1;
2304 	}
2305 
2306 	if (b[i] == OB_SUSP)
2307 	    cfp->sawiacsusp = FLAGTRUE;
2308 	else if (b[i] == OB_EXEC)
2309 	    cfp->sawiacexec = FLAGTRUE;
2310 	else if (b[i] == OB_ABRT)
2311 	    cfp->sawiacabrt = FLAGTRUE;
2312 	else if (b[i] == OB_GOTO)
2313 	    cfp->sawiacgoto = FLAGTRUE;
2314 	else {
2315 	    if (b[i] != OB_IAC)
2316 		Error
2317 		    ("ParseIACBuf(): fd %d: unrecognized quoted-OB_IAC char",
2318 		     cfp->fd, strerror(errno));
2319 	    l = 1;
2320 	}
2321 	*len = *len - i - 1 + l;
2322 	MemMove(b, b + i + 1 - l, *len);
2323 	if (l == 0)
2324 	    return 0;
2325     }
2326     for (; l < *len; l++) {
2327 	if (b[l] == OB_IAC) {
2328 	    if (l + 1 == *len)
2329 		return l;
2330 
2331 	    if (b[l + 1] == OB_IAC) {
2332 		--(*len);
2333 		MemMove(b + l, b + l + 1, *len - l);
2334 	    } else {
2335 		return l;
2336 	    }
2337 	}
2338     }
2339     return l;
2340 }
2341 
2342 /* the format of the file should be as follows
2343  *
2344  * <section keyword> [section name] {
2345  *      <item keyword> [item value];
2346  *                   .
2347  *                   .
2348  * }
2349  *
2350  * whitespace gets retained in [section name], and [item value]
2351  * values.  for example,
2352  *
2353  *    users  bryan  todd ;
2354  *
2355  *  will give users the value of 'bryan  todd'.  the leading and
2356  *  trailing whitespace is nuked, but the middle stuff isn't.
2357  *
2358  *  a little note about the 'state' var...
2359  *      START = before <section keyword>
2360  *      NAME = before [section name]
2361  *      LEFTB = before left curly brace
2362  *      KEY = before <item keyword>
2363  *      VALUE = before [item value]
2364  *      SEMI = before semi-colon
2365  */
2366 
2367 typedef enum states {
2368     START,
2369     NAME,
2370     LEFTB,
2371     KEY,
2372     VALUE,
2373     SEMI
2374 } STATES;
2375 
2376 typedef enum tokens {
2377     DONE,
2378     LEFTBRACE,
2379     RIGHTBRACE,
2380     SEMICOLON,
2381     WORD,
2382     INCLUDE
2383 } TOKEN;
2384 
2385 int line = 1;			/* current line number */
2386 char *file = (char *)0;
2387 
2388 TOKEN
2389 GetWord(FILE *fp, int *line, short spaceok, STRING *word)
2390 {
2391     int c;
2392     short backslash = 0;
2393     short quote = 0;
2394     short comment = 0;
2395     short sawQuote = 0;
2396     short quotedBackslash = 0;
2397     char *include = "include";
2398     short checkInc = -1;
2399     /* checkInc == -3, saw #include
2400      *          == -2, saw nothin'
2401      *          == -1, saw \n or start of file
2402      *          == 0, saw "\n#"
2403      */
2404 
2405     BuildString((char *)0, word);
2406     while ((c = fgetc(fp)) != EOF) {
2407 	if (c == '\n') {
2408 	    (*line)++;
2409 	    if (checkInc == -2)
2410 		checkInc = -1;
2411 	}
2412 	if (comment) {
2413 	    if (c == '\n')
2414 		comment = 0;
2415 	    if (checkInc >= 0) {
2416 		if (include[checkInc] == '\000') {
2417 		    if (isspace(c))
2418 			checkInc = -3;
2419 		} else if (c == include[checkInc])
2420 		    checkInc++;
2421 		else
2422 		    checkInc = -2;
2423 	    } else if (checkInc == -3) {
2424 		static STRING *fname = (STRING *)0;
2425 		if (fname == (STRING *)0)
2426 		    fname = AllocString();
2427 		if (fname->used != 0 || !isspace(c)) {
2428 		    if (c == '\n') {
2429 			if (fname->used > 0) {
2430 			    while (fname->used > 1 && isspace((int)
2431 							      (fname->
2432 							       string
2433 							       [fname->
2434 								used -
2435 								2])))
2436 				fname->used--;
2437 			    if (fname->used > 0)
2438 				fname->string[fname->used - 1] = '\000';
2439 			}
2440 			checkInc = -2;
2441 			if (fname->used > 0) {
2442 			    BuildString((char *)0, word);
2443 			    BuildString(fname->string, word);
2444 			    BuildString((char *)0, fname);
2445 			    return INCLUDE;
2446 			}
2447 		    } else
2448 			BuildStringChar(c, fname);
2449 		}
2450 	    }
2451 	    continue;
2452 	}
2453 	if (backslash) {
2454 	    BuildStringChar(c, word);
2455 	    backslash = 0;
2456 	    continue;
2457 	}
2458 	if (quote) {
2459 	    if (c == '"') {
2460 		if (quotedBackslash) {
2461 		    BuildStringChar(c, word);
2462 		    quotedBackslash = 0;
2463 		} else
2464 		    quote = 0;
2465 	    } else {
2466 		if (quotedBackslash) {
2467 		    BuildStringChar('\\', word);
2468 		    quotedBackslash = 0;
2469 		}
2470 		if (c == '\\')
2471 		    quotedBackslash = 1;
2472 		else
2473 		    BuildStringChar(c, word);
2474 	    }
2475 	    continue;
2476 	}
2477 	if (c == '\\') {
2478 	    backslash = 1;
2479 	} else if (c == '#') {
2480 	    comment = 1;
2481 	    if (checkInc == -1)
2482 		checkInc = 0;
2483 	} else if (c == '"') {
2484 	    quote = 1;
2485 	    sawQuote = 1;
2486 	} else if (isspace(c)) {
2487 	    if (word->used <= 1)
2488 		continue;
2489 	    if (spaceok) {
2490 		BuildStringChar(c, word);
2491 		continue;
2492 	    }
2493 	  gotword:
2494 	    while (word->used > 1 &&
2495 		   isspace((int)(word->string[word->used - 2])))
2496 		word->used--;
2497 	    if (word->used > 0)
2498 		word->string[word->used - 1] = '\000';
2499 	    return WORD;
2500 	} else if (c == '{') {
2501 	    if (word->used <= 1 && !sawQuote) {
2502 		BuildStringChar(c, word);
2503 		return LEFTBRACE;
2504 	    } else {
2505 		ungetc(c, fp);
2506 		goto gotword;
2507 	    }
2508 	} else if (c == '}') {
2509 	    if (word->used <= 1 && !sawQuote) {
2510 		BuildStringChar(c, word);
2511 		return RIGHTBRACE;
2512 	    } else {
2513 		ungetc(c, fp);
2514 		goto gotword;
2515 	    }
2516 	} else if (c == ';') {
2517 	    if (word->used <= 1 && !sawQuote) {
2518 		BuildStringChar(c, word);
2519 		return SEMICOLON;
2520 	    } else {
2521 		ungetc(c, fp);
2522 		goto gotword;
2523 	    }
2524 	} else {
2525 	    BuildStringChar(c, word);
2526 	}
2527     }
2528     /* this should only happen in rare cases */
2529     if (quotedBackslash) {
2530 	BuildStringChar('\\', word);
2531 	quotedBackslash = 0;
2532     }
2533     /* if we saw "valid" data, it's a word */
2534     if (word->used > 1 || sawQuote)
2535 	goto gotword;
2536     return DONE;
2537 }
2538 
2539 void
2540 ParseFile(char *filename, FILE *fp, int level)
2541 {
2542     /* things that should be used between recursions */
2543     static STATES state = START;
2544     static STRING *word = (STRING *)0;
2545     static short spaceok = 0;
2546     static int secIndex = 0;
2547     static int keyIndex = 0;
2548 
2549     /* other stuff that's local to each recursion */
2550     char *p;
2551     TOKEN token = DONE;
2552     int nextline = 1;		/* "next" line number */
2553 
2554     if (level >= 10) {
2555 	if (isMaster)
2556 	    Error("ParseFile(): nesting too deep, not parsing `%s'",
2557 		  filename);
2558 	return;
2559     }
2560 
2561     /* set some globals */
2562     line = 1;
2563     file = filename;
2564 
2565     /* if we're parsing the base file, set static vars */
2566     if (level == 0) {
2567 	state = START;
2568 	spaceok = 0;
2569 	secIndex = 0;
2570 	keyIndex = 0;
2571     }
2572 
2573     /* initialize local things */
2574     if (word == (STRING *)0)
2575 	word = AllocString();
2576 
2577     while ((token = GetWord(fp, &nextline, spaceok, word)) != DONE) {
2578 	if (token == INCLUDE) {
2579 	    FILE *lfp;
2580 	    if ((FILE *)0 == (lfp = fopen(word->string, "r"))) {
2581 		if (isMaster)
2582 		    Error("ParseFile(): fopen(%s): %s", word->string,
2583 			  strerror(errno));
2584 	    } else {
2585 		char *fname;
2586 		/* word gets destroyed, so save the name */
2587 		fname = StrDup(word->string);
2588 		ParseFile(fname, lfp, level + 1);
2589 		fclose(lfp);
2590 		free(fname);
2591 	    }
2592 	} else {
2593 	    switch (state) {
2594 		case START:
2595 		    switch (token) {
2596 			case WORD:
2597 			    for (secIndex = 0;
2598 				 (p = sections[secIndex].id) != (char *)0;
2599 				 secIndex++) {
2600 				if (strcasecmp(word->string, p) == 0) {
2601 				    CONDDEBUG((1,
2602 					       "ReadCfg(): got keyword '%s' [%s:%d]",
2603 					       word->string, file, line));
2604 				    state = NAME;
2605 				    break;
2606 				}
2607 			    }
2608 			    if (state == START) {
2609 				if (isMaster)
2610 				    Error("invalid keyword '%s' [%s:%d]",
2611 					  word->string, file, line);
2612 			    }
2613 			    break;
2614 			case LEFTBRACE:
2615 			case RIGHTBRACE:
2616 			case SEMICOLON:
2617 			    if (isMaster)
2618 				Error("invalid token '%s' [%s:%d]",
2619 				      word->string, file, line);
2620 			    break;
2621 			case DONE:	/* just shutting up gcc */
2622 			case INCLUDE:	/* just shutting up gcc */
2623 			    break;
2624 		    }
2625 		    break;
2626 		case NAME:
2627 		    switch (token) {
2628 			case WORD:
2629 			    (*sections[secIndex].begin) (word->string);
2630 			    state = LEFTB;
2631 			    break;
2632 			case RIGHTBRACE:
2633 			    if (isMaster)
2634 				Error("premature token '%s' [%s:%d]",
2635 				      word->string, file, line);
2636 			    state = START;
2637 			    break;
2638 			case LEFTBRACE:
2639 			case SEMICOLON:
2640 			    if (isMaster)
2641 				Error("invalid token '%s' [%s:%d]",
2642 				      word->string, file, line);
2643 			    break;
2644 			case DONE:	/* just shutting up gcc */
2645 			case INCLUDE:	/* just shutting up gcc */
2646 			    break;
2647 		    }
2648 		    break;
2649 		case LEFTB:
2650 		    switch (token) {
2651 			case LEFTBRACE:
2652 			    state = KEY;
2653 			    break;
2654 			case RIGHTBRACE:
2655 			    if (isMaster)
2656 				Error("premature token '%s' [%s:%d]",
2657 				      word->string, file, line);
2658 			    (*sections[secIndex].abort) ();
2659 			    state = START;
2660 			    break;
2661 			case SEMICOLON:
2662 			    if (isMaster)
2663 				Error("invalid token '%s' [%s:%d]",
2664 				      word->string, file, line);
2665 			    break;
2666 			case WORD:
2667 			    if (isMaster)
2668 				Error("invalid word '%s' [%s:%d]",
2669 				      word->string, file, line);
2670 			    break;
2671 			case DONE:	/* just shutting up gcc */
2672 			case INCLUDE:	/* just shutting up gcc */
2673 			    break;
2674 		    }
2675 		    break;
2676 		case KEY:
2677 		    switch (token) {
2678 			case WORD:
2679 			    for (keyIndex = 0;
2680 				 (p =
2681 				  sections[secIndex].items[keyIndex].id) !=
2682 				 (char *)0; keyIndex++) {
2683 				if (strcasecmp(word->string, p) == 0) {
2684 				    CONDDEBUG((1,
2685 					       "got keyword '%s' [%s:%d]",
2686 					       word->string, file, line));
2687 				    state = VALUE;
2688 				    break;
2689 				}
2690 			    }
2691 			    if (state == KEY) {
2692 				if (isMaster)
2693 				    Error("invalid keyword '%s' [%s:%d]",
2694 					  word->string, file, line);
2695 			    }
2696 			    break;
2697 			case RIGHTBRACE:
2698 			    (*sections[secIndex].end) ();
2699 			    state = START;
2700 			    break;
2701 			case LEFTBRACE:
2702 			    if (isMaster)
2703 				Error("invalid token '%s' [%s:%d]",
2704 				      word->string, file, line);
2705 			    break;
2706 			case SEMICOLON:
2707 			    if (isMaster)
2708 				Error("premature token '%s' [%s:%d]",
2709 				      word->string, file, line);
2710 			case DONE:	/* just shutting up gcc */
2711 			case INCLUDE:	/* just shutting up gcc */
2712 			    break;
2713 		    }
2714 		    break;
2715 		case VALUE:
2716 		    switch (token) {
2717 			case WORD:
2718 			    (*sections[secIndex].
2719 			     items[keyIndex].reg) (word->string);
2720 			    state = SEMI;
2721 			    break;
2722 			case SEMICOLON:
2723 			    if (isMaster)
2724 				Error("invalid token '%s' [%s:%d]",
2725 				      word->string, file, line);
2726 			    state = KEY;
2727 			    break;
2728 			case RIGHTBRACE:
2729 			    if (isMaster)
2730 				Error("premature token '%s' [%s:%d]",
2731 				      word->string, file, line);
2732 			    (*sections[secIndex].abort) ();
2733 			    state = START;
2734 			    break;
2735 			case LEFTBRACE:
2736 			    if (isMaster)
2737 				Error("invalid token '%s' [%s:%d]",
2738 				      word->string, file, line);
2739 			    break;
2740 			case DONE:	/* just shutting up gcc */
2741 			case INCLUDE:	/* just shutting up gcc */
2742 			    break;
2743 		    }
2744 		    break;
2745 		case SEMI:
2746 		    switch (token) {
2747 			case SEMICOLON:
2748 			    state = KEY;
2749 			    break;
2750 			case RIGHTBRACE:
2751 			    if (isMaster)
2752 				Error("premature token '%s' [%s:%d]",
2753 				      word->string, file, line);
2754 			    (*sections[secIndex].abort) ();
2755 			    state = START;
2756 			    break;
2757 			case LEFTBRACE:
2758 			    if (isMaster)
2759 				Error("invalid token '%s' [%s:%d]",
2760 				      word->string, file, line);
2761 			    break;
2762 			case WORD:
2763 			    if (isMaster)
2764 				Error("invalid word '%s' [%s:%d]",
2765 				      word->string, file, line);
2766 			    break;
2767 			case DONE:	/* just shutting up gcc */
2768 			case INCLUDE:	/* just shutting up gcc */
2769 			    break;
2770 		    }
2771 		    break;
2772 	    }
2773 	    switch (state) {
2774 		case NAME:
2775 		case VALUE:
2776 		    spaceok = 1;
2777 		    break;
2778 		case KEY:
2779 		case LEFTB:
2780 		case START:
2781 		case SEMI:
2782 		    spaceok = 0;
2783 		    break;
2784 	    }
2785 	}
2786 	line = nextline;
2787     }
2788 
2789     if (level == 0) {
2790 	int i;
2791 
2792 	/* check for proper ending of file and do any cleanup */
2793 	switch (state) {
2794 	    case START:
2795 		break;
2796 	    case KEY:
2797 	    case LEFTB:
2798 	    case VALUE:
2799 	    case SEMI:
2800 		(*sections[secIndex].abort) ();
2801 		/* fall through */
2802 	    case NAME:
2803 		if (isMaster)
2804 		    Error("premature EOF seen [%s:%d]", file, line);
2805 		break;
2806 	}
2807 
2808 	/* now clean up all the temporary space used */
2809 	for (i = 0; sections[i].id != (char *)0; i++) {
2810 	    (*sections[i].destroy) ();
2811 	}
2812     }
2813 }
2814 
2815 void
2816 ProcessSubst(SUBST *s, char **repl, char **str, char *name, char *id)
2817 {
2818     /*
2819      * (CONSENT *pCE) and (char **repl) are used when a replacement is to
2820      * actually happen...repl is the string to munch, pCE holds the data.
2821      *
2822      * (char **str) is used to store a copy of (char *id), if it passes
2823      * the format check.
2824      *
2825      * the idea is that this is first called when the config file is read,
2826      * putting the result in (char **str).  then we call it again, near
2827      * the end, permuting (char **repl) with values from (CONSENT *pCE) with
2828      * the saved string now coming in as (char *id).  got it?
2829      *
2830      * you could pass all arguments in...then both types of actions occur.
2831      */
2832     char *p;
2833     char *repfmt[256];
2834     unsigned short repnum;
2835     int i;
2836 
2837     enum repstate {
2838 	REP_BEGIN,
2839 	REP_LTR,
2840 	REP_EQ,
2841 	REP_INT,
2842 	REP_END
2843     } state;
2844 
2845     if (s == (SUBST *)0) {
2846 	Error("ProcessSubst(): WTF? No substitute support structure?!?!");
2847 	Bye(EX_SOFTWARE);
2848     }
2849 
2850     if (str != (char **)0) {
2851 	if (*str != (char *)0) {
2852 	    free(*str);
2853 	    *str = (char *)0;
2854 	}
2855     }
2856 
2857     if ((id == (char *)0) || (*id == '\000'))
2858 	return;
2859 
2860     repnum = 0;
2861     state = REP_BEGIN;
2862 
2863     for (i = 0; i < 256; i++)
2864 	repfmt[i] = (char *)0;
2865 
2866     for (p = id; *p != '\000'; p++) {
2867 	switch (state) {
2868 	    case REP_BEGIN:
2869 		/* must be printable */
2870 		if (*p == ',' || !isgraph((int)(*p)))
2871 		    goto subst_err;
2872 
2873 		/* make sure we haven't seen this replacement char yet */
2874 		repnum = (unsigned short)(*p);
2875 		if (repfmt[repnum] != (char *)0) {
2876 		    if (isMaster)
2877 			Error
2878 			    ("substitution characters of `%s' option are the same [%s:%d]",
2879 			     name, file, line);
2880 		    return;
2881 		}
2882 		state = REP_LTR;
2883 		break;
2884 	    case REP_LTR:
2885 		if (*p != '=')
2886 		    goto subst_err;
2887 		state = REP_EQ;
2888 		break;
2889 	    case REP_EQ:
2890 		repfmt[repnum] = p;
2891 		if (s->token(*(repfmt[repnum])) != ISNOTHING)
2892 		    state = REP_INT;
2893 		else
2894 		    goto subst_err;
2895 		break;
2896 	    case REP_INT:
2897 		if (*p == 'd' || *p == 'x' || *p == 'X' || *p == 'a' ||
2898 		    *p == 'A') {
2899 		    if (s->token(*(repfmt[repnum])) != ISNUMBER)
2900 			goto subst_err;
2901 		    state = REP_END;
2902 		} else if (*p == 's') {
2903 		    if (s->token(*(repfmt[repnum])) != ISSTRING)
2904 			goto subst_err;
2905 		    state = REP_END;
2906 		} else if (!isdigit((int)(*p)))
2907 		    goto subst_err;
2908 		break;
2909 	    case REP_END:
2910 		if (*p != ',')
2911 		    goto subst_err;
2912 		state = REP_BEGIN;
2913 		break;
2914 	}
2915     }
2916 
2917     if (state != REP_END) {
2918       subst_err:
2919 	if (isMaster)
2920 	    Error
2921 		("invalid `%s' specification `%s' (char #%d: `%c') [%s:%d]",
2922 		 name, id, (p - id) + 1, *p, file, line);
2923 	return;
2924     }
2925 
2926     if (str != (char **)0) {
2927 	if ((*str = StrDup(id)) == (char *)0)
2928 	    OutOfMem();
2929     }
2930 
2931     if (s != (SUBST *)0 && repl != (char **)0 && *repl != (char *)0) {
2932 	static STRING *result = (STRING *)0;
2933 
2934 	if (result == (STRING *)0)
2935 	    result = AllocString();
2936 	BuildString((char *)0, result);
2937 
2938 	for (p = *repl; *p != '\000'; p++) {
2939 	    if (repfmt[(unsigned short)(*p)] != (char *)0) {
2940 		char *r = repfmt[(unsigned short)(*p)];
2941 		int plen = 0;
2942 		char *c = (char *)0;
2943 		int o = 0;
2944 
2945 		if (s->token(*r) == ISSTRING) {
2946 		    /* check the pattern for a length */
2947 		    if (isdigit((int)(*(r + 1))))
2948 			plen = atoi(r + 1);
2949 
2950 		    /* this should never return zero, but just in case */
2951 		    if ((*s->value) (*r, &c, (int *)0) == 0)
2952 			c = "";
2953 		    plen -= strlen(c);
2954 
2955 		    /* pad it out, if necessary */
2956 		    for (i = 0; i < plen; i++)
2957 			BuildStringChar(' ', result);
2958 
2959 		    /* throw in the string */
2960 		    BuildString(c, result);
2961 		} else {
2962 		    int i = 0;
2963 		    unsigned short port = 0;
2964 		    unsigned short base = 0;
2965 		    int padzero = 0;
2966 		    static STRING *num = (STRING *)0;
2967 
2968 		    if (num == (STRING *)0)
2969 			num = AllocString();
2970 		    BuildString((char *)0, num);
2971 
2972 		    /* this should never return zero, but just in case */
2973 		    if ((*s->value) (*r, (char **)0, &i) == 0)
2974 			port = 0;
2975 		    else
2976 			port = (unsigned short)i;
2977 
2978 		    /* check the pattern for a length and padding */
2979 		    for (c = r + 1; *c != '\000'; c++)
2980 			if (!isdigit((int)(*c)))
2981 			    break;
2982 		    if (c != r + 1) {
2983 			plen = atoi(r + 1);
2984 			padzero = (r[1] == '0');
2985 		    }
2986 
2987 		    /* check for base */
2988 		    switch (*c) {
2989 			case 'd':
2990 			    base = 10;
2991 			    break;
2992 			case 'x':
2993 			case 'X':
2994 			    base = 16;
2995 			    break;
2996 			case 'a':
2997 			case 'A':
2998 			    base = 36;
2999 			    break;
3000 			default:
3001 			    return;
3002 		    }
3003 		    while (port >= base) {
3004 			if (port % base >= 10)
3005 			    BuildStringChar((port % base) - 10 +
3006 					    ((*c == 'x' ||
3007 					      *c == 'a') ? 'a' : 'A'),
3008 					    num);
3009 			else
3010 			    BuildStringChar((port % base) + '0', num);
3011 			port /= base;
3012 		    }
3013 		    if (port >= 10)
3014 			BuildStringChar(port - 10 +
3015 					((*c == 'x' ||
3016 					  *c == 'a') ? 'a' : 'A'), num);
3017 		    else
3018 			BuildStringChar(port + '0', num);
3019 
3020 		    /* if we're supposed to be a certain length, pad it */
3021 		    while (num->used - 1 < plen) {
3022 			if (padzero == 0)
3023 			    BuildStringChar(' ', num);
3024 			else
3025 			    BuildStringChar('0', num);
3026 		    }
3027 
3028 		    /* reverse the text to put it in forward order */
3029 		    o = num->used - 1;
3030 		    for (i = 0; i < o / 2; i++) {
3031 			char temp;
3032 
3033 			temp = num->string[i];
3034 			num->string[i]
3035 			    = num->string[o - i - 1];
3036 			num->string[o - i - 1] = temp;
3037 		    }
3038 		    BuildStringN(num->string, o, result);
3039 		}
3040 	    } else
3041 		BuildStringChar(*p, result);
3042 	}
3043 	free(*repl);
3044 	if ((*repl = StrDup(result->string)) == (char *)0)
3045 	    OutOfMem();
3046     }
3047 
3048     return;
3049 }
3050 
3051 char *
3052 MyVersion(void)
3053 {
3054     static STRING *version = (STRING *)0;
3055     if (version != (STRING *)0)
3056 	return version->string;
3057     version = AllocString();
3058     BuildStringPrint(version, "%s %d.%d.%d", VERSION_TEXT, VERSION_MAJOR,
3059 		     VERSION_MINOR, VERSION_REV);
3060     return version->string;
3061 }
3062 
3063 unsigned int
3064 AtoU(char *str)
3065 {
3066     unsigned int v;
3067     int i;
3068     v = 0;
3069     for (i = 0; isdigit((int)str[i]); i++) {
3070 	v *= 10;
3071 	v += str[i] - '0';
3072     }
3073     return v;
3074 }
3075 
3076 void
3077 StrCpy(char *dst, const char *src, unsigned int size)
3078 {
3079 #ifdef HAVE_STRLCPY
3080     strlcpy(dst, src, size);
3081 #else
3082     strcpy(dst, src);
3083 #endif
3084 }
3085