mod_linuxprivs.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:6k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD - FTP server daemon
  3.  * Copyright (c) 1997, 1998 Public Flood Software
  4.  *  
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  18.  */
  19. /*
  20.  * Optional module for Linux 2.1.104 and > ONLY.  Uses the new "capabilities"
  21.  * in 2.1 kernels which allow root to perform fine grained control
  22.  * over system calls which may be performed (essential making root
  23.  * "not-root" in terms of syscalls).  Excellent for security.  See
  24.  * README.linux-privs.  In order to use this module you'll _need_ a
  25.  * a 2.1 kernel.  A psuedo-port of libcap is included with proftpd
  26.  * in the contrib/libcap directory.  From the top-level directory
  27.  * run ./configure --with-modules=mod_linuxprivs
  28.  * This will automatically build libcap and link it to proftpd.
  29.  *
  30.  * This module effectively _completely_ gives up root, except for
  31.  * the bare minimum functionality that is required, after user
  32.  * authentication.  VERY highly recommended for security-consious admins.
  33.  *
  34.  * NOTE: Linux kernels 2.1 are _development_ kernels, and are likely
  35.  * to change over time.  As this happens, we'll try to keep this module
  36.  * up to date.  Additionally, libcap is a tad buggy and not completely
  37.  * standardized.  This should be solved be the time Linux 2.2 is released.
  38.  * In the interim, we've had to "work-around" a few bugs in libcap, which
  39.  * is why a separate static library is included.
  40.  *
  41.  * -- DO NOT MODIFY THE TWO LINES BELOW --
  42.  * $Libraries: -Lcontrib/libcap -lcap$
  43.  * $Directories: contrib/libcap$
  44.  * $Id: mod_linuxprivs.c,v 1.4 1999/09/30 05:54:30 macgyver Exp $
  45.  */
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #ifdef __powerpc__
  49. #define _LINUX_BYTEORDER_GENERIC_H
  50. #endif
  51. #include <linux/capability.h>
  52. #undef WNOHANG
  53. #undef WUNTRACED
  54. #include "conf.h"
  55. #include "privs.h"
  56. #include "../contrib/libcap/include/sys/capability.h"
  57. static cap_t capabilities = 0;
  58. static int use_capabilities = 1;
  59. /* log current capabilities */
  60. static void lp_debug()
  61. {
  62.   cap_t caps;
  63.   char *res;
  64.   ssize_t len;
  65.   caps = cap_get_proc();
  66.   if(!caps) {
  67.     log_pri(LOG_ERR,"module linuxprivs: cap_get_proc failed: %s",
  68.             strerror(errno));
  69.     return;
  70.   }
  71.   res = cap_to_text(caps,&len);
  72.   if(!res) {
  73.     log_pri(LOG_ERR,"module linuxprivs: cap_to_text failed: %s",
  74.             strerror(errno));
  75.     cap_free(&caps);
  76.     return;
  77.   }
  78.   log_debug(DEBUG1,"module linuxprivs: capabilities '%s'", res);
  79.   cap_free(&caps);
  80.   free(res);
  81. }
  82. /* create a new capability structure */
  83. static int lp_init_cap()
  84. {
  85.   if( !(capabilities = cap_init()) ) {
  86.     log_pri(LOG_ERR,"module linuxprivs: cap_init failed: %s",
  87.             strerror(errno));
  88.     return -1;
  89.   }
  90.   return 0;
  91. }
  92. /* free the capability structure */
  93. static void lp_free_cap()
  94. {
  95.   cap_free(&capabilities);
  96. }
  97. /* add a capability to a given set */
  98. static int lp_add_cap(cap_value_t cap, cap_flag_t set)
  99. {
  100.   if(cap_set_flag(capabilities, set, 1, &cap, CAP_SET) == -1) {
  101.     log_pri(LOG_ERR,"module linuxprivs: cap_set_flag failed: %s",
  102.                     strerror(errno));
  103.     return -1;
  104.   }
  105.   return 0;
  106. }
  107. /* send the capabilities to the kernel */
  108. static int lp_set_cap()
  109. {
  110.   if(cap_set_proc(capabilities) == -1) {
  111.     log_pri(LOG_ERR,"module linuxprivs: cap_set_proc failed: %s",
  112.                     strerror(errno));
  113.     return -1;
  114.   }
  115.   return 0;
  116. }
  117. /* The post cmd handler for "PASS" is only called after PASS has
  118.  * successfully completed, which means authentication is successful,
  119.  * so we can "tweak" our root access down to almost nothing.
  120.  */
  121. MODRET lowerprivs(cmd_rec *cmd)
  122. {
  123.   int ret;
  124.   if(!use_capabilities)
  125.     return DECLINED(cmd);
  126.   block_signals();
  127.   
  128.   /* glibc2.1 is BROKEN, seteuid() no longer lets one set euid to uid,
  129.    * so we can't use PRIVS_ROOT/PRIVS_RELINQUISH.  setreuid() is the
  130.    * workaround.
  131.    */
  132.   if(setreuid(session.uid,0) == -1) {
  133.     log_pri(LOG_ERR,"setreuid: %s",strerror(errno));
  134.     unblock_signals();
  135.     return DECLINED(cmd);
  136.   }
  137.   /* The only capability we need is CAP_NET_BIND_SERVICE (bind
  138.    * ports < 1024).  Everything else can be discarded.  We set this
  139.    * in CAP_PERMITTED set only, as when we switch away from root
  140.    * we lose CAP_EFFECTIVE anyhow, and must reset it.
  141.    */
  142.   ret = lp_init_cap();
  143.   if(ret != -1)
  144.     ret = lp_add_cap(CAP_NET_BIND_SERVICE,CAP_PERMITTED);
  145.   if(ret != -1)
  146.     ret = lp_set_cap();
  147.   if(setreuid(0,session.uid) == -1) {
  148.     log_pri(LOG_ERR,"setreuid: %s",strerror(errno));
  149.     unblock_signals();
  150.     end_login(1);
  151.   }
  152.   unblock_signals();
  153.   /* now our ownly capabilities consist of CAP_NET_BIND_SERVICE,
  154.    * however in order to actually be able to bind to low-numbered
  155.    * ports, we need the capability to be in the effective set.
  156.    */
  157.   if(ret != -1)
  158.     ret = lp_add_cap(CAP_NET_BIND_SERVICE,CAP_EFFECTIVE);
  159.   if(ret != -1)
  160.     ret = lp_set_cap();
  161.   if(capabilities)
  162.     lp_free_cap();
  163.   if(ret != -1) {
  164.     /* That's it!  Disable all further id switching */
  165.     session.disable_id_switching = TRUE;
  166.     lp_debug();
  167.   } else
  168.     log_pri(LOG_NOTICE,"attempt to configure capabilities failed, reverting to normal operation");
  169.   return DECLINED(cmd);
  170. }
  171. static int linuxprivs_init()
  172. {
  173.   /* Attempt to determine if we are running on a kernel that supports
  174.    * linuxprivs, this allows binary distributions to include the module
  175.    * even if it may not work.
  176.    */
  177.   if(!cap_get_proc() && errno == ENOSYS) {
  178. #if 0
  179.     log_debug(DEBUG1,"module linuxprivs: kernel does not support capabilities, disabling");
  180. #endif
  181.     use_capabilities = 0;
  182.   }
  183.   return 0;
  184. }  
  185. cmdtable linuxprivs_commands[] = {
  186.   { POST_CMD, C_PASS, G_NONE, lowerprivs, TRUE, FALSE },
  187.   { 0, NULL }
  188. };
  189. module linuxprivs_module = {
  190.   NULL, NULL, /* Always NULL */
  191.   0x20, /* API Version */
  192.   "linuxprivs", /* Module name */
  193.   NULL, /* No directive table */
  194.   linuxprivs_commands, /* Command handler table */
  195.   NULL, /* No auth table */
  196.   linuxprivs_init,NULL /* No child init */
  197. };