Beispiel #1
0
void child_update(void) {
  pr_child_t *ch, *chn = NULL;

  if (!child_list)
    return;

  /* Scan the child list, removing those entries marked as 'dead'. */
  for (ch = (pr_child_t *) child_list->xas_list; ch; ch = chn) {
    chn = ch->next;

    if (ch->ch_dead) {
      if (ch->ch_pipefd != -1)
        close(ch->ch_pipefd);

      xaset_remove(child_list, (xasetmember_t *) ch);
      destroy_pool(ch->ch_pool);
    }
  }

  /* If the child list is empty, recover the list pool memory. */
  if (!child_list->xas_list) {
    destroy_pool(child_list->pool);
    child_list = NULL;
  }

  return;
}
Beispiel #2
0
config_rec *pr_parser_config_ctxt_close(int *empty) {
  config_rec *c = *parser_curr_config;

  /* Note that if the current config is empty, it should simply be removed.
   * Such empty configs can happen for <Directory> sections that
   * contain no directives, for example.
   */

  if (parser_curr_config == (config_rec **) parser_confstack->elts) {
    if (c != NULL &&
        (!c->subset || !c->subset->xas_list)) {
      xaset_remove(c->set, (xasetmember_t *) c);
      destroy_pool(c->pool);

      if (empty) {
        *empty = TRUE;
      }
    }

    if (*parser_curr_config) {
      *parser_curr_config = NULL;
    }

    return NULL;
  }

  if (c != NULL &&
      (!c->subset || !c->subset->xas_list)) {
    xaset_remove(c->set, (xasetmember_t *) c);
    destroy_pool(c->pool);

    if (empty) {
      *empty = TRUE;
    }
  }

  parser_curr_config--;
  parser_confstack->nelts--;

  return *parser_curr_config;
}
Beispiel #3
0
/* Sentinel values:
 *
 *  cmd_type = 0
 *  cmd_group = NULL
 *  cmd_class = -1
 */
int pr_stash_remove_cmd(const char *cmd_name, module *m,
    unsigned char cmd_type, const char *cmd_group, int cmd_class) {
  int count = 0, prev_idx, symtab_idx = 0;
  size_t cmd_namelen = 0;
  unsigned int hash;
  cmdtable *tab = NULL;

  if (cmd_name == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* Don't forget to include one for the terminating NUL. */
  cmd_namelen = strlen(cmd_name) + 1;

  hash = sym_type_hash(PR_SYM_CMD, cmd_name, cmd_namelen);
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
  prev_idx = -1;

  tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, NULL, &prev_idx, &hash);
  while (tab) {
    cmdtable *cmd_sym;

    pr_signals_handle();

    /* Note: this works because of a hack: the symbol lookup functions set a
     * static pointer, cmd_curr_sym, to point to the struct stash just looked
     * up.  cmd_curr_sym will not be NULL if pr_stash_get_symbol2() returns
     * non-NULL.
     */

    cmd_sym = cmd_curr_sym->ptr.sym_cmd;
    if ((m == NULL || cmd_curr_sym->sym_module == m) &&
        (cmd_type == 0 || cmd_sym->cmd_type == cmd_type) &&
        (cmd_group == NULL ||
         (cmd_group != NULL &&
          cmd_sym->group != NULL &&
          strcmp(cmd_sym->group, cmd_group) == 0)) &&
        (cmd_class == -1 || cmd_sym->cmd_class == cmd_class)) {
      xaset_remove(cmd_symbol_table[symtab_idx],
        (xasetmember_t *) cmd_curr_sym);
      destroy_pool(cmd_curr_sym->sym_pool);
      cmd_curr_sym = NULL;
      tab = NULL;
      count++;
    }

    tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, tab, &prev_idx, &hash);
  }

  return count;
}
Beispiel #4
0
int pr_timer_reset(int timerno, module *mod) {
  struct timer *t = NULL;

  if (!timers) {
    errno = EPERM;
    return -1;
  }

  if (_indispatch) {
    errno = EINTR;
    return -1;
  }

  pr_alarms_block();

  if (!recycled)
    recycled = xaset_create(timer_pool, NULL);

  for (t = (struct timer *) timers->xas_list; t; t = t->next) {
    if (t->timerno == timerno &&
        (t->mod == mod || mod == ANY_MODULE)) {
      t->count = t->interval;
      xaset_remove(timers, (xasetmember_t *) t);
      xaset_insert(recycled, (xasetmember_t *) t);
      nalarms++;

      /* The handle_alarm() function also readjusts the timers lists
       * as part of its processing, so it needs to be called when a timer
       * is reset.
       */
      handle_alarm();
      break;
    }
  }

  pr_alarms_unblock();

  if (t != NULL) {
    pr_trace_msg("timer", 7, "reset timer ID %d ('%s', for module '%s')",
      t->timerno, t->desc, t->mod ? t->mod->name : "[none]");
    return t->timerno;
  }

  return 0;
}
Beispiel #5
0
int pr_stash_remove_conf(const char *directive_name, module *m) {
  int count = 0, prev_idx, symtab_idx = 0;
  size_t directive_namelen = 0;
  unsigned int hash;
  conftable *tab = NULL;

  if (directive_name == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* Don't forget to include one for the terminating NUL. */
  directive_namelen = strlen(directive_name) + 1;

  hash = sym_type_hash(PR_SYM_CONF, directive_name, directive_namelen);
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
  prev_idx = -1;

  tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, NULL, &prev_idx,
    &hash);
  while (tab) {
    pr_signals_handle();

    /* Note: this works because of a hack: the symbol lookup functions set a
     * static pointer, conf_curr_sym, to point to the struct stash just looked
     * up.  conf_curr_sym will not be NULL if pr_stash_get_symbol2() returns
     * non-NULL.
     */

    if (m == NULL ||
        conf_curr_sym->sym_module == m) {
      xaset_remove(conf_symbol_table[symtab_idx],
        (xasetmember_t *) conf_curr_sym);
      destroy_pool(conf_curr_sym->sym_pool);
      conf_curr_sym = NULL;
      tab = NULL;
      count++;
    }

    tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, tab, &prev_idx,
      &hash);
  }

  return count;
}
Beispiel #6
0
void run_schedule(void) {
  sched_t *s, *snext;

  if (scheds == NULL ||
      scheds->xas_list == NULL) {
    return;
  }

  for (s = (sched_t *) scheds->xas_list; s; s = snext) {
    snext = s->next;

    if (s->loops-- <= 0) {
      s->f(s->a1, s->a2, s->a3, s->a4);
      xaset_remove(scheds, (xasetmember_t *) s);
      destroy_pool(s->pool);
    }
  }
}
Beispiel #7
0
void run_schedule(void) {
  sched_t *s, *snext;

  if (scheds == NULL ||
      scheds->xas_list == NULL) {
    return;
  }

  for (s = (sched_t *) scheds->xas_list; s; s = snext) {
    snext = s->next;

    pr_signals_handle();

    if (s->nloops-- <= 0) {
      s->cb(s->arg1, s->arg2, s->arg3, s->arg4);
      xaset_remove(scheds, (xasetmember_t *) s);
      destroy_pool(s->pool);
    }
  }
}
Beispiel #8
0
/* This function does the work of iterating through the list of registered
 * timers, checking to see if their callbacks should be invoked and whether
 * they should be removed from the registration list. Its return value is
 * the amount of time remaining on the first timer in the list.
 */
