Example #1
0
File: types.c Project: hsiboy/ida
static int idsa_risk_scan(IDSA_UNIT * u, char *s)
{
  unsigned int x;

  x = idsa_risk_parse(s);

  memcpy(u->u_ptr, &x, sizeof(int));

  return 0;
}
Example #2
0
int main(int argc, char **argv)
{
  char *user, *group, *interface, *root, *port, *cmd;
  int niceinc;
  int nofork;
  int timeout;
  int instances;
  int queue;

  int reuse;
  int keepalive;
  int what;
  int value;
  int offset;
  int i, j;
  char c;
  int lfd;
  int nfd;
  struct sigaction sag;
  sigset_t sst;
  int status;
  int hang;
  int busy;
  int tos;
  int ttl;
  int sane;
  int just;
#ifdef USE_IDSA
  int exitcode;
  int killcode;
  int flags;
  unsigned int arisk, crisk, irisk, risk;
#endif

  double limit_load = 0.0;

  port = NULL;
  user = NULL;
  group = NULL;
  root = NULL;
  interface = NULL;
  cmd = NULL;

  just = 0;
  sane = 1;
  reuse = 1;
  keepalive = 1;
  niceinc = 0;
  nofork = 0;
  timeout = 0;
  instances = 0;
  queue = 5;
  tos = 0;
  ttl = 0;
  offset = 0;

#ifdef USE_IDSA
  flags = 0;
  arisk = idsa_risk_make(-0.3,0.8);
  crisk = IDSA_R_UNKNOWN;
  irisk = IDSA_R_PARTIAL;
#endif

  i = j = 1;
  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {
      case 'c':
	printf("(c) 2002,2007 Marc Welz: Distributed under the terms of the GNU General Public License\n");
	exit(0);
	break;
      case 'h':		/* print brief help message */
      case '?':
	usage(argv[0]);
	exit(0);
	break;
      case 'v':
#ifdef USE_IDSA
	printf("linetd %s-i\n", VERSION);
#else
	printf("linetd %s\n", VERSION);
#endif
	exit(0);
	break;

	/* flags */
      case 'f':		/* keep in foreground */
	nofork = 1;
	j++;
	break;
      case 'a' :        /* disable reuse of address */
        j++;
	c = argv[i][j];
	switch (c) {
        case 'r':
          reuse = 0;
          break;
	case 'k':
          keepalive = 0;
          break;
	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -a requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -a%c", c);
	  break;
        }

	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}

        break;
      case 'd' :        /* disable sanity checks */
        sane = 0;
	j++;
        break;

	/* strings */
      case 'u':
      case 'g':
      case 'p':
      case 'r':
      case 'b':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	switch (c) {
	case 'u':
	  user = argv[i] + j;
	  break;
	case 'g':
	  group = argv[i] + j;
	  break;
	case 'p':        
	  port = argv[i] + j;
	  break;
	case 'r':
	  root = argv[i] + j;
	  break;
	case 'b':
	  interface = argv[i] + j;
	  break;
	}
	i++;
	j = 1;
	break;

      case 'l':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a floating point value", c);
	}
        load_fd = open(LOADAVG, O_RDONLY);
        if(load_fd < 0){
          fatal_failure(LINET_SYSTEM, errno, "unable to open %s to read load average", LOADAVG);
        }
	limit_load = atof(argv[i] + j);
	i++;
	j = 1;
	break;

      case 'n':
      case 'm':
      case 'i':
      case 'j':
      case 'q':
      case 't':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a numeric value", c);
	}
	value = atoi(argv[i] + j);
	switch (c) {
	case 'n':
	  niceinc = value;
	  break;
	case 'm':
	  timeout = value;
	  break;
	case 'i':
	  instances = value;
	  break;
	case 'j':
	  just = value;
	  break;
	case 'q':
	  queue = value;
	  break;
	case 't':
	  ttl = value;
	  break;
	}
	i++;
	j = 1;
	break;

      case 'o':
        j++;
	c = argv[i][j];
	switch (c) {
        case 'c':
          tos = IPTOS_LOWCOST;
          break;
	case 'd':
          tos = IPTOS_LOWDELAY;
          break;
	case 'r':
          tos = IPTOS_RELIABILITY;
          break;
	case 't':
          tos = IPTOS_THROUGHPUT;
          break;

	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -o requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -o%c", c);
	  break;
        }

	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}

        break;

