Exemplo n.º 1
0
static array_header *counter_file_read(pr_fh_t *fh) {
  char buf[PR_TUNABLE_BUFFER_SIZE];
  array_header *ids = make_array(counter_pool, 0, sizeof(int));

  /* Read the list of IDs in the CounterFile into an array. */

  if (counter_file_lock(fh, LOCK_SH) < 0) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "error read-locking CounterFile '%s': %s", fh->fh_path, strerror(errno));
  }

  if (pr_fsio_lseek(fh, 0, SEEK_SET) < 0) {
    int xerrno = errno;

    counter_file_lock(fh, LOCK_UN);
    errno = xerrno;

    return NULL;
  }

  memset(buf, '\0', sizeof(buf));
  while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) {
    int id;

    pr_signals_handle();

    id = atoi(buf);
    if (id < 0) {
      continue;
    }

    *((int *) push_array(ids)) = id;
  }

  if (counter_file_lock(fh, LOCK_UN) < 0) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "error unlocking CounterFile '%s': %s", fh->fh_path, strerror(errno));
  }

  return ids;
}
Exemplo n.º 2
0
/* This getline() function is quite similar to pr_fsio_getline(), except
 * that it a) enforces the 72-byte max line length from RFC4716, and b)
 * properly handles lines ending with CR, LF, or CRLF.
 *
 * Technically it allows one more byte than necessary, since the worst case
 * is 74 bytes (72 + CRLF); this also means 73 + CR or 73 + LF.  The extra
 * byte is for the terminating NUL.
 */