static int process_timers(int elapsed) {
  struct timer *t = NULL, *next = NULL;

  if (!recycled)
    recycled = xaset_create(timer_pool, NULL);

  if (!elapsed &&
      !recycled->xas_list) {

    if (!timers)
      return 0;

    return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0);
  }

  /* Critical code, no interruptions please */
  if (_indispatch)
    return 0;

  pr_alarms_block();
  _indispatch++;

  if (elapsed) {
    for (t = (struct timer *) timers->xas_list; t; t = next) {
      /* If this timer has already been handled, skip */
      next = t->next;

      if (t->remove) {
        /* Move the timer onto the free_timers chain, for later reuse. */
        xaset_remove(timers, (xasetmember_t *) t);
        xaset_insert(free_timers, (xasetmember_t *) t);

      } else if ((t->count -= elapsed) <= 0) {
        /* This timer's interval has elapsed, so trigger its callback. */

        pr_trace_msg("timer", 4,
          "%ld %s for timer ID %d ('%s', for module '%s') elapsed, invoking "
          "callback (%p)", t->interval,
          t->interval != 1 ? "seconds" : "second", t->timerno,
          t->desc ? t->desc : "<unknown>",
          t->mod ? t->mod->name : "<none>", t->callback);

        if (t->callback(t->interval, t->timerno, t->interval - t->count,
            t->mod) == 0) {

          /* A return value of zero means this timer is done, and can be
           * removed.
           */
          xaset_remove(timers, (xasetmember_t *) t);
          xaset_insert(free_timers, (xasetmember_t *) t);

        } else {
          /* A non-zero return value from a timer callback signals that
           * the timer should be reused/restarted.
           */
          pr_trace_msg("timer", 6, "restarting timer ID %d ('%s'), as per "
            "callback", t->timerno, t->desc ? t->desc : "<unknown>");

          xaset_remove(timers, (xasetmember_t *) t);
          t->count = t->interval;
          xaset_insert(recycled, (xasetmember_t *) t);
        }
      }
    }
  }

  /* Put the recycled timers back into the main timer list. */
  while ((t = (struct timer *) recycled->xas_list) != NULL) {
    xaset_remove(recycled, (xasetmember_t *) t);
    xaset_insert_sort(timers, (xasetmember_t *) t, TRUE);
  }

  _indispatch--;
  pr_alarms_unblock();

  /* If no active timers remain in the list, there is no reason to set the
   * SIGALRM handle.
   */
  return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0);
}
Beispiel #9
0
int pr_timer_add(int seconds, int timerno, module *mod, callback_t cb,
    const char *desc) {
  struct timer *t = NULL;

  if (seconds <= 0 ||
      cb == NULL ||
      desc == NULL) {
    errno = EINVAL;
    return -1;
  }

  if (!timers)
    timers = xaset_create(timer_pool, (XASET_COMPARE) timer_cmp);

  /* Check to see that, if specified, the timerno is not already in use. */
  if (timerno >= 0) {
    for (t = (struct timer *) timers->xas_list; t; t = t->next) {
      if (t->timerno == timerno) {
        errno = EPERM;
        return -1;
      }
    }
  }

  if (!free_timers)
    free_timers = xaset_create(timer_pool, NULL);

  /* Try to use an old timer first */
  pr_alarms_block();
  t = (struct timer *) free_timers->xas_list;
  if (t != NULL) {
    xaset_remove(free_timers, (xasetmember_t *) t);

  } else {

    if (timer_pool == NULL) {
      timer_pool = make_sub_pool(permanent_pool);
      pr_pool_tag(timer_pool, "Timer Pool");
    }

    /* Must allocate a new one */
    t = palloc(timer_pool, sizeof(struct timer));
  }

  if (timerno < 0) {
    /* Dynamic timer */
    if (dynamic_timerno < PR_TIMER_DYNAMIC_TIMERNO) {
      dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO;
    }

    timerno = dynamic_timerno++;
  }

  t->timerno = timerno;
  t->count = t->interval = seconds;
  t->callback = cb;
  t->mod = mod;
  t->remove = 0;
  t->desc = desc;

  /* If called while _indispatch, add to the recycled list to prevent
   * list corruption
   */

  if (_indispatch) {
    if (!recycled)
      recycled = xaset_create(timer_pool, NULL);
    xaset_insert(recycled, (xasetmember_t *) t);

  } else {
    xaset_insert_sort(timers, (xasetmember_t *) t, TRUE);
    nalarms++;
    set_sig_alarm();

    /* The handle_alarm() function also readjusts the timers lists
     * as part of its processing, so it needs to be called when a timer
     * is added.
     */
    handle_alarm();
  }

  pr_alarms_unblock();

  pr_trace_msg("timer", 7, "added timer ID %d ('%s', for module '%s'), "
    "triggering in %ld %s", t->timerno, t->desc,
    t->mod ? t->mod->name : "[none]", t->interval,
    t->interval != 1 ? "seconds" : "second");
  return timerno;
}
Beispiel #10
0
int pr_timer_remove(int timerno, module *mod) {
  struct timer *t = NULL, *tnext = NULL;
  int nremoved = 0;

  /* If there are no timers currently registered, do nothing. */
  if (!timers)
    return 0;

  pr_alarms_block();

  for (t = (struct timer *) timers->xas_list; t; t = tnext) {
    tnext = t->next;

    if ((timerno < 0 || t->timerno == timerno) &&
        (mod == ANY_MODULE || t->mod == mod)) {
      nremoved++;

      if (_indispatch) {
        t->remove++;

      } else {
        xaset_remove(timers, (xasetmember_t *) t);
        xaset_insert(free_timers, (xasetmember_t *) t);
	nalarms++;

        /* The handle_alarm() function also readjusts the timers lists
         * as part of its processing, so it needs to be called when a timer
         * is removed.
         */
        handle_alarm();
      }

      pr_trace_msg("timer", 7, "removed timer ID %d ('%s', for module '%s')",
        t->timerno, t->desc, t->mod ? t->mod->name : "[none]");
    }

    /* If we are removing a specific timer, break out of the loop now.
     * Otherwise, keep removing any matching timers.
     */
    if (nremoved > 0 &&
        timerno >= 0) {
      break;
    }
  }

  pr_alarms_unblock();

  if (nremoved == 0) {
    errno = ENOENT;
    return -1;
  }

  /* If we removed a specific timer because of the given timerno, return
   * that timerno value.
   */
  if (timerno >= 0) {
    return timerno;
  }

  return nremoved;
}
Beispiel #11
0
static int init_standalone_bindings(void) {
  int res = 0;
  server_rec *serv = NULL;
  unsigned char *default_server = NULL, is_default = FALSE;

  /* If a port is set to zero, the address/port is not bound to a socket
   * at all.
   */
  if (main_server->ServerPort) {

    /* If SocketBindTight is off, then pr_inet_create_conn() will
     * create and bind to a wildcard socket.  However, should it be an
     * IPv4 or an IPv6 wildcard socket?
     */
    if (!SocketBindTight) {
#ifdef PR_USE_IPV6
      if (pr_netaddr_use_ipv6()) {
        pr_inet_set_default_family(NULL, AF_INET6);

      } else {
        int default_family;

        default_family = pr_netaddr_get_family(main_server->addr);
        pr_inet_set_default_family(NULL, default_family);
      }
#else
      pr_inet_set_default_family(NULL,
        pr_netaddr_get_family(main_server->addr));
#endif /* PR_USE_IPV6 */
    }

    main_server->listen = pr_ipbind_get_listening_conn(main_server,
      (SocketBindTight ? main_server->addr : NULL), main_server->ServerPort);
    if (main_server->listen == NULL) {
      return -1;
    }

  } else {
    main_server->listen = NULL;
  }

  default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE);
  if (default_server != NULL &&
      *default_server == TRUE) {
    is_default = TRUE;
  }

  if (main_server->ServerPort ||
      is_default) {
    PR_CREATE_IPBIND(main_server, main_server->addr, main_server->ServerPort);
    PR_OPEN_IPBIND(main_server->addr, main_server->ServerPort,
      main_server->listen, is_default, TRUE, TRUE);
    PR_ADD_IPBINDS(main_server);
  }

  for (serv = main_server->next; serv; serv = serv->next) {
    config_rec *c;
    int is_namebind = FALSE;

    /* See if this server is a namebind, to be part of an existing ipbind. */
    c = find_config(serv->conf, CONF_PARAM, "ServerAlias", FALSE);
    while (c != NULL) {
      pr_signals_handle();

      res = pr_namebind_create(serv, c->argv[0], serv->addr, serv->ServerPort);
      if (res == 0) {
        is_namebind = TRUE;

        res = pr_namebind_open(c->argv[0], serv->addr, serv->ServerPort);
        if (res < 0) {
          pr_log_pri(PR_LOG_NOTICE,
            "%s:%d: notice: unable to open namebind '%s': %s", __FILE__,
            __LINE__, (char *) c->argv[0], strerror(errno));
        }

      } else {
        pr_log_pri(PR_LOG_NOTICE,
          "unable to create namebind for '%s' to %s#%u: %s",
          (char *) c->argv[0], pr_netaddr_get_ipstr(serv->addr),
          serv->ServerPort, strerror(errno));
      }

      c = find_config_next(c, c->next, CONF_PARAM, "ServerAlias", FALSE);
    }

    if (is_namebind == TRUE) {
      continue;
    }

    if (serv->ServerPort != main_server->ServerPort ||
        SocketBindTight ||
        !main_server->listen) {
      is_default = FALSE;

      default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE);
      if (default_server != NULL &&
          *default_server == TRUE) {
        is_default = TRUE;
      }

      if (serv->ServerPort) {
        if (!SocketBindTight) {
#ifdef PR_USE_IPV6
          if (pr_netaddr_use_ipv6()) {
            pr_inet_set_default_family(NULL, AF_INET6);

          } else {
            pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr));
          }
#else
          pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr));