#ifdef USE_IDSA
      case 'k' : /* risk ratings */
	j++;
	c = argv[i][j];
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}

	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -k%c requires a parameter", c);
	}

        risk = idsa_risk_parse(argv[i]+j);

	switch (c) {
	case 'a':
          arisk = risk;
          break;
	case 'c':
          crisk = risk;
          break;
	case 'i':
          irisk = risk;
          break;
        }
	i++;
	j = 1;
        break;

      case 'x':
        j++;
	c = argv[i][j];
	switch (c) {
        case 'e':
	  flags |= IDSA_F_ENV; /* honour IDSA_SOCKET */
          break;
	case 'o':
	  flags |= IDSA_F_FAILOPEN; /* continue on failure */
          break;
	case 'u':
	  flags |= IDSA_F_UPLOAD; /* allow uploading of rules */
          break;
	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -x requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -x%c", c);
	  break;
        }
	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}
        break;
#endif

      case 's':
	j++;
	c = argv[i][j];
	what = 0;
	switch (c) {
	case 'c':
	  what = RLIMIT_CORE;
	  break;
	case 'd':
	  what = RLIMIT_DATA;
	  break;
	case 'f':
	  what = RLIMIT_FSIZE;
	  break;
	case 'l':
	  what = RLIMIT_MEMLOCK;
	  break;
	case 'm':
	  what = RLIMIT_RSS;
	  break;
	case 'n':
	  what = RLIMIT_NOFILE;
	  break;
	case 's':
	  what = RLIMIT_STACK;
	  break;
	case 't':
	  what = RLIMIT_CPU;
	  break;
	case 'u':
	  what = RLIMIT_NPROC;
	  break;
	case 'v':
	  what = RLIMIT_AS;
	  break;

	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -s requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -s%c", c);
	  break;
	}

	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}

	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -s%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -s%c requires a numeric value", c);
	}
	value = atoi(argv[i] + j);

        if(resource_count >= LINET_MAXRES){
	  fatal_failure(LINET_USAGE, 0, "too many resource restrictions", c);
        }

        resource_table[resource_count][0] = what;
        resource_table[resource_count][1] = value;
        resource_count++;

	i++;
	j = 1;
	break;

      case '-':
	j++;
	break;
      case '\0':
	j = 1;
	i++;
	break;
      default:
	fatal_failure(LINET_USAGE, 0, "unknown option -%c", argv[i][j]);
	break;
      }
    } else {
      cmd = argv[i];
      offset = i + 1;

      if (sane) {
        if (i + 1 >= argc){
          fprintf(stderr, "%s: warning: zeroth argument should be specified\n", argv[0]);
          offset = i;
        }
      }

      i = argc;
    }
  }

  if (cmd == NULL) {
    fatal_failure(LINET_USAGE, 0, "require a command to run");
  }

  if (!nofork) {
    fork_parent(argv[0]);
  }
#ifdef USE_IDSA
  if (ic == NULL) {
    ic = idsa_open(LINETD, NULL, flags);
  }
  if (ic == NULL) {
    fprintf(stderr, "%s: unable to open idsa connection\n", argv[0]);
    exit(EX_UNAVAILABLE);
  }
#endif

  sigfillset(&(sag.sa_mask));
  sag.sa_flags = 0;

  sag.sa_handler = handle_child;
  if (sigaction(SIGCHLD, &sag, NULL)) {
    fatal_failure(LINET_SYSTEM, errno, "unable to set signal handler");
  }

  sag.sa_handler = handle_stop;
  if (sigaction(SIGTERM, &sag, NULL)) {
    fatal_failure(LINET_SYSTEM, errno, "unable to set signal handler");
  }

  lfd = setup_listener(argv[0], port, interface, queue, ttl, tos, reuse, keepalive);

  drop_root(argv[0], user, group, root);

  if(sane){
    if(access(cmd, X_OK)){
      fatal_failure(LINET_SYSTEM, errno, "\"%s\" %s", cmd, (cmd[0] == '/') ? "appears unavailable" : "might need an absolute path");
    }
  }

  if (niceinc) {
    nice(niceinc);
  }