static char *filestore_getline(sftp_keystore_t *store, pool *p) {
  char linebuf[75], *line = "", *res;
  struct filestore_data *store_data = store->keystore_data;

  while (TRUE) {
    size_t linelen;

    pr_signals_handle();

    memset(&linebuf, '\0', sizeof(linebuf));
    res = pr_fsio_gets(linebuf, sizeof(linebuf) - 1, store_data->fh);

    if (res == NULL) {
      if (errno == EINTR) {
        continue;
      }

      pr_trace_msg(trace_channel, 10, "reached end of '%s', no matching "
        "key found", store_data->path);
      errno = EOF;
      return NULL;
    }

    linelen = strlen(linebuf);
    if (linelen >= 1) {
      if (linebuf[linelen - 1] == '\r' ||
          linebuf[linelen - 1] == '\n') {
        char *tmp;
        unsigned int header_taglen, header_valuelen;
        int have_line_continuation = FALSE;

        store_data->lineno++;

        linebuf[linelen - 1] = '\0';
        line = pstrcat(p, line, linebuf, NULL);

        if (line[strlen(line) - 1] == '\\') {
          have_line_continuation = TRUE;
          line[strlen(line) - 1] = '\0';
        }

        tmp = strchr(line, ':');
        if (tmp == NULL) {
          return line;
        } 

        /* We have a header.  Make sure the header tag is not longer than
         * the specified length of 64 bytes, and that the header value is
         * not longer than 1024 bytes.
         */
        header_taglen = tmp - line;
        if (header_taglen > 64) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header tag too long (%u) on line %u of '%s'", header_taglen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        /* Header value starts at 2 after the ':' (one for the mandatory
         * space character.
         */
        header_valuelen = strlen(line) - (header_taglen + 2);
        if (header_valuelen > 1024) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header value too long (%u) on line %u of '%s'", header_valuelen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        if (!have_line_continuation) {
          return line;
        }

        continue;

      } else if (linelen >= 2 &&
          linebuf[linelen - 2] == '\r' &&
          linebuf[linelen - 1] == '\n') {
        char *tmp;
        unsigned int header_taglen, header_valuelen;
        int have_line_continuation = FALSE;

        store_data->lineno++;

        linebuf[linelen - 2] = '\0';
        linebuf[linelen - 1] = '\0';
        line = pstrcat(p, line, linebuf, NULL);

        if (line[strlen(line) - 1] == '\\') {
          have_line_continuation = TRUE;
          line[strlen(line) - 1] = '\0';
        }

        tmp = strchr(line, ':');
        if (tmp == NULL) {
          return line;
        } 

        /* We have a header.  Make sure the header tag is not longer than
         * the specified length of 64 bytes, and that the header value is
         * not longer than 1024 bytes.
         */
        header_taglen = tmp - line;
        if (header_taglen > 64) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header tag too long (%u) on line %u of '%s'", header_taglen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        /* Header value starts at 2 after the ':' (one for the mandatory
         * space character.
         */
        header_valuelen = strlen(line) - (header_taglen + 2);
        if (header_valuelen > 1024) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header value too long (%u) on line %u of '%s'", header_valuelen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        if (!have_line_continuation) {
          return line;
        }

        continue;

      } else {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
          "line too long (%lu) on line %u of '%s'", (unsigned long) linelen,
          store_data->lineno, store_data->path);
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
          "Make sure that '%s' is a RFC4716 formatted key", store_data->path);
        errno = EINVAL;
        break;
      }
    }
  }

  return NULL;
}
Exemplo n.º 3
0
const char *sftp_display_fh_get_msg(pool *p, pr_fh_t *fh) {
  struct stat st;
  char buf[PR_TUNABLE_BUFFER_SIZE], *msg = "";
  int len, res;
  unsigned int *current_clients = NULL;
  unsigned int *max_clients = NULL;
  off_t fs_size = 0;
  void *v;
  const char *serverfqdn = main_server->ServerFQDN;
  char *outs, mg_size[12] = {'\0'}, mg_size_units[12] = {'\0'},
    mg_max[12] = "unlimited";
  char mg_class_limit[12] = {'\0'}, mg_cur[12] = {'\0'},
    mg_cur_class[12] = {'\0'};
  const char *mg_time;
  char *rfc1413_ident = NULL, *user = NULL;

  /* Stat the opened file to determine the optimal buffer size for IO. */
  memset(&st, 0, sizeof(st));
  if (pr_fsio_fstat(fh, &st) == 0) {
    fh->fh_iosz = st.st_blksize;
  }

  res = pr_fs_fgetsize(fh->fh_fd, &fs_size);
  if (res < 0 &&
      errno != ENOSYS) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error getting filesystem size for '%s': %s", fh->fh_path,
      strerror(errno));
    fs_size = 0;
  }

  snprintf(mg_size, sizeof(mg_size), "%" PR_LU, (pr_off_t) fs_size);
  format_size_str(mg_size_units, sizeof(mg_size_units), fs_size);

  mg_time = pr_strtime(time(NULL));

  max_clients = get_param_ptr(main_server->conf, "MaxClients", FALSE);

  v = pr_table_get(session.notes, "client-count", NULL);
  if (v) {
    current_clients = v;
  }

  snprintf(mg_cur, sizeof(mg_cur), "%u", current_clients ? *current_clients: 1);

  if (session.conn_class != NULL &&
      session.conn_class->cls_name) {
    unsigned int *class_clients = NULL;
    config_rec *maxc = NULL;
    unsigned int maxclients = 0;

    v = pr_table_get(session.notes, "class-client-count", NULL);
    if (v) {
      class_clients = v;
    }

    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u",
      class_clients ? *class_clients : 0);

    /* For the %z variable, first we scan through the MaxClientsPerClass,
     * and use the first applicable one.  If none are found, look for
     * any MaxClients set.
     */

    maxc = find_config(main_server->conf, CONF_PARAM, "MaxClientsPerClass",
      FALSE);

    while (maxc) {
      pr_signals_handle();

      if (strcmp(maxc->argv[0], session.conn_class->cls_name) != 0) {
        maxc = find_config_next(maxc, maxc->next, CONF_PARAM,
          "MaxClientsPerClass", FALSE);
        continue;
      }

      maxclients = *((unsigned int *) maxc->argv[1]);
      break;
    }

    if (maxclients == 0) {
      maxc = find_config(main_server->conf, CONF_PARAM, "MaxClients", FALSE);

      if (maxc)
        maxclients = *((unsigned int *) maxc->argv[0]);
    }

    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", maxclients);

  } else {
    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u",
      max_clients ? *max_clients : 0);
    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", 0);
  }

  snprintf(mg_max, sizeof(mg_max), "%u", max_clients ? *max_clients : 0);

  user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
  if (user == NULL)
    user = "";

  rfc1413_ident = pr_table_get(session.notes, "mod_ident.rfc1413-ident", NULL);
  if (rfc1413_ident == NULL) {
    rfc1413_ident = "UNKNOWN";
  }

  memset(buf, '\0', sizeof(buf));
  while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) {
    char *tmp;

    pr_signals_handle();

    buf[sizeof(buf)-1] = '\0';
    len = strlen(buf);

    while (len > 0 &&
           (buf[len-1] == '\r' || buf[len-1] == '\n')) {
      pr_signals_handle();

      buf[len-1] = '\0';
      len--;
    }

    /* Check for any Variable-type strings. */
    tmp = strstr(buf, "%{");
    while (tmp) {
      char *key, *tmp2;
      const char *val;

      pr_signals_handle();

      tmp2 = strchr(tmp, '}');
      if (tmp2 == NULL) {
        /* No closing '}' found in this string, so no need to look for any
         * aother '%{' opening sequence.  Just move on.
         */
        tmp = NULL;
        break;
      }

      key = pstrndup(p, tmp, tmp2 - tmp + 1);

      /* There are a couple of special-case keys to watch for:
       *
       *   env:$var
       *   time:$fmt
       *
       * The Var API does not easily support returning values for keys
       * where part of the value depends on part of the key.  That's why
       * these keys are handled here, instead of in pr_var_get().
       */

      if (strncmp(key, "%{time:", 7) == 0) {
        char time_str[128], *fmt;
        time_t now;
        struct tm *time_info;

        fmt = pstrndup(p, key + 7, strlen(key) - 8);

        now = time(NULL);
        time_info = pr_localtime(NULL, &now);

        memset(time_str, 0, sizeof(time_str));
        strftime(time_str, sizeof(time_str), fmt, time_info);

        val = pstrdup(p, time_str);

      } else if (strncmp(key, "%{env:", 6) == 0) {
        char *env_var;

        env_var = pstrndup(p, key + 6, strlen(key) - 7);
        val = pr_env_get(p, env_var);
        if (val == NULL) {
          pr_trace_msg("var", 4,
            "no value set for environment variable '%s', using \"(none)\"",
            env_var);
          val = "(none)";
        }

      } else {
        val = pr_var_get(key);
        if (val == NULL) {
          pr_trace_msg("var", 4,
            "no value set for name '%s', using \"(none)\"", key);
          val = "(none)";
        }
      }

      outs = sreplace(p, buf, key, val, NULL);
      sstrncpy(buf, outs, sizeof(buf));

      tmp = strstr(outs, "%{");
    }

    outs = sreplace(p, buf,
      "%C", (session.cwd[0] ? session.cwd : "(none)"),
      "%E", main_server->ServerAdmin,
      "%F", mg_size,
      "%f", mg_size_units,
      "%i", "0",
      "%K", "0",
      "%k", "0B",
      "%L", serverfqdn,
      "%M", mg_max,
      "%N", mg_cur,
      "%o", "0",
      "%R", (session.c && session.c->remote_name ?
        session.c->remote_name : "(unknown)"),
      "%T", mg_time,
      "%t", "0",
      "%U", user,
      "%u", rfc1413_ident,
      "%V", main_server->ServerName,
      "%x", session.conn_class ? session.conn_class->cls_name : "(unknown)",
      "%y", mg_cur_class,
      "%z", mg_class_limit,
      NULL);

    /* Always make sure that the lines we send are CRLF-terminated. */
    msg = pstrcat(p, msg, outs, "\r\n", NULL);

    /* Clear the buffer for the next read. */
    memset(buf, '\0', sizeof(buf));
  }

  return msg;
}