アットウィキロゴ

vsftpd_1.2.1_main.c

memo


処理の流れ


  1. die_unless_privileged(); /* Just get out unless we start with requisite privilege */
  2. 番号リスト

  1. コンフィグ読み出し(?)
  • vsf_sysutil_map_anon_pages_init();

 /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
  * to be done early (i.e. before config file parse, which may use
  * anonymous pages
  */
 これは、MAP_ANONを欠きながらシステムの上で/dev/zeroを開く必要があるかもしれません。 
 早くされるべき必要性、(すなわち、コンフィグファイルが分析される前に、どれが匿名のページを使用するかもしれないか。

  • コンフィグファイルの状態確認?
   int retval = vsf_sysutil_stat(p_config_name, &p_statbuf);

  • コンフィグ読み出し
    • if (!vsf_sysutil_retval_is_error(retval)) → vsf_parseconf_load_file(p_config_name, 1);
    • コンフィグを読み込めない場合はエラー
      • else if (config_specified) → die2("vsftpd: cannot open config file:", p_config_name);
                   vsf_sysutil_free(p_statbuf);

  1. わからん
    • tunable_setproctitle_enable が設定されている場合(デフォルトは 0

tunable_setproctitle_enable
有効にした場合、システムのプロセスリスト(例えば ps aux コマンド)にセッションの状態に関する情報を表示する。
つまり、表示されるプロセス名が vsftpd のセッションがどうなっているか (idle, downloading など)に応じて変化する。
セキュリティ上、これを off のままにしておきたいと思うのが普通である。 

     /* Warning -- warning -- may nuke argv, environ */

vsf_sysutil_setproctitle_init(argc, argv);

  1. Standalone Mode (inetd を使用しない)で起動するか

どちらかが設定されていれば、Standalone モードで起動する
./tunables.h:extern int tunable_listen; (デフォルトは0)
./tunables.h:extern int tunable_listen_ipv6; (デフォルトは0)

tunable_listen
YES に設定した場合、スタンドアロンモードで起動する。
これは inetd などのスーパーサーバから起動してはいけないということを意味する。
その代わりに、vsftpd プログラムを一度だけ直接実行すればよい。 
vsftpd 自身が、入ってくる接続を待ち、処理する面倒をみる。 

tunable_listen_ipv6
IPv4 ソケットの代わりに IPv6 ソケットを待ち受ける点を除けば、 listen オプションと同じである。
このオプションと listen オプションは、どちらか一方しか指定することができない。 

   struct vsf_client_launch ret = vsf_standalone_main();
   the_session.num_clients = ret.num_children;
   the_session.num_this_ip = ret.num_this_ip;

  1. 健全性チェック
  • do_sanity_checks();

 /* Sanity checks - exit with a graceful error message if our STDIN is not
  * a socket. Also check various config options don't collide.
  */
 健全度チェック--私たちのSTDINがソケットでないなら優雅なエラーメッセージと共に出てください。 
 また、チェックの様々なコンフィグオプションは衝突しません。

  1. セッション初期化
  • session_init(&the_session);

/* Initializes session globals - e.g. IP addr's etc. */

  1. 環境初期化
  • env_init();

/* Set up "environment", e.g. process group etc. */
 
  1. ロギング設定
  • vsf_log_init(&the_session);

/* Set up logging - must come after global init because we need the remote
 * address to convert into text
 */
伐採--私たちがテキストに変換するためにリモートアドレスを必要とするのでグローバルなイニットに続かなければならないのをセットアップしてください。

  1. str_alloc_text(&the_session.remote_ip_str,
                vsf_sysutil_inet_ntop(the_session.p_remote_addr));
 
  1. /* Set up options on the command socket */
  • vsf_cmdio_sock_setup();
  • if (tunable_setproctitle_enable)
    • vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);vsf_sysutil_setproctitle("connected");

  • /* We might chroot() very soon (one process model), so we need to open
  * any required config files here.
  */

  1. TCP-Wrapper を使用するか

tunable_tcp_wrappers が設定されている場合、(デフォルトは0)

tunable_tcp_wrappers
有効にした場合、 vsftpd を tcp_wrappers をサポートしてコンパイルしてあれば、外から来る接続は tcp_wrappers のアクセス制御が適用される。
さらに IP ごとの設定のための仕組みがある。 
tcp_wrappers で環境変数 VSFTPD_LOAD_CONF をセットした場合 (訳注: /etc/hosts.allow で指定することが可能)、その環境変数で指定したファイルを vsftpd の設定ファイルとして読み込む。 

    the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
    const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");

  1. if (p_load_conf)
     vsf_parseconf_load_file(p_load_conf, 1);

  1. tunable_deny_email_enable が設定されている場合(デフォルトは0)

tunable_deny_email_enable
YES に設定した場合、anonymous ユーザのパスワード(e-mail アドレス)のうち、ログインを拒否したいもののリストを設定できる。
デフォルトでは、このリストは /etc/vsftpd.banned_emails ファイルであるが、 banned_email_file 設定によってこれを変更することができる。 

    int retval = str_fileread(&the_session.banned_email_str,
                             tunable_banned_email_file, VSFTP_CONF_FILE_MAX);

  1. if (vsf_sysutil_retval_is_error(retval))
     die2("cannot open anon e-mail list file:", tunable_banned_email_file);

  1. バナーファイルがあるか
  • ある場合

tunable_banner_file
誰かがサーバに接続したときに表示するテキストを格納するファイル名を指定する。
このオプションが設定された場合、 ftpd_banner で指定される文字列よりも優先される。 

  if (tunable_banner_file)
    int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
                             VSFTP_CONF_FILE_MAX);
  
  • 無い場合
  if (vsf_sysutil_retval_is_error(retval))
    die2("cannot open banner file:", tunable_banner_file);


tunable_secure_email_list_enable(デフォルトは0)
匿名ログインで許可する e-mail パスワードのリストを指定したい場合にだけ YES に設定すること。
仮想的なユーザーを必要とせずに、低セキュリティなコンテンツへのアクセスを制限する、面倒の少ないやり方として便利である。 
YES に設定した場合には、 email_password_file で指定されるファイルに書かれているパスワードが与えられない限り、匿名ログインを許可しない。
このファイルのフォーマットは 1 行に 1 パスワードで、余分な空白があってはいけない。デフォルトのファイルはは /etc/vsftpd.email_passwords である。 

if (tunable_secure_email_list_enable)
    int retval = str_fileread(&the_session.email_passwords_str,
                             tunable_email_password_file,
                             VSFTP_CONF_FILE_MAX);
  1. if (vsf_sysutil_retval_is_error(retval))
     die2("cannot open email passwords file:", tunable_email_password_file);

/* Special case - can force one process model if we've got a setup
  * needing _no_ privs
  */
  1. Process Model(?)の確認

  • 以下の条件にマッチする場合は、One Process Model(?)で起動する

ローカルログインを許可しない
Port20で接続しない
匿名ユーザーで?

if (!tunable_local_enable && !tunable_connect_from_port_20 &&!tunable_chown_uploads)
  tunable_one_proess_model = 1;

./tunables.h:extern int tunable_local_enable; /* Allow local logins */
./tunables.h:extern int tunable_connect_from_port_20; /* PORT connects from port 20 */
./tunables.h:extern int tunable_chown_uploads; /* chown() anon uploaded files */
./tunables.h:extern int tunable_one_process_model; /* Go faster stripes ;-) */

tunable_local_enable(デフォルトは0)
ローカルユーザのログインを許可するかどうかを制御する。 
YES に設定した場合、/etc/passwd にある普通のユーザアカウントをログインに使う。

tunable_connect_from_port_20(デフォルトは0)
PORT でのデータ接続において、サーバが(送信元)ポートに 20(ftp-data) を使うかどうか制御する。
セキュリティ上の理由から、いくつかのクライアントはポート 20 を要求する。
逆に言えば、このオプションを無効にすることで、わずかではあるが vsftpd をより少ない特権で動作させることができる。 

tunable_chown_uploads(デフォルトは0)
YES に設定した場合、anonymous でアップロードされたファイルの所有者を chown_username で設定したユーザにする。
管理上、そして多分セキュリティの観点から便利である。

tunable_one_process_model(デフォルトは0)
もし Linux 2.4 カーネルを使用しているならば、一つの接続に一つのプロセスを使用するという、異なったセキュリティモデルを使用することができる。
これは純粋なセキュリティモデルから少し外れるが、性能を得ることができる。
自サイトで非常に多いユーザの同時接続をサポートし、自分が何をしているか知っている人だけが、このオプションを有効にしたくなる。 

if (tunable_one_process_model)
    vsf_one_process_start(&the_session);

  • 条件にマッチしない場合は、Two Process Model(?)で起動する
    vsf_two_process_start(&the_session);

  1. /* NOTREACHED */
 bug("should not get here: main");
 return 1;

source


/*
 * Part of Very Secure FTPd
 * Licence: GPL
 * Author: Chris Evans
 * main.c
 */

#include "session.h"
#include "utility.h"
#include "tunables.h"
#include "logging.h"
#include "str.h"
#include "filestr.h"
#include "ftpcmdio.h"
#include "sysutil.h"
#include "sysdeputil.h"
#include "defs.h"
#include "parseconf.h"
#include "oneprocess.h"
#include "twoprocess.h"
#include "standalone.h"
#include "tcpwrap.h"

/*
 * Forward decls of helper functions
 */
static void die_unless_privileged(void);
static void do_sanity_checks(void);
static void session_init(struct vsf_session* p_sess);
static void env_init(void);

int
main(int argc, const char* argv[])
{
 struct vsf_session the_session =
 {
   /* Control connection */
   0, 0,
   /* Data connection */
   -1, 0, -1, 0, 0, 0, 0,
   /* Login */
   1, INIT_MYSTR, INIT_MYSTR,
   /* Protocol state */
   0, 1, INIT_MYSTR, 0, 0,
   /* Session state */
   0,
   /* Userids */
   -1, -1, -1,
   /* Pre-chroot() cache */
   INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1,
   /* Logging */
   -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
   /* Buffers */
   INIT_MYSTR, INIT_MYSTR,
   /* Parent <-> child comms */
   0, -1, -1,
   /* Number of clients */
   0, 0
 };
 int config_specified = 0;
 const char* p_config_name = VSFTP_DEFAULT_CONFIG;
 /* Zero or one argument supported. If one argument is passed, it is the
  * path to the config file
  */
 if (argc > 2)
 {
   die("vsftpd: too many arguments (I take an optional config file only)");
 }
 else if (argc == 0)
 {
   die("vsftpd: missing argv[0]");
 }
 if (argc == 2)
 {
   p_config_name = argv[1];
   config_specified = 1;
 }
 /* Just get out unless we start with requisite privilege */
 die_unless_privileged();
 /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
  * to be done early (i.e. before config file parse, which may use
  * anonymous pages
  */
 vsf_sysutil_map_anon_pages_init();
 /* Parse config file if it's there */
 {
   struct vsf_sysutil_statbuf* p_statbuf = 0;
   int retval = vsf_sysutil_stat(p_config_name, &p_statbuf);
   if (!vsf_sysutil_retval_is_error(retval))
   {
     vsf_parseconf_load_file(p_config_name, 1);
   }
   else if (config_specified)
   {
     die2("vsftpd: cannot open config file:", p_config_name);
   }
   vsf_sysutil_free(p_statbuf);
 }
 if (tunable_setproctitle_enable)
 {
   /* Warning -- warning -- may nuke argv, environ */
   vsf_sysutil_setproctitle_init(argc, argv);
 }
 if (tunable_listen || tunable_listen_ipv6)
 {
   /* Standalone mode */
   struct vsf_client_launch ret = vsf_standalone_main();
   the_session.num_clients = ret.num_children;
   the_session.num_this_ip = ret.num_this_ip;
 }
 /* Sanity checks - exit with a graceful error message if our STDIN is not
  * a socket. Also check various config options don't collide.
  */
 do_sanity_checks();
 /* Initializes session globals - e.g. IP addr's etc. */
 session_init(&the_session);
 /* Set up "environment", e.g. process group etc. */
 env_init();
 /* Set up logging - must come after global init because we need the remote
  * address to convert into text
  */
 vsf_log_init(&the_session);
 str_alloc_text(&the_session.remote_ip_str,
                vsf_sysutil_inet_ntop(the_session.p_remote_addr));
 /* Set up options on the command socket */
 vsf_cmdio_sock_setup();
 if (tunable_setproctitle_enable)
 {
   vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
   vsf_sysutil_setproctitle("connected");
 }
 /* We might chroot() very soon (one process model), so we need to open
  * any required config files here.
  */
 if (tunable_tcp_wrappers)
 {
   the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
 }
 {
   const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");
   if (p_load_conf)
   {
     vsf_parseconf_load_file(p_load_conf, 1);
   }
 }
 if (tunable_deny_email_enable)
 {
   int retval = str_fileread(&the_session.banned_email_str,
                             tunable_banned_email_file, VSFTP_CONF_FILE_MAX);
   if (vsf_sysutil_retval_is_error(retval))
   {
     die2("cannot open anon e-mail list file:", tunable_banned_email_file);
   }
 }
 if (tunable_banner_file)
 {
   int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
                             VSFTP_CONF_FILE_MAX);
   if (vsf_sysutil_retval_is_error(retval))
   {
     die2("cannot open banner file:", tunable_banner_file);
   }
 }
 if (tunable_secure_email_list_enable)
 {
   int retval = str_fileread(&the_session.email_passwords_str,
                             tunable_email_password_file,
                             VSFTP_CONF_FILE_MAX);
   if (vsf_sysutil_retval_is_error(retval))
   {
     die2("cannot open email passwords file:", tunable_email_password_file);
   }
 }
 /* Special case - can force one process model if we've got a setup
  * needing _no_ privs
  */
 if (!tunable_local_enable && !tunable_connect_from_port_20 &&
     !tunable_chown_uploads)
 {
   tunable_one_process_model = 1;
 }
 if (tunable_one_process_model)
 {
   vsf_one_process_start(&the_session);
 }
 else
 {
   vsf_two_process_start(&the_session);
 }
 /* NOTREACHED */
 bug("should not get here: main");
 return 1;
}

static void
die_unless_privileged(void)
{
 if (!vsf_sysutil_running_as_root())
 {
   die("vsftpd: must be started as root");
 }
}

static void
do_sanity_checks(void)
{
 {
   struct vsf_sysutil_statbuf* p_statbuf = 0;
   vsf_sysutil_fstat(VSFTP_COMMAND_FD, &p_statbuf);
   if (!vsf_sysutil_statbuf_is_socket(p_statbuf))
   {
     die("vsftpd: does not run standalone, must be started from inetd");
   }
   vsf_sysutil_free(p_statbuf);
 }
 if (tunable_one_process_model)
 {
   if (tunable_local_enable)
   {
     die("vsftpd: security: 'one_process_model' is anonymous only");
   }
   if (!vsf_sysdep_has_capabilities_as_non_root())
   {
     die("vsftpd: security: 'one_process_model' needs a better OS");
   }
 }
 if (!tunable_local_enable && !tunable_anonymous_enable)
 {
   die("vsftpd: both local and anonymous access disabled!");
 }
}

static void
env_init(void)
{
 vsf_sysutil_make_session_leader();
 /* Set up a secure umask - we'll set the proper one after login */
 vsf_sysutil_set_umask(VSFTP_SECURE_UMASK);
 /* Fire up libc's timezone initialisation, before we chroot()! */
 vsf_sysutil_tzset();
 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */
 vsf_sysutil_install_null_sighandler(kVSFSysUtilSigPIPE);
}

static void
session_init(struct vsf_session* p_sess)
{
 /* Get the addresses of the control connection */
        vsf_sysutil_getpeername(VSFTP_COMMAND_FD, &p_sess->p_remote_addr);
        vsf_sysutil_getsockname(VSFTP_COMMAND_FD, &p_sess->p_local_addr);
 /* If anonymous mode is active, fetch the uid of the anonymous user */
 if (tunable_anonymous_enable)
 {
   const struct vsf_sysutil_user* p_user =
                    vsf_sysutil_getpwnam(tunable_ftp_username);
   if (p_user == 0)
   {
                  die2("vsftpd: cannot locate user specified in 'ftp_username':",
          tunable_ftp_username);
   }
   p_sess->anon_ftp_uid = vsf_sysutil_user_getuid(p_user);
 }
 if (tunable_guest_enable)
 {
   const struct vsf_sysutil_user* p_user =
                    vsf_sysutil_getpwnam(tunable_ftp_username);
   if (p_user == 0)
   {
                  die2("vsftpd: cannot locate user specified in 'guest_username':",
          tunable_guest_username);
   }
   p_sess->guest_user_uid = vsf_sysutil_user_getuid(p_user);
 }
 if (tunable_chown_uploads)
 {
   const struct vsf_sysutil_user* p_user =
                    vsf_sysutil_getpwnam(tunable_chown_userna);
   if (p_user == 0)
   {
                  die2("vsftpd: cannot locate user specified in 'chown_username':",
          tunable_chown_username);
   }
   p_sess->anon_upload_chown_uid = vsf_sysutil_user_getuid(p_user);
 }
}
最終更新:2009年03月03日 23:45
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。