chroot for ftp/telnet/rsh/ssh on solaris 10

By shyjack

By properly setting up a new root environment, you can fool the user and make them feel they are logging into a real root environment, rather than a jailed root. the funny part is to make a perfect root environment, with everything setting up, not exposure of the real /etc/passwd and /etc/shadow etc… The way to make a root environment I can think of includes 1. copy all required files (binary files, libraries, configurations …) down to the new root. 2. loopback mount the relevant file systems down to the new root. (the drawback is it will expose the real /etc to the user) 3. set the root path to the root path of a non-global zone. (make sure zone is running if you are running a sparse local zone)

 

1. ftp

It is fairly simple to get chroot for ftp session, change home directory from /etc/passwd as below,
usertest:55502:0:comments:/export/home/usertest/newroot/./test:/bin/ksh

/export/home/usertest/newroot/./test  is the new home directory, of which, /export/home/usertest/newroot is the new root, and /test is relateive path to the new root.

ftp server will change root to “/export/home/usertest/newroot/” after ftp session established.

Pls make sure you copy some essential required file down to the new root, such as /bin /sbin /etc,  etc.
the easy way is to loopback mount those file system as below

cd /export/home/usertest/newroot
mkdir bin sbin etc usr lib
mount -F lofs /bin  /export/home/usertest/newroot/bin
mount -F lofs /sbin  /export/home/usertest/newroot/sbin
mount -F lofs /usr  /export/home/usertest/newroot/usr
mount -F lofs /etc  /export/home/usertest/newroot/etc
mount -F lofs /lib  /export/home/usertest/newroot/lib

after user logs in via ftp, the session will be limited under the new root (/export/home/usertest/newroot)

pls note:  for ftp only, even the new root is total empty, the ftp session is still able to establish. But list functionality from ftp gui client doesn’t work, command line works well.
           authentication is based /etc/passwd and /etc/shadow under real root.

2.  telnet  (this example is based on solaris 10, change the procedure accordingly if you are running sol9 or sol
    it doesn’t matter if you do not change home directory in /etc/passwd

2.1 prepare the new root environment (/export/home/usertest/newroot)
    copy all required files/directories down to the new root and test it.
    eg:  /usr/sbin/chroot  /export/home/usertest/newroot  /bin/ksh

2.2
    inetadm -l telnet  > telnet.bak
    inetadm -m telnet exec=”/usr/sbin/a.ksh”
    svcadm restart telnet
   
    a.ksh
    #!/bin/ksh
    /usr/sbin/chroot /export/home/usertest/newroot/ /usr/sbin/in.telnetd
   
pls note, as chroot is explicitly run by a.ksh, the authentication will be based on /etc/passwd and /etc/shadow under new root, namely
/export/home/usertest/newroot/etc/passwd and /export/home/usertest/newroot/etc/shadow

3.  rsh
    it doesn’t matter if you do not change home directory in /etc/passwd
    rsh is using SMF svc:/network/login:rlogin and associated daemon is /usr/sbin/in.rlogind
   
3.1 prepare the new root
3.2 inetadm -m shell/rlogin exec=”/usr/sbin/b.ksh”

    b.ksh
    #!/bin/ksh
    /usr/sbin/chroot /export/home/usertest/newroot/ /usr/sbin/in.rlogind
   
pls note, authentication is based on /export/home/usertest/newroot/etc/passwd and /export/home/usertest/newroot/etc/shadow.

4.  openssh   

    authentication is based /etc/passwd and /etc/shadow under real root.
4.1  it is a must to change the home directory as above for ftp.
4.2  prepare the new root and test it.
4.3  download the below packages from sunfreeware.com and install them
     
     gcc
     libiconv
     openssl

4.4  download openssh source code and save into a temporary directory
     modify session.c as stated below

+ #define CHROOT                     /* to be added (of course without + mark at the beginning) */

  /* func */

  Session *session_new(void);
***************
*** 1159,1164 ****
— 1161,1171 —-
  void
  do_setusercontext(struct passwd *pw)
  {
+ #ifdef CHROOT                      /* to be added (of course without + mark at the beginning ) */
+       char *user_dir;              /* to be added (of course without + mark at the beginning) */
+       char *new_root;              /* to be added (of course without + mark at the beginning) */
+ #endif /* CHROOT */                /* to be added (of course without + mark at the beginning) */
+
        char tty=”;

  #ifdef HAVE_CYGWIN

                if (setlogin(pw->pw_name) < 0)
                        error(“setlogin failed: %s”, strerror(errno));

+               #ifdef CHROOT                  /* to be added (of course without + mark at the beginning) */
+                       user_dir = xstrdup(pw->pw_dir);  /* to be added (of course without + mark at the beginning) */
+                       new_root = user_dir + 1;  /* to be added (of course without + mark at the beginning) */
+
+                       while((new_root = strchr(new_root, ‘.’)) != NULL) {   /* to be added (of course without + mark at the beginning) */
+                               new_root–;                                   /* to be added (of course without + mark at the beginning) */
+                               if(strncmp(new_root, “/./”, 3) == 0) {        /* to be added (of course without + mark at the beginning) */
+                                       *new_root = ”;                     /* to be added (of course without + mark at the beginning) */
+                                       new_root += 2;                        /* to be added (of course without + mark at the beginning) */
+
+                                       if(chroot(user_dir) != 0)             /* to be added (of course without + mark at the beginning) */
+                                               fatal(“Couldn’t chroot to user directory %s”, user_dir);   /* to be added (of course without + mark at the beginning) */
+
+                                       pw->pw_dir = new_root;                 /* to be added (of course without + mark at the beginning) */
+                                       break;                                 /* to be added (of course without + mark at the beginning) */
+                               }                                              /* to be added (of course without + mark at the beginning) */
+                               new_root += 2;                                 /* to be added (of course without + mark at the beginning) */
+                       }                                                      /* to be added (of course without + mark at the beginning) */
+               #endif /* CHROOT */                                            /* to be added (of course without + mark at the beginning) */
+
                if (setgid(pw->pw_gid) < 0) {
                        perror(“setgid”);
                        exit(1);
     

4.5
./configure –with-random=/dev/random \
  –prefix=/usr/local –libexecdir=/usr/libexec/openssh \
  –sysconfdir=/usr/local/etc –mandir=/usr/share/man

4.6
make

4.7
mkdir /var/empty
chown root:sys /var/empty
chmod 755 /var/empty
groupadd sshd
useradd -g sshd -c ’sshd privsep’ -d /var/empty -s /bin/false sshd

4.8
make install

4.9
/usr/local/bin/ssh-keygen -t rsa1 -f /usr/local/etc/ssh_host_key -N
/usr/local/bin/ssh-keygen -t dsa -f /usr/local/etc/ssh_host_dsa_key -N
/usr/local/bin/ssh-keygen -t rsa -f /usr/local/etc/ssh_host_rsa_key -N

4.10
create file /etc/init.d/sshd

#!/bin/sh
pid=`/usr/bin/ps -e | /usr/bin/grep sshd |   /usr/bin/sed -e ’s/^  *//’ -e ’s/ .*//’`
case $1 in
’start’)
  /usr/local/sbin/sshd;;
’stop’)
  if [ "${pid}" != "" ]; then
  /usr/bin/kill ${pid}; fi;;
*)
  echo “usage: /etc/init.d/sshd (start|stop)”;;
esac

4.11
ln -s /etc/init.d/sshd /etc/rc2.d/S100sshd_chroot
ln -s /etc/init.d/sshd /etc/rc0.d/K100sshd_chroot

4.12
/etc/rc2.d/S100sshd_chroot start

回复