Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 74740 Details for
Bug 115082
app-shells/rssh possible local root vulnerability (v-s) (CVE-2005-3345)
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
rssh.patch
rssh.patch (text/plain), 65.88 KB, created by
Thierry Carrez (RETIRED)
on 2005-12-14 10:11:23 UTC
(
hide
)
Description:
rssh.patch
Filename:
MIME Type:
Creator:
Thierry Carrez (RETIRED)
Created:
2005-12-14 10:11:23 UTC
Size:
65.88 KB
patch
obsolete
>Index: CHROOT >=================================================================== >RCS file: /chest/cvsroot/rssh/CHROOT,v >retrieving revision 1.3 >diff -u -r1.3 CHROOT >--- CHROOT 5 Sep 2004 17:48:56 -0000 1.3 >+++ CHROOT 27 Nov 2005 19:20:42 -0000 >@@ -148,7 +148,8 @@ > /lib/libnss_files.so.? into the chroot jail. Without it, the scp command > failed, complaining that my user ID was an unknown user. If you use LDAP > authentication on the server, you will probably need to also copy >-libnss_ldap.so.? into your chroot jail. >+libnss_ldap.so.? into your chroot jail. Similar requirements likely exist for >+other authentication methods... > > > Logging >@@ -190,10 +191,10 @@ > Individual jails for different users > ------------------------------------ > >-In v2.1, you are now able to specify the location of different chroot jails >+Since v2.1, you are now able to specify the location of different chroot jails > for different users, whether or not to chroot individual users, etc. You > might be tempted to create individual jails for each different user, and you >-can do that, BUT... It's probably a bad idea. >+can do that, BUT... it's probably a very bad idea. > > There are several reasons for this. First, it uses lots of disk space, > because you need to copy the libraries and such into each one (though in some >@@ -203,11 +204,12 @@ > above) in each of the chroot jails. However, the number of sockets syslog can > listen to is generally limited. On most Linux systems, that limit is a > maximum of 20, though it can be changed by editing the source code to syslogd. >-So if you go with individual chroot jails, you either need to be satisfied >-without logging for most of your users, or recompile syslogd and manually >-configure it to open a socket in each of your users' jails. And while I >-haven't done it, I suspect creating large numbers of sockets for syslogd to >-listen to will make logging to syslog somewhat painful. >+On other platforms, this may not even be possible. So if you go with >+individual chroot jails, you either need to be satisfied without logging for >+most of your users, or recompile syslogd and manually configure it to open a >+socket in each of your users' jails. And while I haven't done it, I suspect >+creating large numbers of sockets for syslogd to listen to will make logging >+to syslog somewhat painful. > > My recommendation is, if you really really really need individual chroot > jails, use them. But if you can, configure a single jail where the majority >@@ -221,9 +223,9 @@ > > Setting up a proper chroot jail can be difficult, and it is always a very > environment-specific operation. Because of this, I can not and will not >-provide any sort of support for setting up chroot jails. However, in the near >-future, I will make sure there is a mailing list for rssh, where you can ask >-questions. >+provide any sort of support for setting up chroot jails. However, there is a >+mailing list for rssh, where you can ask questions. See the rssh homepage for >+details. > > If you are having problems, make sure that you have logging set up properly, > if nothing else. Doing so will help you determine what kind of problems you >Index: ChangeLog >=================================================================== >RCS file: /chest/cvsroot/rssh/ChangeLog,v >retrieving revision 1.6 >diff -u -r1.6 ChangeLog >--- ChangeLog 30 Dec 2004 20:58:09 -0000 1.6 >+++ ChangeLog 27 Nov 2005 19:23:09 -0000 >@@ -1,3 +1,11 @@ >+2.3.0 >+ >+ - modified chroot_helper to parse the config file, to avoid arbitrary >+ chroot() (and thus root compromise) >+ - numerous documentation updates >+ - fix for va_start()/va_end()-related segfault on 64-bit architecture >+ - small bit of code cleanup >+ > 2.2.3 > > - added checks for command execution arguments to scp, rdist, rsync >Index: Makefile.am >=================================================================== >RCS file: /chest/cvsroot/rssh/Makefile.am,v >retrieving revision 1.3 >diff -u -r1.3 Makefile.am >--- Makefile.am 19 Jun 2004 08:16:15 -0000 1.3 >+++ Makefile.am 27 Nov 2005 21:34:12 -0000 >@@ -6,7 +6,7 @@ > libexec_PROGRAMS = rssh_chroot_helper > nodist_rssh_SOURCES = main.c pathnames.h config.h > rssh_SOURCES = rssh.h rsshconf.h rsshconf.c log.c log.h util.c util.h argvec.c argvec.h >-rssh_chroot_helper_SOURCES = rssh_chroot_helper.c log.c log.h argvec.c argvec.h >+rssh_chroot_helper_SOURCES = rssh_chroot_helper.c log.c log.h argvec.c argvec.h util.c util.h rsshconf.c rsshconf.h rssh.h > dist_sysconf_DATA = rssh.conf > man_MANS = rssh.1 rssh.conf.5 > EXTRA_DIST = $(man_MANS) CHROOT SECURITY rssh.spec mkchroot.sh conf_convert.sh >@@ -16,3 +16,6 @@ > > install-exec-hook: > chmod u+s $(libexecdir)/rssh_chroot_helper >+ >+rpm: >+ rpmbuild -tb `echo @PACKAGE_STRING@.tar.gz|tr " " "-"` >Index: NEWS >=================================================================== >RCS file: /chest/cvsroot/rssh/NEWS,v >retrieving revision 1.1.1.1 >diff -u -r1.1.1.1 NEWS >--- NEWS 15 Mar 2004 21:01:37 -0000 1.1.1.1 >+++ NEWS 27 Nov 2005 19:23:54 -0000 >@@ -0,0 +1 @@ >+Automake's insistance on the existence of this file is very lame. >Index: SECURITY >=================================================================== >RCS file: /chest/cvsroot/rssh/SECURITY,v >retrieving revision 1.5 >diff -u -r1.5 SECURITY >--- SECURITY 22 Jan 2005 21:44:17 -0000 1.5 >+++ SECURITY 27 Nov 2005 20:18:28 -0000 >@@ -1,6 +1,27 @@ > SECURITY > -------- > >+Please note: The man page now has detailed information about security concerns >+and some tips for setting up rssh securely. If you haven't read these, please >+do so now. What follows is mostly a summary of specific security issues which >+have affected rssh since I started developing it. >+ >+Nov 27, 2005 >+ >+Max Vozeler reported a scary problem whereby rssh_chroot_helper can be >+exploited to chroot to arbitrary directories and thereby gain root access. >+The 2.3.0 release of rssh fixes this problem by forcing the chroot helper >+program to re-parse the config file instead of allowing the chroot home to be >+specified on the command line. Thus users not listed can not use it to chroot >+(or will chroot to the default location, which hopefully the sysadmin has set >+up securely), and users who are listed will be chrooted to the directories >+where they are supposed to go only. >+ >+Numerous people reported a problem with the way I used va_start/va_end in >+log.c which causes a segfault on 64-bit Linux platforms. I don't know if this >+is exploitable, but it's fixed. Given the previously mentioned root >+compromise, this probably doesn't matter much... ;-) >+ > Dec 3, 2004 > > Jason Wies has reported a problem whereby rssh can be bypassed in conjunction >Index: aclocal.m4 >=================================================================== >RCS file: /chest/cvsroot/rssh/aclocal.m4,v >retrieving revision 1.2 >diff -u -r1.2 aclocal.m4 >--- aclocal.m4 5 Sep 2004 17:48:56 -0000 1.2 >+++ aclocal.m4 27 Nov 2005 17:58:56 -0000 >@@ -1,4 +1,4 @@ >-# generated automatically by aclocal 1.8.3 -*- Autoconf -*- >+# generated automatically by aclocal 1.9.2 -*- Autoconf -*- > > # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 > # Free Software Foundation, Inc. >@@ -33,14 +33,14 @@ > # ---------------------------- > # Automake X.Y traces this macro to ensure aclocal.m4 has been > # generated from the m4 files accompanying Automake X.Y. >-AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.8"]) >+AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) > > # AM_SET_CURRENT_AUTOMAKE_VERSION > # ------------------------------- > # Call AM_AUTOMAKE_VERSION so it can be traced. > # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. > AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], >- [AM_AUTOMAKE_VERSION([1.8.3])]) >+ [AM_AUTOMAKE_VERSION([1.9.2])]) > > # AM_AUX_DIR_EXPAND > >@@ -108,7 +108,7 @@ > > # AM_CONDITIONAL -*- Autoconf -*- > >-# Copyright (C) 1997, 2000, 2001, 2003 Free Software Foundation, Inc. >+# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. > > # 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 >@@ -145,8 +145,8 @@ > fi > AC_CONFIG_COMMANDS_PRE( > [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then >- AC_MSG_ERROR([conditional "$1" was never defined. >-Usually this means the macro was only invoked conditionally.]) >+ AC_MSG_ERROR([[conditional "$1" was never defined. >+Usually this means the macro was only invoked conditionally.]]) > fi])]) > > # serial 7 -*- Autoconf -*- >@@ -266,9 +266,14 @@ > grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && > ${MAKE-make} -s -f confmf > /dev/null 2>&1; then > # icc doesn't choke on unknown options, it will just issue warnings >- # (even with -Werror). So we grep stderr for any message >- # that says an option was ignored. >- if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else >+ # or remarks (even with -Werror). So we grep stderr for any message >+ # that says an option was ignored or not supported. >+ # When given -MP, icc 7.0 and 7.1 complain thusly: >+ # icc: Command line warning: ignoring option '-M'; no argument required >+ # The diagnosis changed in icc 8.0: >+ # icc: Command line remark: option '-MP' not supported >+ if (grep 'ignoring option' conftest.err || >+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else > am_cv_$1_dependencies_compiler_type=$depmode > break > fi >@@ -314,7 +319,8 @@ > > # Generate code to set up dependency tracking. -*- Autoconf -*- > >-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. >+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 >+# Free Software Foundation, Inc. > > # 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 >@@ -350,27 +356,21 @@ > else > continue > fi >- grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue >- # Extract the definition of DEP_FILES from the Makefile without >- # running `make'. >+ # Extract the definition of DEPDIR, am__include, and am__quote >+ # from the Makefile without running `make'. > DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` > test -z "$DEPDIR" && continue >+ am__include=`sed -n 's/^am__include = //p' < "$mf"` >+ test -z "am__include" && continue >+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"` > # When using ansi2knr, U may be empty or an underscore; expand it > U=`sed -n 's/^U = //p' < "$mf"` >- test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" >- # We invoke sed twice because it is the simplest approach to >- # changing $(DEPDIR) to its actual value in the expansion. >- for file in `sed -n ' >- /^DEP_FILES = .*\\\\$/ { >- s/^DEP_FILES = // >- :loop >- s/\\\\$// >- p >- n >- /\\\\$/ b loop >- p >- } >- /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ >+ # Find all dependency output files, they are included files with >+ # $(DEPDIR) in their names. We invoke sed twice because it is the >+ # simplest approach to changing $(DEPDIR) to its actual value in the >+ # expansion. >+ for file in `sed -n " >+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ > sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do > # Make sure the directory exists. > test -f "$dirpart/$file" && continue >@@ -425,7 +425,7 @@ > # This macro actually does too much some checks are only needed if > # your package does certain things. But this isn't really a big deal. > >-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 >+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 > # Free Software Foundation, Inc. > > # This program is free software; you can redistribute it and/or modify >@@ -501,7 +501,6 @@ > AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) > AM_MISSING_PROG(AUTOHEADER, autoheader) > AM_MISSING_PROG(MAKEINFO, makeinfo) >-AM_MISSING_PROG(AMTAR, tar) > AM_PROG_INSTALL_SH > AM_PROG_INSTALL_STRIP > AC_REQUIRE([AM_PROG_MKDIR_P])dnl >@@ -510,7 +509,9 @@ > AC_REQUIRE([AC_PROG_AWK])dnl > AC_REQUIRE([AC_PROG_MAKE_SET])dnl > AC_REQUIRE([AM_SET_LEADING_DOT])dnl >- >+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], >+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], >+ [_AM_PROG_TAR([v7])])]) > _AM_IF_OPTION([no-dependencies],, > [AC_PROVIDE_IFELSE([AC_PROG_CC], > [_AM_DEPENDENCIES(CC)], >@@ -753,13 +754,21 @@ > # this.) > AC_DEFUN([AM_PROG_MKDIR_P], > [if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then >- # Keeping the `.' argument allows $(mkdir_p) to be used without >- # argument. Indeed, we sometimes output rules like >+ # We used to keeping the `.' as first argument, in order to >+ # allow $(mkdir_p) to be used without argument. As in > # $(mkdir_p) $(somedir) >- # where $(somedir) is conditionally defined. >- # (`test -n '$(somedir)' && $(mkdir_p) $(somedir)' is a more >- # expensive solution, as it forces Make to start a sub-shell.) >- mkdir_p='mkdir -p -- .' >+ # where $(somedir) is conditionally defined. However this is wrong >+ # for two reasons: >+ # 1. if the package is installed by a user who cannot write `.' >+ # make install will fail, >+ # 2. the above comment should most certainly read >+ # $(mkdir_p) $(DESTDIR)$(somedir) >+ # so it does not work when $(somedir) is undefined and >+ # $(DESTDIR) is not. >+ # To support the latter case, we have to write >+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), >+ # so the `.' trick is pointless. >+ mkdir_p='mkdir -p --' > else > # On NextStep and OpenStep, the `mkdir' command does not > # recognize any option. It will interpret all options as >@@ -925,3 +934,111 @@ > INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" > AC_SUBST([INSTALL_STRIP_PROGRAM])]) > >+# Check how to create a tarball. -*- Autoconf -*- >+ >+# Copyright (C) 2004 Free Software Foundation, Inc. >+ >+# 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, 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. >+ >+# serial 1 >+ >+ >+# _AM_PROG_TAR(FORMAT) >+# -------------------- >+# Check how to create a tarball in format FORMAT. >+# FORMAT should be one of `v7', `ustar', or `pax'. >+# >+# Substitute a variable $(am__tar) that is a command >+# writing to stdout a FORMAT-tarball containing the directory >+# $tardir. >+# tardir=directory && $(am__tar) > result.tar >+# >+# Substitute a variable $(am__untar) that extract such >+# a tarball read from stdin. >+# $(am__untar) < result.tar >+AC_DEFUN([_AM_PROG_TAR], >+[# Always define AMTAR for backward compatibility. >+AM_MISSING_PROG([AMTAR], [tar]) >+m4_if([$1], [v7], >+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], >+ [m4_case([$1], [ustar],, [pax],, >+ [m4_fatal([Unknown tar format])]) >+AC_MSG_CHECKING([how to create a $1 tar archive]) >+# Loop over all known methods to create a tar archive until one works. >+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' >+_am_tools=${am_cv_prog_tar_$1-$_am_tools} >+# Do not fold the above two line into one, because Tru64 sh and >+# Solaris sh will not grok spaces in the rhs of `-'. >+for _am_tool in $_am_tools >+do >+ case $_am_tool in >+ gnutar) >+ for _am_tar in tar gnutar gtar; >+ do >+ AM_RUN_LOG([$_am_tar --version]) && break >+ done >+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' >+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' >+ am__untar="$_am_tar -xf -" >+ ;; >+ plaintar) >+ # Must skip GNU tar: if it does not support --format= it doesn't create >+ # ustar tarball either. >+ (tar --version) >/dev/null 2>&1 && continue >+ am__tar='tar chf - "$$tardir"' >+ am__tar_='tar chf - "$tardir"' >+ am__untar='tar xf -' >+ ;; >+ pax) >+ am__tar='pax -L -x $1 -w "$$tardir"' >+ am__tar_='pax -L -x $1 -w "$tardir"' >+ am__untar='pax -r' >+ ;; >+ cpio) >+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L' >+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L' >+ am__untar='cpio -i -H $1 -d' >+ ;; >+ none) >+ am__tar=false >+ am__tar_=false >+ am__untar=false >+ ;; >+ esac >+ >+ # If the value was cached, stop now. We just wanted to have am__tar >+ # and am__untar set. >+ test -n "${am_cv_prog_tar_$1}" && break >+ >+ # tar/untar a dummy directory, and stop if the command works >+ rm -rf conftest.dir >+ mkdir conftest.dir >+ echo GrepMe > conftest.dir/file >+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) >+ rm -rf conftest.dir >+ if test -s conftest.tar; then >+ AM_RUN_LOG([$am__untar <conftest.tar]) >+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break >+ fi >+done >+rm -rf conftest.dir >+ >+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) >+AC_MSG_RESULT([$am_cv_prog_tar_$1])]) >+AC_SUBST([am__tar]) >+AC_SUBST([am__untar]) >+]) # _AM_PROG_TAR >+ >Index: configure.ac >=================================================================== >RCS file: /chest/cvsroot/rssh/configure.ac,v >retrieving revision 1.5 >diff -u -r1.5 configure.ac >--- configure.ac 30 Dec 2004 20:58:09 -0000 1.5 >+++ configure.ac 27 Nov 2005 17:16:33 -0000 >@@ -1,5 +1,5 @@ > # Process this file with autoconf to produce a configure script. >-AC_INIT(rssh, 2.2.3, [rssh-discuss at lists dot sourceforge dot net]) >+AC_INIT(rssh, 2.3.0, [rssh-discuss at lists dot sourceforge dot net]) > AM_INIT_AUTOMAKE > AC_CONFIG_SRCDIR([rssh.1]) > AM_CONFIG_HEADER([config.h]) >Index: log.c >=================================================================== >RCS file: /chest/cvsroot/rssh/log.c,v >retrieving revision 1.2 >diff -u -r1.2 log.c >--- log.c 10 Oct 2004 16:59:46 -0000 1.2 >+++ log.c 19 Nov 2005 16:10:12 -0000 >@@ -156,6 +156,7 @@ > /* try to print msg to buffer, until we succeed or fail conclusively */ > va_start( arglist, msg ); > retc = vsnprintf( format_temp, length, msg, arglist ); >+ va_end( arglist ); > > /* > * Check retc to make sure it fit account for differences in libc >@@ -171,7 +172,9 @@ > "Could not allocate mem in log_msg(), log.c"); > exit(1); > } >+ va_start( arglist, msg ); > vsnprintf( format_temp, retc + 1, msg, arglist ); >+ va_end( arglist ); > } > /* if retc == -1, we must be compiled under pre-C99 libc */ > while ( retc == -1 ){ >@@ -183,11 +186,10 @@ > exit(1); > } > memset( format_temp, 0, length ); >+ va_start( arglist, msg ); > retc = vsnprintf( format_temp, length, msg, arglist ); >+ va_end( arglist ); > } >- >- /* clean up arglist and log the string */ >- va_end( arglist ); > syslog((facility | level), "%s", format_temp); > } > >Index: main.c.in >=================================================================== >RCS file: /chest/cvsroot/rssh/main.c.in,v >retrieving revision 1.6 >diff -u -r1.6 main.c.in >--- main.c.in 30 Dec 2004 20:58:09 -0000 1.6 >+++ main.c.in 27 Nov 2005 22:36:19 -0000 >@@ -82,7 +82,7 @@ > char *progname; > char *username; > char *version = "@PACKAGE_STRING@"; >-char *copyr = "Copyright 2002-4 Derek D. Martin <@PACKAGE_BUGREPORT@>"; >+char *copyr = "Copyright 2002-5 Derek D. Martin <@PACKAGE_BUGREPORT@>"; > > /* MAIN PROGRAM */ > int main( int argc, char **argv ) >@@ -116,7 +116,7 @@ > log_open(); > > /* process the config file */ >- if ( !(read_shell_config(&opts, PATH_RSSH_CONFIG)) ){ >+ if ( !(read_shell_config(&opts, PATH_RSSH_CONFIG, 1)) ){ > log_set_priority(LOG_ERR); > log_msg("there were errors processing configuration file!"); > } >@@ -188,7 +188,6 @@ > /* if we need to do chroot processing, do it */ > if ( opts->shell_flags & RSSH_USE_CHROOT ){ > /* create vector of pointers to command line arguments */ >- root = opts->chroot_path; > > /* > * we don't call build_arg_vector() here, because expanding >@@ -205,30 +204,26 @@ > } > > argvec[0] = PATH_CHROOT_HELPER; >- argvec[1] = root; > > /* which one is it? */ > if ( !(strcmp(*cmd, PATH_SCP)) ) >- argvec[2] = "1"; >+ argvec[1] = "1"; > else if ( !(strcmp(*cmd, PATH_SFTP_SERVER)) ) >- argvec[2] = "2"; >+ argvec[1] = "2"; > else if ( !(strcmp(*cmd, PATH_CVS)) ) >- argvec[2] = "3"; >+ argvec[1] = "3"; > else if ( !(strcmp(*cmd, PATH_RDIST)) ) >- argvec[2] = "4"; >+ argvec[1] = "4"; > else if ( !(strcmp(*cmd, PATH_RSYNC)) ) >- argvec[2] = "5"; >+ argvec[1] = "5"; > else { > log_set_priority(LOG_ERR); > log_msg("fatal error identifying the correct command " > "(this should never happen)"); > exit(1); > } >- if ( !(homedir = extract_root(root, uinfo.pw_dir)) ) >- homedir = strdup("/"); >- argvec[3] = homedir; >- argvec[4] = cmdline; >- argvec[5] = NULL; >+ argvec[2] = cmdline; >+ argvec[3] = NULL; > > /* change the command to run to the chroot helper */ > *cmd = PATH_CHROOT_HELPER; >@@ -243,11 +238,9 @@ > } > > /* stuff the args into the buffer */ >- snprintf(temp, len, "%s \"%s\" %s \"%s\" %s", >+ snprintf(temp, len, "%s %s \"%s\"", > PATH_CHROOT_HELPER, >- root, >- argvec[2], >- homedir, >+ argvec[1], > cmdline); > > /* now log 'em */ >Index: rssh.1 >=================================================================== >RCS file: /chest/cvsroot/rssh/rssh.1,v >retrieving revision 1.3 >diff -u -r1.3 rssh.1 >--- rssh.1 30 Dec 2004 20:58:09 -0000 1.3 >+++ rssh.1 27 Nov 2005 21:18:49 -0000 >@@ -1,21 +1,21 @@ > .\" No comment! > .\" >-.TH RSSH 1 "7 Jul 2003" "man pages" "Derek D. Martin" >+.TH RSSH 1 "27 Nov 2005" "man pages" "Derek D. Martin" > .SH NAME > rssh \- restricted secure shell allowing only scp and/or sftp > .SH SYNOPSIS > .B rssh >-.I -c scp|sftp-server > .RI [ " options... " ] " " [ " ... " ] > .br >+.B rssh -v > .SH DESCRIPTION > .B rssh >-is a restricted shell for providing limited access to a host via \fIssh\fP(1), >+is a restricted shell for providing limited access to a host via \fBssh\fP(1), > allowing a user whose shell is configured to > .B rssh >-to use one or more of the command(s) \fIscp\fP(1) or \fIsftp\fP(1) >-\fIcvs\fP(1), \fIrdist\fP(1), and \fIrsync\fP(1), and >-.B only >+to use one or more of the command(s) \fBscp\fP(1), \fBsftp\fP(1) >+\fBcvs\fP(1), \fBrdist\fP(1), and \fBrsync\fP(1), and >+.I only > those commands. It is intended primarily to work with OpenSSH (see > http://www.openssh.com), but may work with other implementations. > .P >@@ -29,15 +29,15 @@ > .RE > .P > If invoked with the >-.I -v >+.B -v > option, > .B rssh > will report its version, and exit. All other arguments to > .B rssh >-are those specified by the remote \fIssh\fP(1) client, and aren't of much >+are those specified by the remote \fBssh\fP(1) client, and aren't of much > concern to the average user. The arguments provided must be what a shell on >-the remote end would receive in order to pass control to \fIscp\fP(1) or >-\fIsftp\fP(1). If >+the remote end would receive in order to pass control to \fBscp\fP(1), >+\fBsftp\fP(1), etc. If > .B rssh > receives arguments which do not conform, it will emit an error message and exit. > If the program the user is trying to run is not allowed, or contains syntax >@@ -45,62 +45,93 @@ > will also emit an error and exit. > .P > .B rssh >-has a configuration file, rssh.conf(5), which allows some of the behavior of >+has a configuration file, \fIrssh.conf\fP(5), which allows some of the >+behavior of > .B rssh > to be customized. See that man page for details. >- > .SH SECURITY NOTES >+.I Read this section with exceptional care, or you may put your system at risk! >+.SS Using rssh With CVS >+If you are using \fBrssh\fP to allow CVS access, it should be noted that it is >+not possible to prevent a user who is very familiar with CVS from bypassing >+\fBrssh\fP and getting a shell, unless the user does not have write access in >+the repository. Obviously, the user must have write access to the repository >+in order to update it, which allows them to upload arbitrary programs into the >+repository. CVS provides several mechanisms for executing such arbitrary >+programs... The only reasonably safe way to use \fBrssh\fP with CVS is to use >+the chroot jail facilities to place the CVS repository within a chroot jail. >+Please see below and all relevant documentation for details of how to set up >+chroot jails. Note that \fIusers will still be able to get shell access >+within the jail\fP; the only protection which is provided is that they can not >+escape the jail. I have been pursuaded to retain support for CVS because this >+protection is better than no protection. >+.I You have been warned. Use CVS at your own risk. >+.SS Potential root Compromise With Old Versions > >-.SS Command Line Parser >- >-As of >+Before \fBrssh 2.3.0\fP, if a regular user had shell access to a machine where > .B rssh >-version 2.2.3, the program must parse out the complete command line to avoid >-command line options which cause the execution of arbitrary programs (and >-hence bypass the security of \fBrssh\fP). In order to keep the program source >-code sane, the parser is a little over-zealous about matching command line >-options. In practice, this probably will not be an issue, but in theory it is >-possible. >-.P >-If you run into a problem where >-.B rssh >-refuses to run, claiming to be rejecting insecure command line options which >-were not specified, try changing your command line such that all \fIshort\fP >-options are specified as single-letter option flags (e.g. -e -p instead of >--ep) and make sure you separate arguments from their respective options by a >-space (e.g. -p 123 instead of -p123). In virtually all cases, this should >-solve the problem. Admittedly, an exhaustive search was not performed, but no >-problematical cases were found which were likely to be common. >-.P >-The alternative would have been to include a complete command-line parser for >-rcp, rdist, and rsync; this was way out of the scope of this project. In >-practice, the existing parser should suffice. If, however, you find cases >-where it does not, please post details to the rssh mailing list. Details >-about how to post to the mailing list can be found at the rssh homepage. >+was installed, a root compromise was possible due to >+.B rssh_chroot_helper >+allowing a user to arbitrarily \fBchroot\fP(2) to anywhere on the filesystem. >+It is possible to mitigate this attack against affected versions of >+.B rssh >+using strict access controls to files, by making sure that the user can not >+write to any file on the same partition as system executables, and that any >+partition where they can write files does not allow execution of SUID >+programs. As of \fBrssh 2.3.0\fP, this attack has been prevented by >+preventing arbitrary chroot(), \fIif your jail is set up securely\fP. In >+particular, make sure that regular users can not write to directories inside >+the jail which contain the copied binaries. That should be obvious, but it >+needs to be said. Though it should not be strictly necessary, to further >+protect your system from possible compromise, it is also advisable to follow >+the section below, entitled "Safeguards Against Bypassing rssh". > .SS Safeguards Against Bypassing rssh >- > .B rssh > is designed to interact with several other programs. Even if rssh is >-completely bug-free, changes in those other programs could possibly result in methods >-to circumvent the protection that >+completely bug-free, changes in those other programs could possibly result in >+methods to circumvent the protection that > .B rssh >-is intended to provide. \fBIt is important for you, the system administrator, >+is intended to provide. \fIIt is important for you, the system administrator, > to stay current on the services you make available with rssh, to be sure that >-these commands do\fP \fInot\fP \fBprovide mechanisms to allow the user to run >-arbitrary commands.\fP Also, while the goal of every release is to be bug >-free, no one is perfect... There may be undiscovered bugs in >+these commands do not provide mechanisms to allow the user to run arbitrary >+commands.\fP Also, while the goal of every release is to be bug free, no one >+is perfect... There may be undiscovered bugs in > .B rssh > which might allow a user to circumvent it. > .P > You can protect your system from those who would take advantage of such >-weaknesses. There are three basic steps: >- >-.nf >- 1. place your users in a chroot jail >- 2. mount their home filesystem with the noexec option >- 3. use standard file permissions appropriately >-.fi >- >+weaknesses. This is not required for \fBrssh\fP to work properly, but it is a >+really good idea. There are six basic steps: >+.RS >+.TP >+1. >+protect all non-administrator accounts with rssh (i.e. no regular user should have shell access to the server) >+.TP >+2. >+place your users in a chroot jail >+.TP >+3. >+limit the binaries which live in the jail to the absolute minimum required >+.TP >+4. >+mount their home filesystem with the noexec/nosuid option (i.e. use >+separate partitions in the jail for user home directories and all other files, >+if possible/reasonable) >+.TP >+5. >+create a group for rssh users, and limit executable access to the binaries to >+users in that group. >+.TP >+6. >+use standard file permissions carefully and appropriately >+.RE >+.P >+If possible, make sure that no regular user has any kind of shell access to >+the system other than through \fBrssh\fP. Otherwise, users with shell access >+could potentially exploit undiscovered bugs in >+.B rssh_chroot_helper >+to gain root access to the server. >+.P > .B rssh > gives the system administrator the ability to place the users in a chroot > jail. See details in the man page for >@@ -113,31 +144,78 @@ > are trying to provide. This prevents them from running standard system > commands. > .P >-Then, make sure the user's files are on a seperate filesystem from your >-system's executables. Make sure you mount this filesystem using the >-.I noexec >-option, if your operating system provides one. This prevents the users from >+Then, make sure the user's files inside the jail are on a seperate filesystem >+from your system's executables. If possible in your environment, make sure >+you mount this filesystem using the >+.IR noexec " and " nosuid >+options, if your operating system provides them. This prevents the users from > being able to execute programs which they have uploaded to the target machine >-(e.g. using scp) which might otherwise be executable. >+(e.g. using scp) which might otherwise be executable, and prevents SUID >+programs from respecting the SUID bits. Note that these options necessitate >+the users' files are on separate partitions from the binaries and libraries >+that live in the jail. Therefore you will need at least 2 partitions for your >+jail to do this properly (one for the system binaries in the jail, the other >+for the user directories). >+.P >+Additionally, create a group, for example "rsshuser", for rssh users. Put all >+your users who will be restricted by rssh in that group. Set the ownership >+and permissions on rssh and rssh_chroot_helper so that only those users can >+execute them. The following commands should illustrate: >+.P >+.RS >+.B # groupadd rsshuser >+.br >+.B # chown root:rsshuser rssh rssh_chroot_helper >+.br >+.B # chmod 550 rssh >+.br >+.B # chmod 4550 rssh_chroot_helper >+.br >+.RE > .P > Lastly, use standard Unix/POSIX file permissions to ensure they > can not access files they should not be able to within the chroot jail. >+.SS Command Line Parser >+As of >+.B rssh >+version 2.2.3, the program must parse out the complete command line to avoid >+command line options which cause the execution of arbitrary programs (and >+hence bypass the security of \fBrssh\fP). In order to keep the program source >+code sane, the parser is a little over-zealous about matching command line >+options. In practice, this probably will not be an issue, but in theory it is >+possible. >+.P >+If you run into a problem where >+.B rssh >+refuses to run, claiming to be rejecting insecure command line options which >+were not specified, try changing your command line such that all \fIshort\fP >+options are specified as single-letter option flags (e.g. -e -p instead of >+-ep) and make sure you separate arguments from their respective options by a >+space (e.g. -p 123 instead of -p123). In virtually all cases, this should >+solve the problem. Admittedly, an exhaustive search was not performed, but no >+problematical cases were found which were likely to be common. >+.P >+The alternative would have been to include a complete command-line parser for >+rcp, rdist, and rsync; this was way out of the scope of this project. In >+practice, the existing parser should suffice. If, however, you find cases >+where it does not, please post details to the rssh mailing list. Details >+about how to post to the mailing list can be found at the rssh homepage. > .SS "OpenSSH Versions and Bypassing rssh" >-Prior to OpenSSH 3.5, \fIsshd\fP(8) will generally attempt to parse files in >+Prior to OpenSSH 3.5, \fBsshd\fP(8) will generally attempt to parse files in > the user's home directory, and may also try to run a start-up script from the > user's > .I $HOME/.ssh > directory. > .B rssh > does not make use of the user's environment in any way. The relevant command >-is executed by calling \fIexecv\fP(3) with the full path to the command, as >+is executed by calling \fBexecv\fP(3) with the full path to the command, as > specified at compile time. It does not depend upon the user's PATH variable, > or on any other environment variable. > .P > There are, however, several problems that can arise. This is due entirely to > the way the OpenSSH Project's sshd works, and is in no way the fault of > \fBrssh\fP. For example, one problem which might exist is that, according to >-the \fIsshd\fP(8) man page from at least some releases of OpenSSH, the >+the \fBsshd\fP(8) man page from at least some releases of OpenSSH, the > commands listed in the > .I $HOME/.ssh/rc > file are executed with >@@ -161,7 +239,7 @@ > .I is > vulnerable to this attack, there is a workaround for this problem, though it > is pretty restrictive. >-.B "The user's home directory absolutely must *not* be writable by the user." >+.I "The user's home directory absolutely must not be writable by the user." > If it is, the user can use sftp to remove the directory or rename it, and then > create a new one, and fill it up with whatever environment files they like. For > providing file uploads, this means a user-writable directory must be created for >@@ -193,7 +271,41 @@ > and disable the default of static compilation. > .SH BUGS > None. =8^) >+.SS A Note About Getting Help >+If you are having trouble getting >+.B rssh >+working, or you think you've found a bug, please use the mailing list, and >+.I do not e-mail me >+\fIdirectly\fP. >+You must sign up for the list in order to post. Information about how to sign >+up is available on the rssh homepage. If you mail me directly with questions, >+I will almost certainly ignore you, or at the very least ask you to repost >+your question on the mailing list. Please also feel free to provide feedback >+about rssh on the mailing list, whether positive or negative (especially >+negative). >+.SS Security Problems >+The only exception to the above is if you believe you have found a security >+problem with \fBrssh\fP. If that is the case, then please \fIdo\fP contact me >+privately. If you are unable to find my direct contact info, post a message on >+the mailing list requesting that I contact you about a potential security >+problem. Security problems should be dealt with privately, so that the threat >+can be properly assessed, and so as not to needlessly endanger the >+installations of \fBrssh\fP in production environments. I take security >+problems seriously, and will work to resolve them as quickly as possible. >+.SS N.B.: >+Before you e-mail me (or the mailing list) with questions, be sure to >+.I THOROUGHLY >+read all of the following files: README, INSTALL, CHROOT, SECURITY. All of >+these files are distributed with the rssh source code, as well as all binary >+packages of \fBrssh\fP. If you downloaded a binary package, these files >+should be located wherever your distribution keeps its documentation files >+(usually /usr/share/doc/rssh-version/ or something similar). Also >+.I THOROUGHLY >+read the man pages for \fBrssh\fP(1), and \fBrssh.conf\fP(5). Finally, if you >+are still having problems, read the FAQ at >+http://www.pizzashack.org/rssh/faq.shtml. If it is clear to me that you have >+not read these documents, I will ignore you. In most cases, these documents >+will already have everything you need to get rssh working, and I won't be able >+to explain it any better on a mailing list than I did in those documents... > .SH SEE ALSO >-\fIrssh.conf\fP(5), \fIsshd\fP(8), \fIssh\fP(1), \fIscp\fP(1), \fIsftp\fP(1). >- >- >+\fBrssh.conf\fP(5), \fBsshd\fP(8), \fBssh\fP(1), \fBscp\fP(1), \fBsftp\fP(1). >Index: rssh.conf >=================================================================== >RCS file: /chest/cvsroot/rssh/rssh.conf,v >retrieving revision 1.3 >diff -u -r1.3 rssh.conf >--- rssh.conf 19 Jun 2004 08:16:15 -0000 1.3 >+++ rssh.conf 27 Nov 2005 21:28:36 -0000 >@@ -19,10 +19,11 @@ > # the chroot jail will be located. > # > # if you DO NOT want to chroot users, LEAVE THIS COMMENTED OUT. >-# You can quote anywhere, but quotes not required unless path contains a >-# space... as in this example. >+# chrootpath = /usr/local/chroot > >-#chrootpath = "/usr/local/chroot dir" >+# You can quote anywhere, but quotes not required unless the path contains a >+# space... as in this example. >+#chrootpath = "/usr/local/my chroot" > > ########################################## > # EXAMPLES of configuring per-user options >@@ -30,10 +31,6 @@ > #user=rudy:077:00010: # the path can simply be left out to not chroot > #user=rudy:077:00010 # the ending colon is optional > >-#spaces in the path must be quoted... >-#user=rudy:011:00001:"/usr/local/chroot dir" # scp with chroot >-#user=rudy:011:00010:"/usr/local/chroot dir" # sftp with chroot >-#user=rudy:011:00011:"/usr/local/chroot dir" # both with chroot > #user=rudy:011:00100: # cvs, with no chroot > #user=rudy:011:01000: # rdist, with no chroot > #user=rudy:011:10000: # rsync, with no chroot >@@ -41,8 +38,14 @@ > #user=rudy:01"1:00001:/usr/local/chroot" # or somewhere in the middle, freak! > #user=rudy:'011:00001:/usr/local/chroot' # single quotes too > >+# if your chroot_path contains spaces, it must be quoted... >+# In the following examples, the chroot_path is "/usr/local/my chroot" >+#user=rudy:011:00001:"/usr/local/my chroot" # scp with chroot >+#user=rudy:011:00010:"/usr/local/my chroot" # sftp with chroot >+#user=rudy:011:00011:"/usr/local/my chroot" # both with chroot >+ > # Spaces before or after the '=' are fine, but spaces in chrootpath need > # quotes. >-#user = "rudy:011:00001:/usr/local/chroot dir" >-#user = "rudy:011:00001:/usr/local/chroot dir" # neither do comments at line end >+#user = "rudy:011:00001:/usr/local/my chroot" >+#user = "rudy:011:00001:/usr/local/my chroot" # neither do comments at line end > >Index: rssh.conf.5.in >=================================================================== >RCS file: /chest/cvsroot/rssh/rssh.conf.5.in,v >retrieving revision 1.2 >diff -u -r1.2 rssh.conf.5.in >--- rssh.conf.5.in 20 Mar 2004 03:00:12 -0000 1.2 >+++ rssh.conf.5.in 28 Nov 2005 16:54:56 -0000 >@@ -78,7 +78,8 @@ > Causes \fBrssh\fP (actually a helper program) to call the > .I chroot() > system call, changing the root of the file system to whatever directory is >-specified. For example: >+specified. Note that the value on the right hand side of the equal sign is >+the name of a directory, not a command. For example: > .P > chrootpath=/usr/chroot > .P >@@ -89,15 +90,24 @@ > distribution for hints about how to do this. See also the \fIchroot\fP(2) man > page. > .P >-If the user's home directory (as specified in /etc/password) is underneath the >-path specified by this keyword, then the user will be chdir'd into their home >-directory. If it is not, then they will be chdir'd to the root of the chroot >-jail. >+If the user's home directory (as specified in \fI/etc/passwd\fP) is underneath >+the path specified by this keyword, then the user will be chdir'd into their >+home directory. If it is not, then they will be chdir'd to the root of the >+chroot jail. >+.P >+In other words, if the jail is \fI/chroot\fP, and your user's home directory >+is \fI/chroot/home/user\fP, then once \fBrssh_chroot_helper\fP changes the >+root of the system, it will cd into \fI/home/user\fP inside the jail. >+However, if your user's home directory is given as \fI/home/user\fP in >+\fI/etc/passwd\fP, then even if that directory exists in the jail, the chroot >+helper will not try to cd there. The user's normal home directory must live >+inside the jail for this to work. > .RE >+.P > .B user > .RS > The user keyword allows for the configuration of options on a per-user basis. >-.B THIS KEYWORD OVERRIDES ALL OTHER KEYWORDS FOR THE SPECIFIED USER. >+.I THIS KEYWORD OVERRIDES ALL OTHER KEYWORDS FOR THE SPECIFIED USER. > That is, if you use a user keyword for user foo, then foo will use only the > settings in that user line, and not any of the settings set with the keywords > above. The user keyword's argument consists of a group of fields separated by >@@ -119,7 +129,9 @@ > .RE > .B path > .RS >-The path to which this user should be chrooted >+The \fIdirectory\fP to which this user should be chrooted (this is not a >+command, it is a directory name). See \fBchroot_path\fP above for complete >+details. > .RE > .P > For example, you might have something like this: >@@ -131,7 +143,7 @@ > specified, the user will > .I not > be chrooted, >-.B regardless of default options set with the keywords above. >+.I regardless of default options set with the keywords above. > If you wanted this user to be chrooted, you would need to specify the chroot > path explicitly, even if it should be the same as that set using the > chrootpath keyword. Remember that if there are spaces in the path, you need >Index: rssh_chroot_helper.c >=================================================================== >RCS file: /chest/cvsroot/rssh/rssh_chroot_helper.c,v >retrieving revision 1.4 >diff -u -r1.4 rssh_chroot_helper.c >--- rssh_chroot_helper.c 3 Apr 2004 08:45:14 -0000 1.4 >+++ rssh_chroot_helper.c 28 Nov 2005 16:38:41 -0000 >@@ -31,20 +31,45 @@ > #ifdef HAVE_CONFIG_H > #include "config.h" > #endif /* HAVE_CONFIG_H */ >+#ifdef HAVE_CONFIG_H >+#include "config.h" >+#endif /* HAVE_CONFIG_H */ > #include <stdio.h> >+#ifdef HAVE_STDLIB_H > #include <stdlib.h> >+#endif /* HAVE_STDLIB_H */ >+#ifdef HAVE_UNISTD_H > #include <unistd.h> >+#endif /* HAVE_UNISTD_H */ >+#ifdef HAVE_ERRNO_H > #include <errno.h> >+#endif /* HAVE_ERRNO_H */ >+#ifdef HAVE_STRING_H > #include <string.h> >+#endif /* HAVE_STRING_H */ >+#ifdef HAVE_LIBGEN_H > #include <libgen.h> >+#endif /* HAVE_LIBGEN_H */ >+#ifdef HAVE_SYSLOG_H > #include <syslog.h> >+#endif /* HAVE_SYSLOG_H */ >+#ifdef HAVE_PWD_H > #include <pwd.h> >+#endif /* HAVE_PWD_H */ >+#ifdef HAVE_SYS_TYPES_H > #include <sys/types.h> >+#endif /* HAVE_SYS_TYPES_H */ >+#ifdef HAVE_SYS_STAT_H > #include <sys/stat.h> >+#endif /* HAVE_SYS_STAT_H */ >+ > > /* LOCAL INCLUDES */ >+#include "rssh.h" >+#include "rsshconf.h" > #include "pathnames.h" > #include "log.h" >+#include "util.h" > #include "argvec.h" > > /* GLOBAL VARIABLES */ >@@ -58,32 +83,20 @@ > /* FILE SCOPE FUNCTIONS */ > > >-char *get_username( void ) >-{ >- struct passwd *temp; >- >- if ( !(temp = getpwuid(getuid()) ) ) return NULL; >- return temp->pw_name; >-} >- >- > void ch_start_logging( void ) > { >- /* set up logging */ >+ /* set up logging - username should be set before this is called */ > if ( log_init ) return; >- username = get_username(); > log_set_facility(LOG_USER); > log_set_priority(LOG_INFO); > log_open(); >- log_msg("new session for %s, UID=%d", >- username ? username : "unknown user", >- getuid()); >+ log_msg("new session for %s, UID=%d", username, getuid()); > /* all log messages from this point on are errors */ > log_set_priority(LOG_ERR); > log_init = 1; > } > >-void ch_fatal_syscall( char *func, char *arg, char *strerr ) >+void ch_fatal_error( char *func, char *arg, char *strerr ) > { > > /* drop privileges */ >@@ -101,45 +114,124 @@ > int main( int argc, char **argv ) > { > struct stat s; >+ ShellOptions_t opts; > long int cmd; > char *conv; > char **argvec; >+ char *cmd_path; >+ char *homedir; >+ struct passwd uinfo; >+ struct passwd *temp; >+ >+ /* >+ * Unfortunately, in order to maintain security, a lot of the code >+ * from the rssh main program must be duplicated. Specifically, the >+ * config file must be parsed to get the chroot path, in order to >+ * prevent a user from being able to chroot() arbitrarily, which leads >+ * to easy root compromise if a user has shell access to the system. >+ * build_arg_vector() must be done here instead of in the main >+ * program, in order to prevent a directory transversal attack. >+ */ >+ >+ /* >+ * As a possible future security enhancement, it should be possible to >+ * have rssh_chroot_helper authenticate cryptographically that it was >+ * exec()'d by rssh. If rssh is SGID to some rssh-users group, it >+ * could store the public key for rssh_chroot_helper in a file which >+ * is only readable by that group. Since rssh_chroot_helper is >+ * already SUID root, it could store its private key in some file that >+ * is only readable by root. Obviously, care should be taken that no >+ * user who has shell access to the system can become a member of the >+ * rssh-users group. The only thing stopping me from coding that now >+ * is my lack of knowledge of cryptographic programming. >+ * >+ * As a further precaution, all users whose accounts will be protected >+ * by rssh should be in the rssh-users group, and both rssh and >+ * rssh_chroot_helper should be executable only by that group. This >+ * can be done now, even without any cryptography. >+ */ >+ >+ /* THIS CODE IS EXPOSED AS ROOT! */ >+ >+ /* initialize variables to defaults */ >+ opts.rssh_umask = 022; >+ opts.shell_flags = 0; >+ opts.chroot_path = NULL; > > /* figure out our name, and give it to the log module */ > progname = strdup(log_make_ident(basename(argv[0]))); > >+ /* get user's passwd info */ >+ if ( (temp = getpwuid(getuid())) ){ >+ uinfo = *temp; >+ username = uinfo.pw_name; >+ } >+ else >+ /* this probably should never happen */ >+ username = "unknown user!"; >+ > /* make sure we have enough arguments, or exit with error */ >- if ( argc < 5 ) >- /* cheating, since this isn't a system call problem... */ >- ch_fatal_syscall("rssh_chroot_helper", "invalid argument(s)", >- "not enough arguments"); >+ if ( argc != 3 ) ch_fatal_error(progname, "invalid arguments", >+ "wrong number of arguments"); >+ >+ /* process the config file, don't log */ >+ if ( !(read_shell_config(&opts, PATH_RSSH_CONFIG, 0)) ){ >+ ch_fatal_error("read_shell_config()", PATH_RSSH_CONFIG, >+ "errors processing configuration file!"); >+ } > > /* >- * argv[1] is the directory to chroot to. Check to make sure it >+ * opts.chroot_path is directory to chroot to. Check to make sure it > * exists. If it does, chroot and drop privileges, and cd to it. > */ > >- if ( stat(argv[1], &s) == -1 ) >- ch_fatal_syscall("stat()", argv[1], strerror(errno)); >- if ( chroot(argv[1]) == -1 ) >- ch_fatal_syscall("chroot()", argv[1], strerror(errno)); >+ if ( stat(opts.chroot_path, &s) == -1 ) >+ ch_fatal_error("stat()", argv[1], strerror(errno)); >+ if ( chroot(opts.chroot_path) == -1 ) >+ ch_fatal_error("chroot()", argv[1], strerror(errno)); >+ >+ /* END OF CODE EXPOSED AS ROOT! */ > > setuid(getuid()); > ch_start_logging(); > >- if ( !(argvec = build_arg_vector(argv[4], 0)) ) >- ch_fatal_syscall("build_arg_vector()", argv[4], >- "bad expansion"); >+ log_msg("user's home dir is %s", uinfo.pw_dir); > >- /* make sure we can change directory to the user's dir */ >- if ( chdir(argv[3]) == -1 ){ >- log_msg("could not cd to user's home dir: %s", argv[3]); >- if ( chdir("/") ) >- ch_fatal_syscall("chdir()", "/", strerror(errno)); >+ /* get the user's home dir */ >+ if ( !(homedir = extract_root(opts.chroot_path, uinfo.pw_dir)) ){ >+ log_msg("couldn't find %s in chroot jail", uinfo.pw_dir); >+ homedir = strdup("/"); > } > >- /* argv[2] is "1" if scp, "2" if sftp, ... */ >- cmd = strtol(argv[2], &conv, 10); >+ log_msg("chrooted to %s", opts.chroot_path); >+ log_msg("changing working directory to %s (inside jail)", homedir); >+ >+ /* cd into / to avoid possibility of breaking out of the jail */ >+ if ( chdir("/") ) >+ ch_fatal_error("chdir()", "/", strerror(errno)); >+ >+ /* make sure we can change directory to the user's dir */ >+ if ( chdir(homedir) == -1 ) >+ log_msg("could not cd to user's home dir: %s", homedir); >+ >+ if ( !(argvec = build_arg_vector(argv[2], 0)) ) >+ ch_fatal_error("build_arg_vector()", argv[2], >+ "bad expansion"); >+ >+ /* >+ * This is the old way to figure out what program to run. Since we're >+ * re-parsing the config file in rssh_chroot helper, we could get rid >+ * of this and redetermine it from the command line, and re-parse >+ * whether or not it's ok to run that command. But, I don't think >+ * that's really necessary, nor worth the effort. A user who is >+ * restricted by rssh will not be able to gain access to manipulate >+ * this on the command line, and a user who has full shell access >+ * can't gain anything they couldn't already do by manipulating it... >+ * so it seems OK to leave as is. >+ */ >+ >+ /* argv[1] is "1" if scp, "2" if sftp, ... */ >+ cmd = strtol(argv[1], &conv, 10); > if ( *conv ){ > log_msg("command identifier contained invalid chars"); > exit(2); >@@ -148,19 +240,19 @@ > /* ok... what were we supposed to run? */ > switch (cmd){ > case 1: >- argv[3] = PATH_SCP; >+ cmd_path = PATH_SCP; > break; > case 2: >- argv[3] = PATH_SFTP_SERVER; >+ cmd_path = PATH_SFTP_SERVER; > break; > case 3: >- argv[3] = PATH_CVS; >+ cmd_path = PATH_CVS; > break; > case 4: >- argv[3] = PATH_RDIST; >+ cmd_path = PATH_RDIST; > break; > case 5: >- argv[3] = PATH_RSYNC; >+ cmd_path = PATH_RSYNC; > break; > default: > log_msg("invalid command specified"); >@@ -168,10 +260,10 @@ > } > > /* now run it */ >- execv(argv[3], argvec); >+ execv(cmd_path, argvec); > > /* we only get here if the exec fails */ >- ch_fatal_syscall("execv()", argv[3], strerror(errno)); >+ ch_fatal_error("execv()", cmd_path, strerror(errno)); > /* and we never get here, but it shuts gcc up */ > exit(1); > } >Index: rsshconf.c >=================================================================== >RCS file: /chest/cvsroot/rssh/rsshconf.c,v >retrieving revision 1.4 >diff -u -r1.4 rsshconf.c >--- rsshconf.c 30 Dec 2004 20:58:09 -0000 1.4 >+++ rsshconf.c 27 Nov 2005 22:35:43 -0000 >@@ -78,6 +78,7 @@ > NULL > }; > >+int log=0; > > /* flag to tell config parser to stop processing config file */ > static bool got_user_config = FALSE; >@@ -124,16 +125,17 @@ > /* EXTERNALLY VISIBLE FUNCTIONS */ > > /* returns FALSE if there was an error, TRUE if not */ >-int read_shell_config( ShellOptions_t *opts, const char *filename ) >+int read_shell_config( ShellOptions_t *opts, const char *filename, int do_log ) > { > FILE *cfg_file; /* config file ptr */ > int linenum; /* cfg file line counter */ > int status = TRUE; /* were all the cfg lines good? */ > char line[CFG_LINE_LEN + 1]; /* buffer to hold region */ > >+ log = do_log; > memset(line, 0, CFG_LINE_LEN + 1); > cfg_file = fopen(filename, "r"); >- if (!cfg_file) { >+ if (!cfg_file && log ) { > log_set_priority(LOG_WARNING); > log_msg("config file (%s) missing, using defaults", filename); > opts->shell_flags = RSSH_ALLOW_SCP; >@@ -169,8 +171,10 @@ > *newline = '\0'; > else { > /* there is no newline - log the error and find the EOL */ >- log_set_priority(LOG_ERR); >- log_msg("line %d: line too long", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("line %d: line too long", lineno); >+ } > while ( fgets(tmp, CFG_LINE_LEN, cfg_file) ){ > if ( (newline = strchr(line, '\n')) ) > break; >@@ -234,9 +238,12 @@ > return TRUE; > default: > /* the keyword is unknown */ >- log_set_priority(LOG_ERR); >- log_msg("line %d: syntax error parsing config file", lineno); >- if ( keywrd[0] ) >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("line %d: syntax error parsing config file", >+ lineno); >+ } >+ if ( keywrd[0] && log ) > log_msg("unknown keyword: %s", keywrd); > return FALSE; > } >@@ -320,8 +327,10 @@ > /* initialize strings and pointers */ > memset(buf, 0, buflen); > if ( !(copy = strdup(str)) ){ >- log_set_priority(LOG_ERR); >- log_msg("OOM error in get_token() (fatal)"); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("OOM error in get_token() (fatal)"); >+ } > exit(1); > } > start = copy; >@@ -421,11 +430,14 @@ > const int lineno ) > { > if ( !eat_comment(line) ){ >- log_msg("line %d: syntax error parsing config file", lineno); >+ if (log) log_msg("line %d: syntax error parsing config file", >+ lineno); > return FALSE; > } >- log_set_priority(LOG_INFO); >- log_msg("allowing scp to all users"); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("allowing scp to all users"); >+ } > opts->shell_flags |= RSSH_ALLOW_SCP; > return TRUE; > } >@@ -445,11 +457,14 @@ > int pos; > > if ( !(pos = eat_comment(line)) ){ >- log_msg("line %d: syntax error parsing config file", lineno); >+ if (log) log_msg("line %d: syntax error parsing config file", >+ lineno); > return FALSE; > } >- log_set_priority(LOG_INFO); >- log_msg("allowing sftp to all users"); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("allowing sftp to all users"); >+ } > opts->shell_flags |= RSSH_ALLOW_SFTP; > return TRUE; > } >@@ -470,11 +485,14 @@ > int pos; > > if ( !(pos = eat_comment(line)) ){ >- log_msg("line %d: syntax error parsing config file", lineno); >+ if (log) log_msg("line %d: syntax error parsing config file", >+ lineno); > return FALSE; > } >- log_set_priority(LOG_INFO); >- log_msg("allowing cvs to all users"); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("allowing cvs to all users"); >+ } > opts->shell_flags |= RSSH_ALLOW_CVS; > return TRUE; > } >@@ -495,12 +513,15 @@ > int pos; > > if ( !(pos = eat_comment(line)) ){ >- log_msg("line %d: syntax error parsing config file", lineno); >+ if (log) log_msg("line %d: syntax error parsing config file", >+ lineno); > return FALSE; > } > log_set_priority(LOG_INFO); >- log_msg("allowing rdist to all users"); >- opts->shell_flags |= RSSH_ALLOW_RDIST; >+ if (log){ >+ log_msg("allowing rdist to all users"); >+ opts->shell_flags |= RSSH_ALLOW_RDIST; >+ } > return TRUE; > } > >@@ -520,11 +541,14 @@ > int pos; > > if ( !(pos = eat_comment(line)) ){ >- log_msg("line %d: syntax error parsing config file", lineno); >+ if (log) log_msg("line %d: syntax error parsing config file", >+ lineno); > return FALSE; > } >- log_set_priority(LOG_INFO); >- log_msg("allowing rsync to all users"); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("allowing rsync to all users"); >+ } > opts->shell_flags |= RSSH_ALLOW_RSYNC; > return TRUE; > } >@@ -546,7 +570,7 @@ > */ > > if ( !(temp = (char *)malloc(CFG_LINE_LEN + 1)) ){ >- log_msg("fatal error: can't allocate space for chroot path"); >+ if (log) log_msg("fatal error: can't allocate space for chroot path"); > exit(1); > } > /* get_asgn_param() eats trailing comments, so we won't */ >@@ -557,8 +581,10 @@ > > /* get rid of any old value for chroot path, assign new one */ > if ( opts->chroot_path ) free(opts->chroot_path); >- log_set_priority(LOG_INFO); >- log_msg("chrooting all users to %s", temp); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("chrooting all users to %s", temp); >+ } > /* we must not free temp, since opts points to it */ > opts->chroot_path = temp; > opts->shell_flags |= RSSH_USE_CHROOT; >@@ -576,8 +602,10 @@ > int pos; > > if ( !(temp = (char *)malloc(CFG_LINE_LEN + 1)) ){ >- log_set_priority(LOG_ERR); >- log_msg("fatal error: can't allocate space for log facility"); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("fatal error: can't allocate space for log facility"); >+ } > exit(1); > } > /* this eats trailing comments */ >@@ -747,17 +775,20 @@ > > free(temp); > if ( !eat_comment(line + pos) ){ >- log_msg("line %d: syntax error parsing config file", lineno); >+ if (log) log_msg("line %d: syntax error parsing config file", >+ lineno); > return FALSE; > } > if ( facname ){ > log_set_priority(LOG_INFO); >- log_msg("setting log facility to %s", facname); >+ if (log) log_msg("setting log facility to %s", facname); > log_set_facility(fac); > return TRUE; > } >- log_msg("line %d: unknown log facility specified", lineno); >- log_set_facility(LOG_USER); >+ if (log){ >+ log_msg("line %d: unknown log facility specified", lineno); >+ log_set_facility(LOG_USER); >+ } > return FALSE; > } > >@@ -770,8 +801,10 @@ > int mask; /* umask */ > > if ( !(temp = (char *)malloc(CFG_LINE_LEN + 1)) ){ >- log_set_priority(LOG_ERR); >- log_msg("fatal error: can't allocate space in process_umask()"); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("fatal error: can't allocate space in process_umask()"); >+ } > exit(1); > } > /* this eats trailing comments */ >@@ -782,15 +815,19 @@ > > /* convert the umask to a number */ > if ( !validate_umask(temp, &mask) ){ >- log_set_priority(LOG_WARNING); >- log_msg("line %d: invalid umask specified, using default 077", >+ if (log){ >+ log_set_priority(LOG_WARNING); >+ log_msg("line %d: invalid umask specified, using default 077", > lineno); >+ } > opts->rssh_umask = 077; > free(temp); > return FALSE; > } >- log_set_priority(LOG_INFO); >- log_msg("setting umask to %#o", mask); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("setting umask to %#o", mask); >+ } > opts->rssh_umask = mask; > free(temp); > return TRUE; >@@ -817,7 +854,7 @@ > > /* make space for user options */ > if ( !(temp = (char *)malloc(CFG_LINE_LEN + 1)) ){ >- log_msg("fatal error: can't allocate space for user options"); >+ if (log) log_msg("fatal error: can't allocate space for user options"); > exit(1); > } > >@@ -831,8 +868,11 @@ > > /* now process individual config bits of temp */ > if ( !(pos = get_token(temp, user, CFG_LINE_LEN + 1, TRUE, TRUE )) ){ >- log_set_priority(LOG_ERR); >- log_msg("syntax error parsing config file, line %d", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("syntax error parsing config file, line %d", >+ lineno); >+ } > return FALSE; > } > >@@ -845,10 +885,13 @@ > * user lines we don't care about... > */ > if ( (strcmp(user, username)) ) return TRUE; >- log_set_priority(LOG_INFO); >- log_msg("line %d: configuring user %s", lineno, user); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("line %d: configuring user %s", lineno, user); >+ } > if ( !(len = eat_colon(temp + pos)) ){ >- log_msg("syntax error parsing config file: line %d ", lineno); >+ if (log) log_msg("syntax error parsing config file: line %d ", >+ lineno); > return FALSE; > } > pos += len; >@@ -856,28 +899,35 @@ > /* do the umask, but validate it last, since it's non-fatal */ > if ( !(len = get_token(temp + pos, mask, CFG_LINE_LEN + 1, > TRUE, FALSE)) ){ >- log_set_priority(LOG_ERR); >- log_msg("syntax error parsing user umask, line %d", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("syntax error parsing user umask, line %d", lineno); >+ } > return FALSE; > } > pos += len; > > /* do the access bits */ > if ( !(len = eat_colon(temp + pos)) ){ >- log_msg("syntax error parsing config file: line %d ", lineno); >+ if (log) log_msg("syntax error parsing config file: line %d ", >+ lineno); > return FALSE; > } > pos += len; > if ( !(len = get_token(temp + pos, axs, CFG_LINE_LEN + 1, > TRUE, FALSE)) ){ >- log_set_priority(LOG_ERR); >- log_msg("syntax error parsing user access, line %d", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("syntax error parsing user access, line %d", lineno); >+ } > return FALSE; > } > if ( !validate_access(axs, &allow_sftp, &allow_scp, &allow_cvs, > &allow_rdist, &allow_rsync) ){ >- log_set_priority(LOG_ERR); >- log_msg("syntax error parsing access bits, line %d", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("syntax error parsing access bits, line %d", lineno); >+ } > return FALSE; > } > pos += len; >@@ -886,7 +936,7 @@ > if ( !(len = eat_colon(temp + pos)) ) goto cleanup; > pos += len; > if ( !(path = (char *)malloc(CFG_LINE_LEN + 1)) ){ >- log_msg("fatal error: can't allocate space for chroot path"); >+ if (log) log_msg("fatal error: can't allocate space for chroot path"); > exit(1); > } > if ( !(len = get_token(temp + pos, path, CFG_LINE_LEN + 1, >@@ -900,20 +950,26 @@ > /* make sure nothing is left */ > while ( *(temp + pos) != '\0' && isspace(*(temp + pos)) ) pos++; > if ( *(temp + pos) != '\0' ){ >- log_set_priority(LOG_ERR); >- log_msg("syntax error parsing user config: line %d", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("syntax error parsing user config: line %d", lineno); >+ } > return FALSE; > } > > /* now finally validate the umask */ > if ( !validate_umask(mask, &tmpmask) ){ >- log_set_priority(LOG_WARNING); >- log_msg("line %d: invalid umask specified, using default", >+ if (log){ >+ log_set_priority(LOG_WARNING); >+ log_msg("line %d: invalid umask specified, using default", > lineno); >+ } > tmpmask = 077; > } >- log_set_priority(LOG_INFO); >- log_msg("setting %s's umask to %#o", user, tmpmask); >+ if (log){ >+ log_set_priority(LOG_INFO); >+ log_msg("setting %s's umask to %#o", user, tmpmask); >+ } > opts->rssh_umask = tmpmask; > > /* set the rest of the parameters */ >@@ -922,27 +978,27 @@ > opts->shell_flags = 0; > /* now set the user-specific flags */ > if ( allow_scp ){ >- log_msg("allowing scp to user %s", user); >+ if (log) log_msg("allowing scp to user %s", user); > opts->shell_flags |= RSSH_ALLOW_SCP; > } > if ( allow_sftp ){ >- log_msg("allowing sftp to user %s", user); >+ if (log) log_msg("allowing sftp to user %s", user); > opts->shell_flags |= RSSH_ALLOW_SFTP; > } > if ( allow_cvs ){ >- log_msg("allowing cvs to user %s", user); >+ if (log) log_msg("allowing cvs to user %s", user); > opts->shell_flags |= RSSH_ALLOW_CVS; > } > if ( allow_rdist ){ >- log_msg("allowing rdist to user %s", user); >+ if (log) log_msg("allowing rdist to user %s", user); > opts->shell_flags |= RSSH_ALLOW_RDIST; > } > if ( allow_rsync ){ >- log_msg("allowing rsync to user %s", user); >+ if (log) log_msg("allowing rsync to user %s", user); > opts->shell_flags |= RSSH_ALLOW_RSYNC; > } > if ( path ){ >- log_msg("chrooting %s to %s", user, path); >+ if (log) log_msg("chrooting %s to %s", user, path); > opts->shell_flags |= RSSH_USE_CHROOT; > } > opts->chroot_path = path; >@@ -961,22 +1017,30 @@ > > /* make sure '=' is next token, otherwise syntax error */ > if ( (pos = eat_assignment(line)) <= 0 ){ >- log_set_priority(LOG_ERR); >- log_msg("error parsing config file at line %d: " >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("error parsing config file at line %d: " > "assignment expected", lineno); >+ } > return FALSE; > } > /* get the string parameter of the assignment */ > if ( !(len = get_token((line + pos), buf, buflen, FALSE, FALSE)) ){ >- log_set_priority(LOG_ERR); >- log_msg("syntax error parsing config file, line %d", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("syntax error parsing config file, line %d", >+ lineno); >+ } > return FALSE; > } > pos += len; > /* check for ending comment */ > if ( !eat_comment(line + pos) ){ >- log_set_priority(LOG_ERR); >- log_msg("syntax error parsing config file at line %d", lineno); >+ if (log){ >+ log_set_priority(LOG_ERR); >+ log_msg("syntax error parsing config file at line %d", >+ lineno); >+ } > return FALSE; > } > return pos; >Index: rsshconf.h >=================================================================== >RCS file: /chest/cvsroot/rssh/rsshconf.h,v >retrieving revision 1.1.1.1 >diff -u -r1.1.1.1 rsshconf.h >--- rsshconf.h 15 Mar 2004 21:01:37 -0000 1.1.1.1 >+++ rsshconf.h 27 Nov 2005 22:34:54 -0000 >@@ -49,7 +49,7 @@ > > > /* EXTERNALLY VISIBLE FUNCTION DECLARATIONS */ >-int read_shell_config( ShellOptions_t *opts, const char *filename ); >+int read_shell_config( ShellOptions_t *opts, const char *filename, int log ); > > > #endif /* _rssh_config_h */ >Index: util.c >=================================================================== >RCS file: /chest/cvsroot/rssh/util.c,v >retrieving revision 1.4 >diff -u -r1.4 util.c >--- util.c 30 Dec 2004 20:58:09 -0000 1.4 >+++ util.c 27 Nov 2005 17:01:52 -0000 >@@ -122,12 +122,13 @@ > > /* > * opt_exist() - takes a string representing a command line, and a single >- * character representing a command-line option to search for. >- * If the option exists in the command line, return TRUE. This >- * function is a little over-zealous about returning a match, >- * but in this case that is better than not being zealous >- * enough. And frankly, I don't want to spend the time required >- * to get it 100% right. It's not worth the effort. >+ * character representing a command-line option flag (e.g. "-S") >+ * to search for. If the option exists in the command line, >+ * return TRUE. This function is a little over-zealous about >+ * returning a match, but in this case that is better than not >+ * being zealous enough. And frankly, I don't want to spend the >+ * time required to get it 100% right. It's not worth the >+ * effort. > */ > bool opt_exist(char *cl, char opt) > { >@@ -209,6 +210,11 @@ > } > > if ( check_command(cl, opts, PATH_CVS, RSSH_ALLOW_CVS) ) >+ if ( opt_exist(cl, 'e') ){ >+ fprintf(stderr, "\ninsecure -e option not allowed."); >+ log_msg("insecure -e option in cvs command line!"); >+ return NULL; >+ } > return PATH_CVS; > > if ( check_command(cl, opts, PATH_RDIST, RSSH_ALLOW_RDIST) ){ >@@ -321,4 +327,16 @@ > return TRUE; > } > >+/* >+ * get_username() - get the username of the user, or return unknown >+ * >+ */ >+char *get_username( void ) >+{ >+ struct passwd *temp; >+ >+ if ( !(temp = getpwuid(getuid()) ) ) return "unknown user!"; >+ return temp->pw_name; >+} >+ > >Index: util.h >=================================================================== >RCS file: /chest/cvsroot/rssh/util.h,v >retrieving revision 1.4 >diff -u -r1.4 util.h >--- util.h 30 Dec 2004 20:58:09 -0000 1.4 >+++ util.h 19 Nov 2005 16:24:33 -0000 >@@ -38,6 +38,7 @@ > int validate_umask( const char *temp, int *mask ); > int validate_access( const char *temp, bool *allow_sftp, bool *allow_scp, > bool *allow_cvs, bool *allow_rdist, bool *allow_rsync ); >-bool opt_exist(char *cl, char opt); >+bool opt_exist( char *cl, char opt ); >+char *get_username( void ); > > #endif /* _util_h */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 115082
: 74740