File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / util.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 08:44:29 2013 UTC (10 years, 11 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_7p0, v5_7, HEAD
5.7

    1: 
    2: /*
    3:  * util.c
    4:  *
    5:  * Written by Archie Cobbs <archie@freebsd.org>
    6:  * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
    7:  * See ``COPYRIGHT.whistle''
    8:  */
    9: 
   10: #include "ppp.h"
   11: #include "util.h"
   12: #include <termios.h>
   13: #include <paths.h>
   14: 
   15: #include <libutil.h>
   16: #include <netdb.h>
   17: #include <tcpd.h>
   18: #include <sys/wait.h>
   19: #include <sys/sysctl.h>
   20: #include <net/route.h>
   21: #include <netinet/if_ether.h>
   22: 
   23: /*
   24:  * DEFINITIONS
   25:  */
   26: 
   27:   #define MAX_FILENAME		1000
   28:   #define MAX_LINE_ARGS		50
   29:   #define BIG_LINE_SIZE		1000
   30:   #define MAX_OPEN_DELAY	2
   31:   #define MAX_LOCK_ATTEMPTS	30
   32: 
   33: /*
   34:  * INTERNAL VARIABLES
   35:  */
   36: 
   37: #ifndef USE_NG_PRED1
   38: static const u_int16_t Crc16Table[256] = {
   39: /* 00 */    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
   40: /* 08 */    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
   41: /* 10 */    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
   42: /* 18 */    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
   43: /* 20 */    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
   44: /* 28 */    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
   45: /* 30 */    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
   46: /* 38 */    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
   47: /* 40 */    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
   48: /* 48 */    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
   49: /* 50 */    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
   50: /* 58 */    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
   51: /* 60 */    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
   52: /* 68 */    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
   53: /* 70 */    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
   54: /* 78 */    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
   55: /* 80 */    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
   56: /* 88 */    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
   57: /* 90 */    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
   58: /* 98 */    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
   59: /* a0 */    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
   60: /* a8 */    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
   61: /* b0 */    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
   62: /* b8 */    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
   63: /* c0 */    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
   64: /* c8 */    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
   65: /* d0 */    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
   66: /* d8 */    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
   67: /* e0 */    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
   68: /* e8 */    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
   69: /* f0 */    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
   70: /* f8 */    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
   71: };
   72: #endif
   73: 
   74:   static FILE			*lockFp = NULL;
   75: 
   76: /*
   77:  * INTERNAL FUNCTIONS
   78:  */
   79: 
   80:   static void		Escape(char *line);
   81:   static char		*ReadLine(FILE *fp, int *lineNum, char *result, int resultsize);
   82: 
   83:   static char		HexVal(char c);
   84: 
   85:   static void           IndexConfFile(FILE *fp, struct configfile **cf);
   86:   
   87:   struct configfiles	*ConfigFilesIndex=NULL;
   88: 
   89: #undef isspace
   90: #define isspace(c) (((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\r')?1:0)
   91: 
   92: /*
   93:  * LengthenArray()
   94:  */
   95: 
   96: void
   97: LengthenArray(void *array, size_t esize, int *alenp, const char *type)
   98: {
   99:   void **const arrayp = (void **)array;
  100:   void *newa;
  101: 
  102:   newa = Malloc(type, (*alenp + 1) * esize);
  103:   if (*arrayp != NULL) {
  104:     memcpy(newa, *arrayp, *alenp * esize);
  105:     Freee(*arrayp);
  106:   }
  107:   *arrayp = newa;
  108:   (*alenp)++;
  109: }
  110: 
  111: /*
  112:  * ExecCmd()
  113:  */
  114: 
  115: int
  116: ExecCmd(int log, const char *label, const char *fmt, ...)
  117: {
  118:   int		rtn;
  119:   char		cmd[BIG_LINE_SIZE];
  120:   char		cmdn[BIG_LINE_SIZE];
  121:   va_list	ap;
  122: 
  123:   va_start(ap, fmt);
  124:   vsnprintf(cmd, sizeof(cmd), fmt, ap);
  125:   va_end(ap);
  126:   strcpy(cmdn, cmd);
  127: 
  128: /* Log command on the console */
  129: 
  130:   Log(log, ("[%s] system: %s", label, cmd));
  131: 
  132: /* Hide any stdout output of command */
  133: 
  134:   snprintf(cmdn + strlen(cmdn), sizeof(cmdn) - strlen(cmdn), " >%s 2>&1", _PATH_DEVNULL);
  135: 
  136: /* Do command */
  137: 
  138:   if ((rtn = system(cmdn)))
  139:     Log(log|LG_ERR, ("[%s] system: command \"%s\" returned %d", label, cmd, rtn));
  140: 
  141: /* Return command's return value */
  142: 
  143:   return(rtn);
  144: }
  145: 
  146: /*
  147:  * ExecCmdNosh()
  148:  */
  149: 
  150: int
  151: ExecCmdNosh(int log, const char *label, const char *fmt, ...)
  152: {
  153:     int		rtn;
  154:     char	cmd[BIG_LINE_SIZE];
  155:     char	*cmdp = &(cmd[0]);
  156:     char	*argv[256];
  157:     char 	**arg;
  158:     va_list	ap;
  159: 
  160:     pid_t pid, savedpid;
  161:     int pstat;
  162:     struct sigaction ign, intact, quitact;
  163:     sigset_t newsigblock, oldsigblock;
  164: 
  165:     va_start(ap, fmt);
  166:     vsnprintf(cmd, sizeof(cmd), fmt, ap);
  167:     va_end(ap);
  168:   
  169:     /* Log command on the console */
  170:     Log(log, ("[%s] exec: %s", label, cmd));
  171: 
  172:     /* Parce args */
  173:     for (arg = &argv[0]; (*arg = strsep(&cmdp, " \t")) != NULL;) {
  174: 	if (**arg != '\0') {
  175: 	    if (++arg >= &argv[255])
  176: 		break;
  177: 	}
  178:     }
  179:     *arg = NULL;
  180: 
  181:     /* Do command */
  182: 
  183: 	/*
  184: 	 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
  185: 	 * existing signal dispositions.
  186: 	 */
  187: 	ign.sa_handler = SIG_IGN;
  188: 	(void)sigemptyset(&ign.sa_mask);
  189: 	ign.sa_flags = 0;
  190: 	(void)sigaction(SIGINT, &ign, &intact);
  191: 	(void)sigaction(SIGQUIT, &ign, &quitact);
  192: 	(void)sigemptyset(&newsigblock);
  193: 	(void)sigaddset(&newsigblock, SIGCHLD);
  194: 	(void)sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
  195: 	switch(pid = fork()) {
  196: 	case -1:			/* error */
  197: 		break;
  198: 	case 0:				/* child */
  199: 		/*
  200: 		 * Restore original signal dispositions and exec the command.
  201: 		 */
  202: 		(void)sigaction(SIGINT, &intact, NULL);
  203: 		(void)sigaction(SIGQUIT,  &quitact, NULL);
  204: 		(void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
  205: 		close(1);
  206: 		open(_PATH_DEVNULL, O_WRONLY);
  207: 		close(2);
  208: 		open(_PATH_DEVNULL, O_WRONLY);
  209: 		execv(argv[0], argv);
  210: 		exit(127);
  211: 	default:			/* parent */
  212: 		savedpid = pid;
  213: 		do {
  214: 			pid = wait4(savedpid, &pstat, 0, (struct rusage *)0);
  215: 		} while (pid == -1 && errno == EINTR);
  216: 		break;
  217: 	}
  218: 	(void)sigaction(SIGINT, &intact, NULL);
  219: 	(void)sigaction(SIGQUIT,  &quitact, NULL);
  220: 	(void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
  221: 
  222: 	rtn = (pid == -1 ? -1 : pstat);
  223: 
  224:     if (rtn)
  225: 	Log(log|LG_ERR, ("[%s] system: command \"%s\" returned %d", label, cmd, rtn));
  226: 
  227:     /* Return command's return value */
  228:     return(rtn);
  229: }
  230: 
  231: /*
  232:  * ParseLine()
  233:  *
  234:  * Parse arguments, respecting double quotes and backslash escapes.
  235:  * Returns number of arguments, at most "max_args". This destroys
  236:  * the original line. The arguments returned are Malloc()'d strings
  237:  * which must be freed by the caller using FreeArgs().
  238:  */
  239: 
  240: int
  241: ParseLine(char *line, char *av[], int max_args, int copy)
  242: {
  243:   int	ac;
  244:   char	*s, *arg;
  245: 
  246: /* Get args one at a time */
  247: 
  248:   for (ac = 0; ac < max_args; ac++)
  249:   {
  250: 
  251:   /* Skip white space */
  252: 
  253:     while (*line && isspace(*line))
  254:       line++;
  255: 
  256:   /* Done? */
  257: 
  258:     if (*line == 0)
  259:       break;
  260: 
  261:   /* Get normal or quoted arg */
  262: 
  263:     if (*line == '"')
  264:     {
  265: 
  266:     /* Stop only upon matching quote or NUL */
  267: 
  268:       for (arg = ++line; *line; line++)
  269: 	if (*line == '"')
  270: 	{
  271: 	  *line++ = 0;
  272: 	  break;
  273: 	}
  274: 	else if (*line == '\\' && line[1] != 0)
  275: 	{
  276: 	  strcpy(line, line + 1);
  277: 	  Escape(line);
  278: 	}
  279:     }
  280:     else
  281:     {
  282: 
  283:     /* NUL terminate this argument at first white space */
  284: 
  285:       for (arg = line; *line && !isspace(*line); line++);
  286:       if (*line)
  287: 	*line++ = 0;
  288: 
  289:     /* Convert characters */
  290: 
  291:       for (s = arg; *s; s++)
  292: 	if (*s == '\\')
  293: 	{
  294: 	  strcpy(s, s + 1);
  295: 	  Escape(s);
  296: 	}
  297:     }
  298: 
  299:   /* Make a copy of this arg */
  300: 
  301:     if (copy) {
  302: 	strcpy(av[ac] = Malloc(MB_CMD, strlen(arg) + 1), arg);
  303:     }
  304:     else
  305: 	av[ac] = arg;
  306:   }
  307: 
  308: #if 0
  309:   {
  310:     int	k;
  311: 
  312:     printf("ParseLine: %d args:\n", ac);
  313:     for (k = 0; k < ac; k++)
  314:       printf("  [%2d] \"%s\"\n", k, av[k]);
  315:   }
  316: #endif
  317: 
  318:   return(ac);
  319: }
  320: 
  321: /*
  322:  * FreeArgs()
  323:  */
  324: 
  325: void
  326: FreeArgs(int ac, char *av[])
  327: {
  328:   while (ac > 0)
  329:     Freee(av[--ac]);
  330: }
  331: 
  332: /*
  333:  * Escape()
  334:  *
  335:  * Give a string, interpret the beginning characters as an escape
  336:  * code and return with that code converted.
  337:  */
  338: 
  339: static void
  340: Escape(char *line)
  341: {
  342:   int	x, k;
  343:   char	*s = line;
  344: 
  345:   switch (*line)
  346:   {
  347:     case 't': *s = '\t'; return;
  348:     case 'n': *s = '\n'; return;
  349:     case 'r': *s = '\r'; return;
  350:     case 's': *s =  ' '; return;
  351:     case '"': *s =  '"'; return;
  352:     case '0': case '1': case '2': case '3':
  353:     case '4': case '5': case '6': case '7':
  354:       for (x = k = 0; k < 3 && *s >= '0' && *s <= '7'; s++)
  355: 	x = (x << 3) + (*s - '0');
  356:       *--s = x;
  357:       break;
  358:     case 'x':
  359:       for (s++, x = k = 0; k < 2 && isxdigit(*s); s++)
  360: 	x = (x << 4) + (isdigit(*s) ? (*s - '0') : (tolower(*s) - 'a' + 10));
  361:       *--s = x;
  362:       break;
  363:     default:
  364:       return;
  365:   }
  366:   strcpy(line, s);
  367: }
  368: 
  369: /*
  370:  * ReadFile()
  371:  *
  372:  * Read the commands specified for the target in the specified
  373:  * file, which can be found in the PATH_CONF_DIR directory.
  374:  * Returns negative if the file or target was not found.
  375:  */
  376: 
  377: int
  378: ReadFile(const char *filename, const char *target,
  379: 	int (*func)(Context ctx, int ac, char *av[], const char *file, int line), Context ctx)
  380: {
  381:   FILE	*fp;
  382:   int	ac;
  383:   char	*av[MAX_LINE_ARGS];
  384:   char	*line;
  385:   char  buf[BIG_LINE_SIZE];
  386:   struct configfile *cf;
  387:   int   lineNum;
  388: 
  389: /* Open file */
  390: 
  391:   if ((fp = OpenConfFile(filename, &cf)) == NULL)
  392:     return(-1);
  393: 
  394: /* Find label */
  395: 
  396:   if (SeekToLabel(fp, target, &lineNum, cf) < 0) {
  397:     fclose(fp);
  398:     return(-1);
  399:   }
  400: 
  401: /* Execute command list */
  402: 
  403:   while ((line = ReadFullLine(fp, &lineNum, buf, sizeof(buf))) != NULL)
  404:   {
  405:     if (!isspace(*line))
  406:     {
  407:       break;
  408:     }
  409:     ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 0);
  410:     (*func)(ctx, ac, av, filename, lineNum);
  411:   }
  412: 
  413: /* Done */
  414: 
  415:   fclose(fp);
  416:   return(0);
  417: }
  418: 
  419: /*
  420:  * IndexConfFile()
  421:  *
  422:  * Scan config file for labels
  423:  */
  424: 
  425: static void
  426: IndexConfFile(FILE *fp, struct configfile **cf)
  427: {
  428:   char	*s, *line;
  429:   char  buf[BIG_LINE_SIZE];
  430:   struct configfile **tmp;
  431:   int   lineNum;
  432: 
  433: /* Start at beginning */
  434: 
  435:   rewind(fp);
  436:   lineNum = 0;
  437: 
  438:   tmp=cf;
  439: 
  440: /* Find label */
  441: 
  442:   while ((line = ReadFullLine(fp, &lineNum, buf, sizeof(buf))) != NULL)
  443:   {
  444:     if (isspace(*line))
  445:       continue;
  446:     if ((s = strtok(line, " \t\f:"))) {
  447: 	(*tmp)=Malloc(MB_CMDL, sizeof(struct configfile));
  448: 	(*tmp)->label=strcpy(Malloc(MB_CMDL, strlen(s)+1),s);
  449: 	(*tmp)->linenum=lineNum;
  450: 	(*tmp)->seek=ftello(fp);
  451: 	tmp=&((*tmp)->next);
  452:     }
  453:   }
  454: }
  455: 
  456: /*
  457:  * SeekToLabel()
  458:  *
  459:  * Find a label in file and position file pointer just after it
  460:  */
  461: 
  462: int
  463: SeekToLabel(FILE *fp, const char *label, int *lineNum, struct configfile *cf)
  464: {
  465:   char	*s, *line;
  466:   char  buf[BIG_LINE_SIZE];
  467:   struct configfile *tmp;
  468: 
  469:   if (cf) { /* Trying to use index */
  470:     tmp=cf;
  471:     while (tmp && strcmp(tmp->label,label)) {
  472: 	tmp=tmp->next;
  473:     }
  474:     if (tmp) {
  475: 	fseeko(fp,tmp->seek, SEEK_SET);
  476: 	if (lineNum)
  477: 	    *lineNum=tmp->linenum;
  478: 	return(0);
  479:     }
  480:   } else { /* There are no index */
  481:   
  482: /* Start at beginning */
  483:     rewind(fp);
  484:     if (lineNum)
  485:       *lineNum = 0;
  486: 
  487: /* Find label */
  488: 
  489:     while ((line = ReadFullLine(fp, lineNum, buf, sizeof(buf))) != NULL)
  490:     {
  491:       if (isspace(*line))
  492:         continue;
  493:       if ((s = strtok(line, " \t\f:")) && !strcmp(s, label))
  494: 	return(0);
  495:     }
  496:   }
  497: 
  498: /* Not found */
  499:   Log(LG_ERR, ("Label '%s' not found", label));
  500:   return(-1);
  501: }
  502: 
  503: /*
  504:  * OpenConfFile()
  505:  *
  506:  * Open a configuration file
  507:  */
  508: 
  509: FILE *
  510: OpenConfFile(const char *name, struct configfile **cf)
  511: {
  512:   char	pathname[MAX_FILENAME];
  513:   FILE	*fp;
  514:   struct configfiles **tmp;
  515: 
  516: /* Build full pathname */
  517:     if (name[0] == '/')
  518: 	snprintf(pathname, sizeof(pathname), "%s", name);
  519:     else
  520: 	snprintf(pathname, sizeof(pathname), "%s/%s", gConfDirectory, name);
  521: 
  522: /* Open file */
  523: 
  524:   if ((fp = fopen(pathname, "r")) == NULL)
  525:   {
  526:     Perror("%s: Can't open file '%s'", __FUNCTION__, pathname);
  527:     return(NULL);
  528:   }
  529:   (void) fcntl(fileno(fp), F_SETFD, 1);
  530:   
  531:   if (cf) {
  532:     tmp=&ConfigFilesIndex;
  533:     while ((*tmp) && strcmp((*tmp)->filename,name)) {
  534: 	tmp=&((*tmp)->next);
  535:     }
  536:     if (!(*tmp)) {
  537: 	(*tmp) = Malloc(MB_CMD, sizeof(struct configfiles));
  538: 	(*tmp)->filename = strcpy(Malloc(MB_CMD, strlen(name)+1),name);
  539: 	(*tmp)->sections = NULL;
  540: 	(*tmp)->next = NULL;
  541: 	IndexConfFile(fp, &((*tmp)->sections));
  542:     }
  543:     *cf=(*tmp)->sections;
  544:   }
  545:   
  546:   return(fp);
  547: }
  548: 
  549: /*
  550:  * ReadFullLine()
  551:  *
  552:  * Read a full line, respecting backslash continuations.
  553:  * Returns pointer to Malloc'd storage, which must be Freee'd
  554:  */
  555: 
  556: char *
  557: ReadFullLine(FILE *fp, int *lineNum, char *result, int resultsize)
  558: {
  559:   int		len, linelen, resultlinesize, continuation;
  560:   char		line[BIG_LINE_SIZE];
  561:   char		real_line[BIG_LINE_SIZE];
  562:   char		*resultline;
  563: 
  564:   if (result!=NULL && resultsize>0) {
  565:     resultline=result;
  566:     resultlinesize=resultsize;
  567:   } else {
  568:     resultline=line;
  569:     resultlinesize=sizeof(line);
  570:   }
  571: 
  572:   resultline[0] = 0;
  573:   linelen = 0;
  574:   continuation = TRUE;
  575:   
  576:   while ( continuation )
  577:   {
  578: 
  579:   /* Get next real line */
  580: 
  581:     if (ReadLine(fp, lineNum, real_line, sizeof(real_line)) == NULL) {
  582:       if (*resultline)
  583: 	break;
  584:       else
  585: 	return(NULL);
  586:     }
  587: 
  588:   /* Strip trailing white space, detect backslash */
  589: 
  590:     for (len = strlen(real_line);
  591: 	len > 0 && isspace(real_line[len - 1]);
  592: 	len--) {};
  593:     real_line[len] = 0;
  594:     
  595:     if ((continuation = (len && real_line[len - 1] == '\\')))
  596: 	real_line[len - 1] = ' ';
  597: 
  598:   /* Append real line to what we've got so far */
  599: 
  600:     strlcpy(resultline + linelen, real_line, resultlinesize - linelen);
  601:     linelen += len;
  602:     if (linelen > sizeof(line) - 1)
  603: 	linelen = sizeof(line) - 1;
  604:   }
  605: 
  606: /* Report any overflow */
  607: 
  608:   if (linelen >= sizeof(line) - 1)
  609:     Log(LG_ERR, ("warning: line too long, truncated"));
  610: 
  611: /* Copy line and return */
  612: 
  613:   if (result!=NULL && resultsize>0)
  614:      return resultline;
  615:   else 
  616:      return strcpy(Malloc(MB_CMD, linelen + 1), resultline);
  617: }
  618: 
  619: /*
  620:  * ReadLine()
  621:  *
  622:  * Read a line, skipping blank lines & comments. A comment
  623:  * is a line whose first non-white-space character is a hash.
  624:  */
  625: 
  626: static char *
  627: ReadLine(FILE *fp, int *lineNum, char *result, int resultsize)
  628: {
  629:   int		empty;
  630:   char		*s;
  631:   int		ch;
  632: 
  633:     if ((!result) || (resultsize <= 0))
  634: 	return (NULL);
  635: 
  636:     /* Get first non-empty, non-commented line */
  637:     empty = TRUE;
  638:     while ( empty ) {
  639: 
  640: 	/* Read next line from file */
  641: 	if ((fgets(result, resultsize, fp)) == NULL)
  642: 	    return(NULL);
  643: 	if (lineNum)
  644:     	    (*lineNum)++;
  645: 
  646: 	/* Truncate long lines */
  647: 	if (strlen(result) > (resultsize - 2)) {
  648:     	    Log(LG_ERR, ("warning: line too long, truncated"));
  649:     	    while ((ch = getc(fp)) != EOF && ch != '\n');
  650: 	}
  651: 
  652: 	/* Ignore comments */
  653: 	s = result + strspn(result, " \t");
  654: 	if (*s == '#') {
  655:     	    *s = 0;
  656: 	} else {
  657: 	    /* Is this line empty? */
  658:     	    for ( ; *s; s++) {
  659:     		if (!isspace(*s)) {
  660:         	    empty = FALSE;
  661:         	    break;
  662:     		}
  663: 	    }
  664: 	}
  665:     }
  666: 
  667:     return(result);
  668: }
  669: 
  670: #ifdef PHYSTYPE_MODEM
  671: /*
  672:  * OpenSerialDevice()
  673:  *
  674:  * Open and configure a serial device. Call ExclusiveCloseDevice()
  675:  * to close a file descriptor returned by this function.
  676:  */
  677: 
  678: int
  679: OpenSerialDevice(const char *label, const char *path, int baudrate)
  680: {
  681:   struct termios	attr;
  682:   int			fd;
  683: 
  684: /* Open & lock serial port */
  685: 
  686:   if ((fd = ExclusiveOpenDevice(label, path)) < 0)
  687:     return(-1);
  688: 
  689: /* Set non-blocking I/O */
  690: 
  691:   if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
  692:   {
  693:     Perror("[%s] can't set \"%s\" to non-blocking", label, path);
  694:     goto failed;
  695:   }
  696: 
  697: /* Set serial port raw mode, baud rate, hardware flow control, etc. */
  698: 
  699:   if (tcgetattr(fd, &attr) < 0)
  700:   {
  701:     Perror("[%s] can't tcgetattr \"%s\"", label, path);
  702:     goto failed;
  703:   }
  704: 
  705:   cfmakeraw(&attr);
  706: 
  707:   attr.c_cflag &= ~(CSIZE|PARENB|PARODD);
  708:   attr.c_cflag |= (CS8|CREAD|CLOCAL|HUPCL|CCTS_OFLOW|CRTS_IFLOW);
  709:   attr.c_iflag &= ~(IXANY|IMAXBEL|ISTRIP|IXON|IXOFF|BRKINT|ICRNL|INLCR);
  710:   attr.c_iflag |= (IGNBRK|IGNPAR);
  711:   attr.c_oflag &= ~OPOST;
  712:   attr.c_lflag = 0;
  713: 
  714:   cfsetspeed(&attr, (speed_t) baudrate);
  715: 
  716:   if (tcsetattr(fd, TCSANOW, &attr) < 0)
  717:   {
  718:     Perror("[%s] can't tcsetattr \"%s\"", label, path);
  719: failed:
  720:     ExclusiveCloseDevice(label, fd, path);
  721:     return(-1);
  722:   }
  723: 
  724: /* OK */
  725: 
  726:   return(fd);
  727: }
  728: 
  729: /*
  730:  * ExclusiveOpenDevice()
  731:  */
  732: 
  733: int
  734: ExclusiveOpenDevice(const char *label, const char *pathname)
  735: {
  736:   int		fd, locked = FALSE;
  737:   const char	*ttyname = NULL;
  738:   time_t	startTime;
  739: 
  740: /* Lock device UUCP style, if it resides in /dev */
  741: 
  742:   if (!strncmp(pathname, _PATH_DEV, 5))
  743:   {
  744:     int res;
  745:     ttyname = pathname + 5;
  746:     if ((res = uu_lock(ttyname)) != UU_LOCK_OK) {
  747:       Log(LG_ERR, ("[%s] uu_lock(%s): %s", label, ttyname, uu_lockerr(res)));
  748:       return(-1);
  749:     }
  750:     locked = TRUE;
  751:   }
  752: 
  753: /* Open it, but give up after so many interruptions */
  754: 
  755:   for (startTime = time(NULL);
  756:       (fd = open(pathname, O_RDWR, 0)) < 0
  757:       && time(NULL) < startTime + MAX_OPEN_DELAY; )
  758:     if (errno != EINTR)
  759:     {
  760:       Perror("[%s] can't open %s", label, pathname);
  761:       if (locked)
  762: 	uu_unlock(ttyname);
  763:       return(-1);
  764:     }
  765: 
  766: /* Did we succeed? */
  767: 
  768:   if (fd < 0)
  769:   {
  770:     Log(LG_ERR, ("[%s] can't open %s after %d secs",
  771:       label, pathname, MAX_OPEN_DELAY));
  772:     if (locked)
  773:       uu_unlock(ttyname);
  774:     return(-1);
  775:   }
  776:   (void) fcntl(fd, F_SETFD, 1);
  777: 
  778: /* Done */
  779: 
  780:   return(fd);
  781: }
  782: 
  783: /*
  784:  * ExclusiveCloseDevice()
  785:  */
  786: 
  787: void
  788: ExclusiveCloseDevice(const char *label, int fd, const char *pathname)
  789: {
  790:   int		rtn = -1;
  791:   const char	*ttyname;
  792:   time_t	startTime;
  793: 
  794: /* Close file(s) */
  795: 
  796:   for (startTime = time(NULL);
  797:       time(NULL) < startTime + MAX_OPEN_DELAY && (rtn = close(fd)) < 0; )
  798:     if (errno != EINTR)
  799:     {
  800:       Perror("[%s] can't close %s", label, pathname);
  801:       break;
  802:     }
  803: 
  804: /* Did we succeed? */
  805: 
  806:   if ((rtn < 0) && (errno == EINTR))
  807:   {
  808:     Log(LG_ERR, ("[%s] can't close %s after %d secs",
  809:       label, pathname, MAX_OPEN_DELAY));
  810:     DoExit(EX_ERRDEAD);
  811:   }
  812: 
  813: /* Remove lock */
  814: 
  815:   if (!strncmp(pathname, _PATH_DEV, 5))
  816:   {
  817:     ttyname = pathname + 5;
  818:     if (uu_unlock(ttyname) < 0)
  819:       Perror("[%s] can't unlock %s", label, ttyname);
  820:   }
  821: }
  822: #endif /* PHYSTYPE_MODEM */
  823: 
  824: 
  825: /*
  826:  * GenerateMagic()
  827:  *
  828:  * Generate random number which will be used as magic number.
  829:  * This could be made a little more "random"...
  830:  */
  831: 
  832: u_long
  833: GenerateMagic(void)
  834: {
  835:   time_t		now;
  836:   struct timeval	tval;
  837: 
  838:   time(&now);
  839:   gettimeofday(&tval, NULL);
  840:   now += (tval.tv_sec ^ tval.tv_usec) + getppid();
  841:   now *= gPid;
  842:   return(now);
  843: }
  844: 
  845: /*
  846:  * PIDCheck()
  847:  *
  848:  * See if process is already running and deal with PID file.
  849:  */
  850: 
  851: int
  852: PIDCheck(const char *filename, int killem)
  853: {
  854:   int	fd = -1, n_tries;
  855: 
  856: /* Sanity */
  857: 
  858:   assert(!lockFp);
  859: 
  860: /* Atomically open and lock file */
  861: 
  862:   for (n_tries = 0;
  863:     n_tries < MAX_LOCK_ATTEMPTS
  864:       && (fd = open(filename, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644)) < 0;
  865:     n_tries++)
  866:   {
  867:     int		nscan, old_pid;
  868:     FILE	*fp;
  869: 
  870:   /* Abort on any unexpected errors */
  871: 
  872:     if (errno != EAGAIN)
  873:     {
  874:       Perror("%s: open(%s)", __FUNCTION__, filename);
  875:       return(-1);
  876:     }
  877: 
  878:   /* We're already running ... see who it is */
  879: 
  880:     if ((fp = fopen(filename, "r")) == NULL)
  881:     {
  882:       Perror("%s: fopen(%s)", __FUNCTION__, filename);
  883:       return(-1);
  884:     }
  885: 
  886:   /* If there's a PID in there, sniff it out */
  887: 
  888:     nscan = fscanf(fp, "%d", &old_pid);
  889:     fclose(fp);
  890:     if (nscan != 1)
  891:     {
  892:       Log(LG_ERR, ("%s: contents mangled", filename));
  893:       return(-1);
  894:     }
  895: 
  896:   /* Maybe kill the other guy */
  897: 
  898:     if (!killem)
  899:     {
  900:       Log(LG_ERR, ("already running as process %d", old_pid));
  901:       return(-1);
  902:     }
  903:     if (kill(old_pid, SIGTERM) < 0)
  904:       switch (errno)
  905:       {
  906: 	case ESRCH:
  907: 	  Log(LG_ERR, ("process %d no longer exists", old_pid));
  908: 	  break;
  909: 	default:
  910: 	  Perror("%s: kill(%d)", __FUNCTION__, old_pid);
  911: 	  return(-1);
  912:       }
  913: 
  914:   /* Wait and try again */
  915: 
  916:     Log(LG_ERR, ("waiting for process %d to die...", old_pid));
  917:     sleep(1);
  918:   }
  919:   if (n_tries == MAX_LOCK_ATTEMPTS)
  920:   {
  921:     Log(LG_ERR, ("can't lock %s after %d attempts", filename, n_tries));
  922:     return(-1);
  923:   }
  924: 
  925: /* Close on exec */
  926: 
  927:   (void) fcntl(fd, F_SETFD, 1);
  928: 
  929: /* Create a stream on top of file descriptor */
  930: 
  931:   if ((lockFp = fdopen(fd, "r+")) == NULL)
  932:   {
  933:     Perror("%s: fdopen", __FUNCTION__);
  934:     return(-1);
  935:   }
  936:   setbuf(lockFp, NULL);
  937: 
  938: /* Write my PID in there */
  939: 
  940:   rewind(lockFp);
  941:   fprintf(lockFp, "%u\n", (u_int) gPid);
  942:   fflush(lockFp);
  943:   (void) ftruncate(fileno(lockFp), ftell(lockFp));
  944:   return(0);
  945: }
  946: 
  947: /*
  948:  * GetInetSocket()
  949:  *
  950:  * Get a TCP socket and bind it to an address. Set SO_REUSEADDR on the socket.
  951:  */
  952: 
  953: int
  954: GetInetSocket(int type, struct u_addr *addr, in_port_t port, int block, char *ebuf, size_t len)
  955: {
  956:   int			sock;
  957:   static int		one = 1;
  958:   struct sockaddr_storage sa;
  959: 
  960:   u_addrtosockaddr(addr,port,&sa);
  961: 
  962: /* Get and bind non-blocking socket */
  963: 
  964:   if ((sock = socket(sa.ss_family, type, type == SOCK_STREAM ? IPPROTO_TCP : 0)) < 0)
  965:   {
  966:     snprintf(ebuf, len, "socket: %s", strerror(errno));
  967:     return(-1);
  968:   }
  969:   (void) fcntl(sock, F_SETFD, 1);
  970:   if (!block) 
  971:   {
  972:     if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
  973:     {
  974:       snprintf(ebuf, len, "can't set socket non-blocking: %s", strerror(errno));
  975:       close(sock);
  976:       return(-1);
  977:     }
  978:   }
  979:   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
  980:   {
  981:     snprintf(ebuf, len, "setsockopt: %s", strerror(errno));
  982:     close(sock);
  983:     return(-1);
  984:   }
  985:   
  986:   if (bind(sock, (struct sockaddr *) &sa, sa.ss_len) < 0)
  987:   {
  988:     snprintf(ebuf, len, "bind: %s", strerror(errno));
  989:     close(sock);
  990:     return(-1);
  991:   }
  992:   
  993:   return(sock);
  994: }
  995: 
  996: 
  997: /*
  998:  * TcpGetListenPort()
  999:  *
 1000:  * Get port for incoming telnet connections
 1001:  */
 1002: 
 1003: int
 1004: TcpGetListenPort(struct u_addr *addr, in_port_t port, int block)
 1005: {
 1006:   char	ebuf[100];
 1007:   int	sock;
 1008:   int	saverrno;
 1009: 
 1010: /* Get socket */
 1011: 
 1012:   if ((sock = GetInetSocket(SOCK_STREAM, addr, port, block, ebuf, sizeof(ebuf))) < 0)
 1013:   {
 1014:     saverrno = errno;
 1015:     Log(LG_ERR, ("%s", ebuf));
 1016:     errno = saverrno;
 1017:     return(-1);
 1018:   }
 1019: 
 1020: /* Make socket available for connections  */
 1021: 
 1022:   if (listen(sock, 2) < 0)
 1023:   {
 1024:     Perror("%s: listen", __FUNCTION__);
 1025:     (void) close(sock);
 1026:     return(-1);
 1027:   }
 1028: 
 1029: /* Done */
 1030: 
 1031:   return(sock);
 1032: }
 1033: 
 1034: 
 1035: /*
 1036:  * TcpAcceptConnection()
 1037:  *
 1038:  * Accept next connection on port
 1039:  */
 1040: 
 1041: int
 1042: TcpAcceptConnection(int sock, struct sockaddr_storage *addr, int block)
 1043: {
 1044:   int	new_sock;
 1045:   socklen_t size=sizeof(struct sockaddr_storage);
 1046: 
 1047: /* Accept incoming connection */
 1048: 
 1049:   memset(addr, 0, sizeof(*addr));
 1050:   if ((new_sock = accept(sock, (struct sockaddr *) addr, &size)) < 0) {
 1051:     Perror("%s: accept", __FUNCTION__);
 1052:     return(-1);
 1053:   }
 1054:   
 1055: #ifdef USE_WRAP
 1056:     if (Enabled(&gGlobalConf.options, GLOBAL_CONF_TCPWRAPPER)) {
 1057:       struct request_info req;
 1058:       request_init(&req, RQ_DAEMON, "mpd", RQ_FILE, new_sock, NULL);
 1059:       fromhost(&req);
 1060:       if (!hosts_access(&req)) {
 1061: 	Log(LG_ERR, ("refused connection (tcp-wrapper) from %s", 
 1062: 	  eval_client(&req)));
 1063: 	close(new_sock);
 1064: 	return(-1);
 1065:       }
 1066:     }
 1067: #endif
 1068:   
 1069:   if (!block) 
 1070:   {
 1071:     (void) fcntl(new_sock, F_SETFD, 1);
 1072:     if (fcntl(new_sock, F_SETFL, O_NONBLOCK) < 0) {
 1073:       Perror("%s: fcntl", __FUNCTION__);
 1074:       return(-1);
 1075:     }
 1076:   }
 1077: 
 1078: /* Done */
 1079: 
 1080:   return(new_sock);
 1081: }
 1082: 
 1083: 
 1084: /*
 1085:  * ShowMesg()
 1086:  */
 1087: 
 1088: void
 1089: ShowMesg(int log, const char *pref, const char *buf, int len)
 1090: {
 1091:   char	*s, mesg[256];
 1092: 
 1093:   if (len > 0)
 1094:   {
 1095:     if (len > sizeof(mesg) - 1)
 1096:       len = sizeof(mesg) - 1;
 1097:     memcpy(mesg, buf, len);
 1098:     mesg[len] = 0;
 1099:     for (s = strtok(mesg, "\r\n"); s; s = strtok(NULL, "\r\n"))
 1100:       Log(log, ("[%s]   MESG: %s", pref, s));
 1101:   }
 1102: }
 1103: 
 1104: /*
 1105:  * Bin2Hex()
 1106:  */
 1107: 
 1108: char *
 1109: Bin2Hex(const unsigned char *bin, size_t len)
 1110: {
 1111:   static char	hexconvtab[] = "0123456789abcdef";
 1112:   size_t	i, j;
 1113:   char		*buf;
 1114:   
 1115:   if (len > 0) {
 1116:     buf = Malloc(MB_UTIL, len * 2 + 1);
 1117:     for (i = j = 0; i < len; i++) {
 1118:       buf[j++] = hexconvtab[bin[i] >> 4];
 1119:       buf[j++] = hexconvtab[bin[i] & 15];
 1120:     }
 1121:     buf[j] = 0;
 1122:   } else {
 1123:     buf = Malloc(MB_UTIL, 3);
 1124:     buf[0] = '0';
 1125:     buf[1] = '0';
 1126:     buf[2] = 0;
 1127:   }
 1128:   return buf;
 1129: }
 1130: 
 1131: /*
 1132:  * Hex2Bin()
 1133:  */
 1134: 
 1135: u_char *
 1136: Hex2Bin(char *hexstr)
 1137: {
 1138:   int		i;
 1139:   u_char	*binval;
 1140: 
 1141:   binval = Malloc(MB_UTIL, strlen(hexstr) / 2);
 1142: 
 1143:   for (i = 0; i < strlen(hexstr) / 2; i++) {
 1144:     binval[i] = 16 * HexVal(hexstr[2*i]) + HexVal(hexstr[2*i+1]);
 1145:   }
 1146: 
 1147:   return binval;
 1148: }
 1149:  
 1150: static char
 1151: HexVal(char c)
 1152: {
 1153:   if (c >= '0' && c <= '9') {
 1154:     return (c - '0');
 1155:   } else if (c >= 'a' && c <= 'z') {
 1156:     return (c - 'a' + 10);
 1157:   } else if (c >= 'A' && c <= 'Z') {
 1158:     return (c - 'A' + 10);
 1159:   } else {
 1160:     return (-1);
 1161:   }
 1162: }
 1163: 
 1164: #ifndef USE_NG_PRED1
 1165: /*
 1166:  * Crc16()
 1167:  *
 1168:  * Compute the 16 bit frame check value, per RFC 1171 Appendix B,
 1169:  * on an array of bytes.
 1170:  */
 1171: 
 1172: u_short
 1173: Crc16(u_short crc, u_char *cp, int len)
 1174: {
 1175:   while (len--)
 1176:     crc = (crc >> 8) ^ Crc16Table[(crc ^ *cp++) & 0xff];
 1177:   return(crc);
 1178: }
 1179: #endif
 1180: 
 1181: /*
 1182:  * GetAnyIpAddress()
 1183:  *
 1184:  * Get any non-loopback IP address owned by this machine
 1185:  * Prefer addresses from non-point-to-point interfaces.
 1186:  */
 1187: 
 1188: int
 1189: GetAnyIpAddress(struct u_addr *ipaddr, const char *ifname)
 1190: {
 1191:   int			s, p2p = 0;
 1192:   struct in_addr	ipa = { 0 };
 1193:   static struct in_addr	nipa = { 0 };
 1194:   static int		have_nipa = 0;
 1195:   struct ifreq		*ifr, *ifend;
 1196:   struct ifreq		ifreq;
 1197:   struct ifconf		ifc;
 1198:   unsigned int		buffsize = IFCONF_BUFFSIZE;
 1199: 
 1200:     /* use cached IP to reduce number of syscalls */
 1201:     if (ifname == NULL && have_nipa) {
 1202: 	in_addrtou_addr(&nipa, ipaddr);
 1203: 	return(0);
 1204:     }
 1205: 
 1206:     /* Get socket */
 1207:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 1208: 	Perror("%s: Socket creation error", __FUNCTION__);
 1209: 	return(-1);
 1210:     }
 1211: 
 1212:     /* Try simple call for the first IP on interface */
 1213:     if (ifname != NULL) {
 1214: 	strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
 1215:         if (ioctl(s, SIOCGIFADDR, &ifreq) < 0) {
 1216: 	    if (errno != ENXIO)
 1217:     		Perror("%s: ioctl(SIOCGIFADDR)", __FUNCTION__);
 1218:     	    close(s);
 1219:     	    return(-1);
 1220:         }
 1221: 	ipa = ((struct sockaddr_in *)&ifreq.ifr_ifru.ifru_addr)->sin_addr;
 1222: 	if ((ntohl(ipa.s_addr)>>24) == 127)
 1223: 	    ipa.s_addr = 0; 	/* We don't like 127.0.0.1 */
 1224:     }
 1225: 
 1226:     /* If simple is not enouth try complex call */
 1227:     if (ipa.s_addr == 0) {
 1228:       struct ifreq *ifs;
 1229:       while (1) {
 1230:         ifc.ifc_len = buffsize;
 1231:         ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len);
 1232:         if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
 1233:           Freee(ifs);
 1234:           if (errno != ENXIO)
 1235:     	     Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__);
 1236:           close(s);
 1237:           return(-1);
 1238:         }
 1239:         
 1240:         /* if used size is too close to allocated size retry with a larger buffer */
 1241:         if (ifc.ifc_len + 128 < buffsize)
 1242:           break;
 1243:         
 1244:          Freee(ifs);
 1245:         if (buffsize >= IFCONF_BUFFMAXSIZE) {
 1246:        	  Log(LG_ERR, ("%s: Max buffer size reached", __FUNCTION__));
 1247:           close(s);
 1248:           return(-1);
 1249:         }
 1250:         buffsize *= 2;
 1251:       }
 1252: 
 1253:       for (ifend = (struct ifreq *)(void *)(ifc.ifc_buf + ifc.ifc_len),
 1254:     	    ifr = ifc.ifc_req;
 1255:           ifr < ifend;
 1256:           ifr = (struct ifreq *)(void *)((char *) &ifr->ifr_addr
 1257: 	    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
 1258:         if (ifr->ifr_addr.sa_family == AF_INET) {
 1259: 
 1260:           if (ifname!=NULL && strcmp(ifname,ifr->ifr_name))
 1261: 	    continue;
 1262: 
 1263:           /* Check that the interface is up; prefer non-p2p and non-loopback */
 1264:           strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
 1265:           if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
 1266:     	    continue;
 1267:           if ((ifreq.ifr_flags & IFF_UP) != IFF_UP)
 1268: 	    continue;
 1269: 	  if ((ifreq.ifr_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) && ipa.s_addr)
 1270: 	    continue;
 1271: 	  if ((ntohl(((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr.s_addr)>>24)==127)
 1272: 	    continue;
 1273: 
 1274:           /* Save IP address and interface name */
 1275:           ipa = ((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr;
 1276:           p2p = (ifreq.ifr_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0;
 1277:       
 1278:           if (!p2p) break;
 1279:         }
 1280:       }
 1281:       Freee(ifs);
 1282:     }
 1283:     close(s);
 1284: 
 1285:     /* Found? */
 1286:     if (ipa.s_addr == 0)
 1287: 	return(-1);
 1288:     if (ifname == NULL) {
 1289: 	nipa = ipa;
 1290: 	have_nipa = 1;
 1291:     }
 1292:     in_addrtou_addr(&ipa, ipaddr);
 1293:     return(0);
 1294: }
 1295: 
 1296: /*
 1297:  * GetEther()
 1298:  *
 1299:  * Get the hardware address of an interface on the the same subnet as addr.
 1300:  * If addr == NULL, finds the address of any local ethernet interface.
 1301:  */
 1302: 
 1303: int
 1304: GetEther(struct u_addr *addr, struct sockaddr_dl *hwaddr)
 1305: {
 1306:   int			s;
 1307:   struct ifreq		*ifr, *bifr, *ifend, *ifp;
 1308:   u_int32_t		ina, mask, bmask;
 1309:   struct ifreq		ifreq;
 1310:   struct ifconf		ifc;
 1311:   struct ifreq 		*ifs;
 1312:   unsigned int buffsize = IFCONF_BUFFSIZE;
 1313:   
 1314:   static struct sockaddr_dl nhwaddr;
 1315:   static int		have_nhwaddr = 0;
 1316: 
 1317:     /* cache value to reduce number of syscalls */
 1318:     if (addr == NULL && have_nhwaddr) {
 1319:         memcpy(hwaddr, &nhwaddr,
 1320: 	    sizeof(*hwaddr));
 1321: 	return(0);
 1322:     }
 1323: 
 1324:     /* Get interface list */
 1325:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 1326: 	Perror("%s: Socket creation error", __FUNCTION__);
 1327: 	return(-1);
 1328:     }
 1329: 
 1330:     while (1) {
 1331: 	ifc.ifc_len = buffsize;
 1332: 	ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len);
 1333: 	if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
 1334: 	    Freee(ifs);
 1335: 	    Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__);
 1336:     	    close(s);
 1337: 	    return(-1);
 1338: 	}
 1339: 	 
 1340: 	/* if used size is too close to allocated size retry with a larger buffer */
 1341: 	if (ifc.ifc_len + 128 < buffsize)
 1342: 	    break;
 1343: 	 
 1344: 	Freee(ifs);
 1345: 	if (buffsize >= IFCONF_BUFFMAXSIZE) {
 1346: 	    Log(LG_ERR, ("%s: Max buffer size reached", __FUNCTION__));
 1347:     	    close(s);
 1348: 	    return(-1);
 1349: 	}
 1350: 	buffsize *= 2;
 1351:     }
 1352: 
 1353:   /*
 1354:    * Scan through looking for an interface with an IP
 1355:    * address on same subnet as `addr'.
 1356:    */
 1357:   bifr = NULL;
 1358:   bmask = 0;
 1359:   for (ifend = (struct ifreq *)(void *)(ifc.ifc_buf + ifc.ifc_len),
 1360: 	ifr = ifc.ifc_req;
 1361:       ifr < ifend;
 1362:       ifr = (struct ifreq *)(void *)((char *) &ifr->ifr_addr
 1363: 	+ MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
 1364:     if (ifr->ifr_addr.sa_family == AF_INET) {
 1365: 
 1366:       /* Save IP address and interface name */
 1367:       ina = ((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr.s_addr;
 1368:       strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
 1369:       ifreq.ifr_addr = ifr->ifr_addr;
 1370: 
 1371:       /* Check that the interface is up, and not point-to-point or loopback */
 1372:       if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) {
 1373: 	Log(LG_IFACE2, ("ioctl(SIOCGIFFLAGS, %s): %d", ifr->ifr_name, errno));
 1374: 	continue;
 1375:       }
 1376:       if ((ifreq.ifr_flags &
 1377: 	  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
 1378: 	  != (IFF_UP|IFF_BROADCAST))
 1379: 	continue;
 1380: 
 1381:       if (addr) {
 1382:         /* Get its netmask and check that it's on the right subnet */
 1383:         if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
 1384: 	    continue;
 1385:         mask = ((struct sockaddr_in *)(void *)&ifreq.ifr_addr)->sin_addr.s_addr;
 1386:         if ((addr->u.ip4.s_addr & mask) != (ina & mask))
 1387: 	    continue;
 1388: 	/* Is this the best match? */
 1389: 	if (mask >= bmask) {
 1390: 	    bmask = mask;
 1391: 	    bifr = ifr;
 1392: 	}
 1393: 	continue;
 1394:       }
 1395: 
 1396:       /* OK */
 1397:       bifr = ifr;
 1398:       break;
 1399:     }
 1400:   }
 1401:   close(s);
 1402: 
 1403:   /* Found? */
 1404:   if (bifr == NULL) {
 1405:     Freee(ifs);
 1406:     return(-1);
 1407:   }
 1408: 
 1409:   /* Now scan again looking for a link-level address for this interface */
 1410:   for (ifp = bifr, ifr = ifc.ifc_req; ifr < ifend; ) {
 1411:     if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
 1412: 	&& ifr->ifr_addr.sa_family == AF_LINK) {
 1413:       if (addr == NULL) {
 1414:         memcpy(&nhwaddr, (struct sockaddr_dl *)(void *)&ifr->ifr_addr,
 1415: 	    sizeof(*hwaddr));
 1416: 	have_nhwaddr = 1;
 1417:       }
 1418:       memcpy(hwaddr, (struct sockaddr_dl *)(void *)&ifr->ifr_addr,
 1419: 	sizeof(*hwaddr));
 1420:       Freee(ifs);
 1421:       return(0);
 1422:     }
 1423:     ifr = (struct ifreq *)(void *)((char *)&ifr->ifr_addr
 1424:       + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
 1425:   }
 1426: 
 1427:   /* Not found! */
 1428:   Freee(ifs);
 1429:   return(-1);
 1430: }
 1431: 
 1432: int
 1433: GetPeerEther(struct u_addr *addr, struct sockaddr_dl *hwaddr)
 1434: {
 1435: 	int mib[6];
 1436: 	size_t needed;
 1437: 	char *lim, *buf, *next;
 1438: 	struct rt_msghdr *rtm;
 1439: 	struct sockaddr_inarp *sin2;
 1440: 	struct sockaddr_dl *sdl;
 1441: 	int st, found_entry = 0;
 1442: 
 1443: 	mib[0] = CTL_NET;
 1444: 	mib[1] = PF_ROUTE;
 1445: 	mib[2] = 0;
 1446: 	mib[3] = addr->family;
 1447: 	mib[4] = NET_RT_FLAGS;
 1448: #ifdef RTF_LLINFO
 1449: 	mib[5] = RTF_LLINFO;
 1450: #else
 1451: 	mib[5] = 0;
 1452: #endif
 1453: 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
 1454: 		Perror("route-sysctl-estimate");
 1455: 		return (0);
 1456: 	}
 1457: 	if (needed == 0)	/* empty table */
 1458: 		return 0;
 1459: 	buf = NULL;
 1460: 	for (;;) {
 1461: 		if (buf)
 1462: 		    Freee(buf);
 1463: 		buf = Malloc(MB_UTIL, needed);
 1464: 		st = sysctl(mib, 6, buf, &needed, NULL, 0);
 1465: 		if (st == 0 || errno != ENOMEM)
 1466: 			break;
 1467: 		needed += needed / 8;
 1468: 	}
 1469: 	if (st == -1) {
 1470: 		Log(LG_ERR, ("actual retrieval of routing table"));
 1471: 		Freee(buf);
 1472: 		return (0);
 1473: 	}
 1474: 	lim = buf + needed;
 1475: 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
 1476: 		rtm = (struct rt_msghdr *)next;
 1477: 		sin2 = (struct sockaddr_inarp *)(rtm + 1);
 1478: 		if (addr->u.ip4.s_addr == sin2->sin_addr.s_addr) {
 1479: 			sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
 1480: 			memcpy(hwaddr, sdl, sdl->sdl_len);
 1481: 			found_entry = 1;
 1482: 			break;
 1483: 		}
 1484: 	}
 1485: 	Freee(buf);
 1486: 	return (found_entry);
 1487: }
 1488: 
 1489: /*
 1490:  * Decode ASCII message
 1491:  */
 1492: void
 1493: ppp_util_ascify(char *buf, size_t bsiz, const char *data, size_t len)
 1494: {
 1495: 	char *bp;
 1496: 	int i;
 1497: 
 1498: 	for (bp = buf, i = 0; i < len; i++) {
 1499: 		const char ch = (char)data[i];
 1500: 
 1501: 		if (bsiz < 3)
 1502: 			break;
 1503: 		switch (ch) {
 1504: 		case '\t':
 1505: 			*bp++ = '\\';
 1506: 			*bp++ = 't';
 1507: 			bsiz -= 2;
 1508: 			break;
 1509: 		case '\n':
 1510: 			*bp++ = '\\';
 1511: 			*bp++ = 'n';
 1512: 			bsiz -= 2;
 1513: 			break;
 1514: 		case '\r':
 1515: 			*bp++ = '\\';
 1516: 			*bp++ = 'r';
 1517: 			bsiz -= 2;
 1518: 			break;
 1519: 		default:
 1520: 			if (isprint(ch & 0x7f)) {
 1521: 				*bp++ = ch;
 1522: 				bsiz--;
 1523: 			} else {
 1524: 				*bp++ = '^';
 1525: 				*bp++ = '@' + (ch & 0x1f);
 1526: 				bsiz -= 2;
 1527: 			}
 1528: 			break;
 1529: 		}
 1530: 	}
 1531: 	*bp = '\0';
 1532: }
 1533: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>