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