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