#endif /* PR_USE_IPV6 */
        }

        serv->listen = pr_ipbind_get_listening_conn(serv,
          (SocketBindTight ? serv->addr : NULL), serv->ServerPort);
        if (serv->listen == NULL) {
          return -1;
        }

        PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
        PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default,
          FALSE, TRUE);
        PR_ADD_IPBINDS(serv);

      } else if (is_default) {
        serv->listen = NULL;

        PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
        PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default,
          FALSE, TRUE);
        PR_ADD_IPBINDS(serv);

      } else {
        serv->listen = NULL;
      }

    } else {
      /* Because this server is sharing the connection with the main server,
       * we need a cleanup handler to remove the server's reference when the
       * original connection's pool is destroyed.
       */

      is_default = FALSE;
      default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE);
      if (default_server != NULL &&
          *default_server == TRUE) {
        is_default = TRUE;
      }

      serv->listen = main_server->listen;
      register_cleanup(serv->listen->pool, &serv->listen, server_cleanup_cb,
        server_cleanup_cb);

      PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
      PR_OPEN_IPBIND(serv->addr, serv->ServerPort, NULL, is_default, FALSE,
        TRUE);
      PR_ADD_IPBINDS(serv);
    }
  }

  /* Any "unclaimed" listening conns can be removed and closed. */
  if (listening_conn_list) {
    struct listener_rec *lr, *lrn;

    for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lrn) {
      lrn = lr->next;

      if (!lr->claimed) {
        xaset_remove(listening_conn_list, (xasetmember_t *) lr);
        destroy_pool(lr->pool);
      }
    }
  }

  return 0;
}