#ifdef USE_IDSA
  if(idsa_set(ic, LINET_DR, LINET_SCHEME, 1, IDSA_R_SUCCESS, IDSA_R_UNKNOWN, IDSA_R_UNKNOWN, 
        IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SSTART, 
        "version", IDSA_T_STRING, VERSION, 
        NULL) != IDSA_L_ALLOW){
    fprintf(stderr, "%s: start disallowed\n", LINETD);
    return EX_NOPERM;
  }
#endif

  if (!nofork) {
    close(STDERR_FILENO);
  }

  sigemptyset(&sst);
  sigaddset(&sst, SIGCHLD);
  sigaddset(&sst, SIGTERM);

  sigprocmask(SIG_BLOCK, &sst, NULL);	/* disable child signal for everything execpt accept and sleep */

  while (run) {
#ifdef USE_IDSA
    nfd = accept_connection(lfd, arisk, crisk, irisk);
#else
    nfd = accept_connection(lfd);
#endif
    if (nfd >= 0) {
      run_command(lfd, cmd, &argv[offset], nfd, timeout);
      if(just){
        just--;
        if(just == 0){
          run = 0;
        }
      }
    }

    do{ /* check children and load */
      busy = 0;
      hang = ((instances > 0) && (child_count >= instances)); /* actually wait for child */

      if (zombies || hang) {
        if (waitpid(WAIT_ANY, &status, hang ? 0 : WNOHANG) > 0) {	/* collect pids without risk of EINTR */
#ifdef USE_IDSA

          /* in theory this could parse signals and exit codes. Eg SIG{SEGV,BUS} == ES_INTERNAL etc */

          if (WIFEXITED(status)) {
            exitcode = WEXITSTATUS(status);
            if (exitcode == 0) {
              idsa_set(ic, LINET_JD, LINET_SCHEME, 0, IDSA_R_NONE, IDSA_R_UNKNOWN, IDSA_R_UNKNOWN, 
                  IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WSTOP, 
                  NULL);
            } else {
              idsa_set(ic, LINET_JE, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_UNKNOWN, IDSA_R_PARTIAL, 
                  IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WFAIL, 
                  IDSA_ES,  IDSA_T_STRING, IDSA_ES_OTHER, 
                  "exit",   IDSA_T_INT, &exitcode, 
                  NULL);
            }
          } else if (WIFSIGNALED(status)) {
            killcode = WTERMSIG(status);
            idsa_set(ic, LINET_JS, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_UNKNOWN, IDSA_R_PARTIAL,
                IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WFAIL, 
                IDSA_ES,  IDSA_T_STRING, IDSA_ES_OTHER, 
                "signal", IDSA_T_INT, &killcode,
                NULL);
          }
#endif
          child_count--;
          busy = ! hang; 
        } else { /* nothing more to collect */
          zombies = 0;
        }
      }

      if((load_fd >= 0) && (zombies == 0)){ /* if zombies then loop will run again, defer load check */
        if(get_load() > limit_load){ /* go to sleep if overloaded */
          sigprocmask(SIG_UNBLOCK, &sst, NULL);	/* enable child|term signal */
          sleep(LINET_SLEEP);
          sigprocmask(SIG_BLOCK, &sst, NULL);	/* disable child|term signal */
          busy = run;
        }
      }
    } while (busy); /* end of child and delay loop */
  } /* end of main loop */

  if(lfd >= 0){
    close(lfd);
  }
  if(load_fd >= 0){
    close(load_fd);
  }

#ifdef USE_IDSA
  idsa_set(ic, LINET_DE, LINET_SCHEME, 0, IDSA_R_TOTAL, IDSA_R_NONE, IDSA_R_UNKNOWN, 
      IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SSTOP, 
      "version", IDSA_T_STRING, VERSION, 
      NULL);
  idsa_close(ic);
#endif

  return 0;
}