Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > C/C++ > vsftpd源码"探究"<二>
【标  题】:vsftpd源码"探究"<二>
【关键字】:vsftpd,quot,quot
【来  源】:http://blog.chinaunix.net/article.php?articleId=61165&blogId=12122

vsftpd源码"探究"<二>

Your Ad Here 此篇学习vsftpd中关于配置文件分析的那段代码.至于作者为什么采取这样的方法,本人十分不解,还请各位高人指点一二.

前期工作准备完毕,接下来我们就正式研究Vsftpd中的源程序(源程序可从http://vsftpd.beasts.org/处获得,版本:vsftpd-1.2.1).首先从main.c文件着手,为了查看方便,我把main.c中的main函数贴出来.

1 int
2 main(int argc, const char* argv[])
3 {
4 struct vsf_session the_session =
5 {
6    /* Control connection */
7    0, 0,
8   /* Data connection */
9    -1, 0, -1, 0, 0, 0, 0,
10    /* Login */
11    1, INIT_MYSTR, INIT_MYSTR,
12    /* Protocol state */
13   0, 1, INIT_MYSTR, 0, 0,
14    /* Session state */
15    0,
16    /* Userids */
17    -1, -1, -1,
18    /* Pre-chroot() cache */
19    INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1,
20    /* Logging */
21    -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
22    /* Buffers */
23    INIT_MYSTR, INIT_MYSTR,
24    /* Parent <-> child comms */
25    0, -1, -1,
26    /* Number of clients */
27    0, 0
28  };
29  int config_specified = 0;
30  const char* p_config_name = VSFTP_DEFAULT_CONFIG;
31  /* Zero or one argument supported. If one argument is passed, it is the
32  * path to the config file
33   */
34  if (argc > 2)
35  {
36    die("vsftpd: too many arguments (I take an optional config file only)");
37  }
38  else if (argc == 0)
39  {
40    die("vsftpd: missing argv[0]");
41 }
42  if (argc == 2)
43  {
44    p_config_name = argv[1];
45    config_specified = 1;
46  }
47  /* Just get out unless we start with requisite privilege */
48  die_unless_privileged();
49  /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
50   * to be done early (i.e. before config file parse, which may use
51   * anonymous pages
52   */
53  /*******************************************/
54  vsf_sysutil_map_anon_pages_init();
55  /*****************************************/
56 
57  /* 分析配置文件 */
58  {
59    struct vsf_sysutil_statbuf* p_statbuf = 0;
60   /*因为p_statbuf的指针中并无确定的地址,所以传送该指针的地址*/
61    int retval = vsf_sysutil_stat(p_config_name, &p_statbuf);/*p_statbuf指向stat结构*/
62    if (!vsf_sysutil_retval_is_error(retval))
63    {
64      vsf_parseconf_load_file(p_config_name, 1);
65    }
66    else if (config_specified)
67    {
68      die2("vsftpd: cannot open config file:", p_config_name);
69    }
70    vsf_sysutil_free(p_statbuf);
71  }/*分析配置文件结束*/
72 
73  if (tunable_setproctitle_enable)/*设置进程标题*/
74  {
75   /* Warning -- warning -- may nuke argv, environ */
76    vsf_sysutil_setproctitle_init(argc, argv);
77  }
78 
79  /*Standalone模式*/
80  if (tunable_listen || tunable_listen_ipv6)
81  {
82    /* Standalone mode */
83    struct vsf_client_launch ret = vsf_standalone_main();
84    /*父进程继续监听,0,1,2重定向到子进程Socket*/
85    the_session.num_clients = ret.num_children;
86    the_session.num_this_ip = ret.num_this_ip;
87  }
88 
89  /* Sanity checks - exit with a graceful error message if our STDIN is not
90   * a socket. Also check various config options don't collide.
91   */
92  do_sanity_checks();
93 /* Initializes session globals - e.g. IP addr's etc. */
94  session_init(&the_session);
95  /* Set up "environment", e.g. process group etc. */
96  env_init();
97  /* Set up logging - must come after global init because we need the remote
98   * address to convert into text
99   */
100  vsf_log_init(&the_session);/*日志初始化*/
101 
102  str_alloc_text(&the_session.remote_ip_str,
103                 vsf_sysutil_inet_ntop(the_session.p_remote_addr));
104  /* Set up options on the command socket */
105  vsf_cmdio_sock_setup();/*设置控制连接属性*/
106  /*设置进程标题:"IP地址+connected"*/
107  if (tunable_setproctitle_enable)
108  {
109    vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
110    vsf_sysutil_setproctitle("connected");
111  }
112  /* We might chroot() very soon (one process model), so we need to open
113   * any required config files here.
114   */
115   /*如果启用, 并且在编译 vsftpd 时加入了对 TCP_Wrappers 的支持,
116    *则连入请求转由 TCP_Wrappers 完成访问控制. 另外, 这是基于
117    *每个IP的配置机制. 如果 tcp_wrappers 设置了 VSFTPD_LOAD_CONF
118    * 环境变量, 则 vsftpd 会话将会试图加载在此变量中指定的 vsftpd
119    * 配置文件.
120    */
121  if (tunable_tcp_wrappers)
122  {
123    the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
124  }
125  {
126    const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");
127    if (p_load_conf)
128    {
129      vsf_parseconf_load_file(p_load_conf, 1);
130    }
131  }
132  if (tunable_deny_email_enable)
133  {
134    int retval = str_fileread(&the_session.banned_email_str,
135                              tunable_banned_email_file, VSFTP_CONF_FILE_MAX);
136    if (vsf_sysutil_retval_is_error(retval))
137    {
138      die2("cannot open anon e-mail list file:", tunable_banned_email_file);
139    }
140  }
141  if (tunable_banner_file)
142  {
143    int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
144                              VSFTP_CONF_FILE_MAX);
145    if (vsf_sysutil_retval_is_error(retval))
146    {
147      die2("cannot open banner file:", tunable_banner_file);
148    }
149  }
150  if (tunable_secure_email_list_enable)
151  {
152    int retval = str_fileread(&the_session.email_passwords_str,
153                              tunable_email_password_file,
154                              VSFTP_CONF_FILE_MAX);
155    if (vsf_sysutil_retval_is_error(retval))
156    {
157      die2("cannot open email passwords file:", tunable_email_password_file);
158    }
159  }
160  /* Special case - can force one process model if we've got a setup
161   * needing _no_ privs/*不需要特权*/
162   */
163  /*默认: NO
164    *connect_from_port_20
165    *用于控制在服务器端, 是否使用端口20(ftp-data)进行数据联接.
166    *基于安全的考虑, 有些客户端需要这样做. 相反, 禁用这个选项,
167    *可以使 vsftpd 以较少特权运行
168    */
169  if (!tunable_local_enable && !tunable_connect_from_port_20 &&
170      !tunable_chown_uploads)/*禁止本地登录&&禁止使用端口20进行数据连接&&禁止将匿名上传的文件宿主修改*/
171  {
172    tunable_one_process_model = 1;
173  }
174  if (tunable_one_process_model)
175  {
176    vsf_one_process_start(&the_session);
177  }
178  else
179  {
180    vsf_two_process_start(&the_session);
181  }
182  /* NOTREACHED */
183  bug("should not get here: main");
184  return 1;
185}

从第34->46行是对命令行参数的分析,在此略过,第48行调用函数die_unless_privileged(),该函数是检查用户权限(root).第54行调用函数vsf_sysutil_map_anon_pages_init(),由于分析配置文件的过程中需要创建虚拟内存页,而且可能部分系统不支持MAP_ANON(创建匿名虚拟内存).对于不支持MAP_ANON的系统需要通过打开/dev/zero文件来为创建匿名虚拟内存页做好准备,这里我们只要了解该函数功能即可.以后我会对这部分进行详细描述.从58->71行便是分析配置文件的过程了.这里我们要着重描述作者对配置文件分析所采用的方法:

第61行调用vsf_sysutil_stat(p_config_name, &p_statbuf)函数,该函数调用stat系统函数得到配置文件(p_config_name)的stat结构信息.

第62行判断vsf_sysutil_stat(p_config_name, &p_statbuf)函数的返回值,如果正确,则在64行中调用函数vsf_parseconf_load_file(p_config_name, 1).该函数便是Vsftpd中分析配置文件的函数.该函数的实现在parseconf.c文件中.

1void
2vsf_parseconf_load_file(const char* p_filename, int errs_fatal)
3{
4  struct mystr config_file_str = INIT_MYSTR;
5  struct mystr config_setting_str = INIT_MYSTR;
6  struct mystr config_value_str = INIT_MYSTR;
7  unsigned int str_pos = 0;
8  int retval;
9  if (!p_filename)
10  {
11    p_filename = s_p_saved_filename;
12  }
13  else
14 {
15    if (s_p_saved_filename)
16    {
17      vsf_sysutil_free((char*)s_p_saved_filename);
18    }
19    s_p_saved_filename = vsf_sysutil_strdup(p_filename);
20  }
21  if (!p_filename)
22  {
23    bug("null filename in vsf_parseconf_load_file");
24  }
25  if (!s_strings_copied)
26  {
27    s_strings_copied = 1;
28    /* A minor hack to make sure all strings are malloc()'ed so we can free
29     * them at some later date. Specifically handles strings embedded in the
30     * binary.
31     */
32    copy_string_settings();
33  }
34  retval = str_fileread(&config_file_str, p_filename, VSFTP_CONF_FILE_MAX);
35  if (vsf_sysutil_retval_is_error(retval))
36  {
37    if (errs_fatal)
38    {
39      die2("cannot open config file:", p_filename);
40    }
41    else
42    {
43      return;
44    }
45  }
46  while (str_getline(&config_file_str, &config_setting_str, &str_pos))/*读取行记录(' ')*/
47  {
48    if (str_isempty(&config_setting_str) ||
49        str_get_char_at(&config_setting_str, 0) == '#')/*判断是否以#号开始*/
50    {
51      continue;
52    }
53    /* Split into name=value pair */
54    str_split_char(&config_setting_str, &config_value_str, '=');/*获取配置值*/
55    handle_config_setting(&config_setting_str, &config_value_str, errs_fatal);
56  }
57  str_free(&config_file_str);
58  str_free(&config_setting_str);
59  str_free(&config_value_str);
60}

该函数的第34行调用函数retval = str_fileread(&config_file_str, p_filename, VSFTP_CONF_FILE_MAX),该函数在filestr.c文件中实现,在此我就不贴出代码.这里简要说明该函数的功能:1>打开配置文件;2>根据返回的文件描述符调用fstat函数得到stat结构信息;3>判断是否为普通文件.4>如果是普通文件,则创建一个匿名的虚拟内存页(何为匿名虚拟内存页呢?匿名虚拟内存页是指创建的虚拟内存,并不映射到任何物理文件上).这里还需特别强调的是,作者在创建虚拟内存时,多申请两个虚拟内存页,这两个虚拟内存页一个作为第一页,一个作为最后一页,并且调用函数mprotect采取保护.5>匿名虚拟内存创建成功后,读取配置文件,建立配置文件和匿名虚拟内存的映射。结果在虚拟内存中形成这样的情景:保护页+配置文件映射+保护页.6>将虚拟内存中的内容作为一个字符串,并在内存中开辟空间存放。同时释放虚拟内存空间。

我们回到parseconf.c中,str_fileread函数调用完毕,接着第46行便调用函数str_getline(&config_file_str, &config_setting_str, &str_pos)对str_fileread函数中建立的字符串(内存)中循环读取行记录(根据' '判断).

第48行判断行记录是否为空,或者是否以'#'开头.

第54行调用函数str_split_char(&config_setting_str, &config_value_str, '=')获取配置值.

第54行调用函数handle_config_setting(&config_setting_str, &config_value_str, errs_fatal)处理配置选项和配置值.

第57行调用函数str_free(&config_file_str),释放字符串占用的内存.

至此,Vsftpd中便完成了配置文件的读取分析工作,总结这个过程如下:

1>.创建匿名虚拟内存(额外增加两页.第一页和最后一页采取保护机制)
2>.读取配置文件,建立文件和虚拟内存的映射。
3>.将虚拟内存中的内容作为一个字符串,并在内存中开辟空间存放。同时释放虚拟内存空间。
4>.通过读取这个内存空间,分析配置选项。
5>.分析完毕,释放内存空间。

这里我很纳闷,为什么要通过创建匿名虚拟内存中转一下呢?而不是直接开辟内存空间存放配置文件的内容呢?如果是考虑速度的原因,那为什么不直接对虚拟内存操作?为什么还采用页保护的机制?难道是出于安全方面的考虑吗?请各位高人指点,小弟在此先谢过.小弟联系方式:Emai:yeziyq@yahoo.com.cn  MSN:yeziyq1983@hotmail.com

今天看到了第103页:【上一篇】
今天的感受:【下一篇】
【相关文章】
  • The "format" Utility in the Solaris
  • 关于"幸福"的开发(搞笑版)
  • 今年"立春"的交节时间在当日7:25
  • [收藏]"Stay Hungry, Stay Foolish"
  • 举例说明在汇编语言中,"[]"的用法
  • [翻译] Effective C++, 3rd Edition, Item 45: 用 member function templates(成员函数模板) 接受 "...
  • "linux"发音,今天你发错了吗
  • 翻译:Effective C++, 3rd Edition, Item 45: 用 member function templates(成员函数模板) 接受 "a...
  • vsftpd源码"探究"<一>
  • vsftpd最简安装
  • 【随机文章】
  • 数据要求说明书(转载自国家计算机标准和文件模板)
  • 综合布线工程应注意的问题
  • adaptec 2944uw,adaptec 3944uw,sun x6541a
  • InstallShield脚本语言的编写
  • Authorware中播放MP3
  • 实时监测网络是否断线的几种办法(转coolend)
  • 合理设置IDE解决WinXP启动缓慢
  • 改进VB的驱动器列表框
  • 位图文件读写综述
  • VI 使用手册
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.