How to setup openssh chrooted sftp and SELinux in Fedora 16
updated: 2012-02-10
I promised that I would write an article about setting of the chrooted sftp accounts with openssh and SELinux. So here it is.


I use Fedora 16 but everything I write is applicable in later Fedoras either since openssh-5.8p2-24.fc16 and later contain SELinux support for chrooted sftp environment.

openssh server configuration

I don't want to restrict all users, so I prepare special group for restricted users called sftponly:
server# groupadd sftponly
Then I add these lines to /etc/ssh/sshd_config file:
 Match Group sftponly
     ForceCommand internal-sftp
     ChrootDirectory %h
It means if an user is in the group sftponly, force internal-sftp for him and chroot him into his home directory. Then that restart sshd service:
server# systemctl restart sshd.service

user configuration

server# useradd -M -g sftponly sftponlyuser
This command creates the "sftponlyuser" user with home direcotry set to /home/sftponlyuser, but this directory is not created. This directory will be used as root for chrooted sftp sessions and has to be owned by root and not be writeable by anybody else. But subdirectory for upload must be owned by sftponlyuser:
updated: 2012-02-10
server# mkdir -p /home/sftponlyuser/upload

server# chown sftponlyuser: /home/sftponlyuser/upload

server# restorecon -R -v /home/sftponlyuser
restorecon reset /home/sftponlyuser context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:user_home_dir_t:s0
restorecon reset /home/sftponlyuser/upload context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:user_home_t:s0
Now I try to connect with sftp to the sftponlyuser account
client$ sftp sftponlyuser@f16-openssh
Connecting to f16-openssh...
sftponlyuser@f16-openssh's password: password
sftp> ls
sftp> cd upload
It looks good.


sftp> put myfile.txt
Uploading myfile.txt to /upload/myfile.txt
Couldn't get handle: Permission denied
All chrooted sftp processes are running as the chroot_user_t context:
system_u:system_r:chroot_user_t:s0-s0:c0.c1023 \_ sshd: sftponlyuser@notty
system_u:system_r:chroot_user_t:s0-s0:c0.c1023      \_ sshd: sftponlyuser@internal-sftp
And there is an AVC message on the server:
type=AVC msg=audit(1328793486.912:654): avc:  denied  { write } for  pid=12722 comm="sshd" name="upload" dev=vda3 ino=971 scontext=system_u:system_r:chroot_user_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir
chroot_user_t can be allowed to write into user_home_t using the SELinux boolean 'ssh_chroot_rw_homedirs'
server# setsebool -P ssh_chroot_rw_homedirs on
sftp> put myfile.txt
Uploading myfile.txt to /upload/myfile.txt
myfile.txt                                        100%   29     0.0KB/s   00:00
Moreover, chroot_user_t is also restricted in read operations. This context is allowed to read only contexts intended for user home content:
updated: 2012-02-10
server# echo 'secret data' > ~sftponlyuser/upload/secret_file.txt

server# chcon -t admin_home_t ~sftponlyuser/upload/secret_file.txt

server# cp /etc/passwd /home/sftponlyuser/upload

server# chcon -t etc_t /home/sftponlyuser/upload/passwd                                                                       
sftp> ls
sftp> get secret_file.txt
Couldn't stat remote file: Permission denied
File "/upload/secret_file.txt" not found.

sftp> get passwd
Couldn't stat remote file: Permission denied
File "/upload/passwd" not found.
server# setenforce 0
sftp> ls
myfile.txt     passwd      secret_file.txt

sftp> get secret_file.txt
Fetching /upload/secret_file.txt to secret_file.txt
/upload/secret_file.txt                           100%   12     0.0KB/s   00:00


using gemalto smart card with openssh in Fedora 16
This is only memo post.

$ rpm -q openssh coolkey nss-util

$ modutil -list -dbdir /etc/pki/nssdb
Listing of PKCS #11 Modules
1. NSS Internal PKCS #11 Module
slots: 2 slots attached
status: loaded

slot: NSS Internal Cryptographic Services
token: NSS Generic Crypto Services

slot: NSS User Private Key and Certificate Services
token: NSS Certificate DB

2. CoolKey PKCS #11 Module
library name:
slots: 1 slot attached
status: loaded

slot: Gemalto GemPC Twin 00 00
token: accountid

$ ssh-keygen -D /usr/lib64/pkcs11/
ssh-rsa AAAAB3NzaC1yc .... oXEdVwIHDTuYM9KRW/6Q==
ssh-rsa AAAAB3NzaC1yc .... bFgPY1JMTokZSiHYkyhw==

$ ssh-keygen -D /usr/lib64/pkcs11/ | ssh malas cat \>\> .ssh/authorized_keys
user@malas's password: ***

$ ssh -I /usr/lib64/pkcs11/ malas
Enter PIN for 'accountid': ***
Last login: Thu Jan 19 16:02:17 2012 from localhost
[user@malas ~]$ logout

$ ssh-add -s /usr/lib64/pkcs11/
Enter passphrase for PKCS#11: ***
Card added: /usr/lib64/pkcs11/

$ ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCEIfvLQ3ItOA+vG9TBbsmxtBQAvXHRtXaJuAORMXR1c2KBVfPZUakat47ZkKNK2yODgb3LHego/MNCriMg0kQB98ga5N6e2LnNRAHz21zArCER6L+fXbc8pfkB34aioTnLan1UTTacTqejKeBwDUBRuxoXEdVwIHDTuYM9KRW/6Q== /usr/lib64/pkcs11/
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC22cHPLN/eCwR0WoPkXTZIZRqCtqW1oFkQPSVyy4/hVaoOnvVaFInDXQDC5RAF6VfLYKreWF0rS0erNefSE0P5bIyoP049nCG9suIViS5nlFmYCW7p8rd1k+zX78S/nldY8EPxy+VrDfHZ3jnXeMn2h2bFgPY1JMTokZSiHYkyhw== /usr/lib64/pkcs11/

$ ssh malas
Last login: Thu Jan 19 16:03:16 2012 from malas
[user@malas ~]$ logout

$ ssh-add -e /usr/lib64/pkcs11/
Enter passphrase for PKCS#11: ***
Card removed: /usr/lib64/pkcs11/

$ ssh-add -L
The agent has no identities.

using serial console in qemu+kvm with grub and grub2
I usually use "virsh console <virtual domain>" command to access 
domain's virtual serial console. There are only few steps 
needed to allow control grub or grub2 and see boot output via this console:

grub (RHEL and Fedora < 16)

 1. add 2 following lines to main part of /boot/grub/grub.conf
serial --unit=0 --speed=38400
terminal --timeout=10 serial console
 2. add "console=ttyS0" to the end of kernel command line
title Red Hat Enterprise Linux (2.6.32-131.0.15.el6.x86_64)
     root (hd0,0)
     kernel /vmlinuz-2.6.32-131.0.15.el6.x86_64 ro ... console=ttyS0

grub2 (Fedora > 15)

 1. add these lines to /etc/default/grub
GRUB_SERIAL_COMMAND="serial --unit=0 --speed=38400 --word=8 --parity=no --stop=1"
 2. add "console=ttyS0" to BOOT_IMAGE variable in the same file

 3. regenerate /boot/grub2/grub.cfg
# grub2-mkconfig -o /boot/grub2/grub.cfg

latest upstart update in Fedora 15+ - upstart-1.2-2.fc15.x86_64
Good news at the beginning - upstart is still usable in Fedora 15 and Rawhide. How to use upstart in Fedora 15+ read here

upstart-1.2-2 brings some changes against -1 release.

1. /run
/run was announced few weeks ago as new feature in Fedora ... link ... It is created by dracut and also dracut mounts tmpfs on this directory, but the directory is not labelled correctly - it's left for systemd. Since with upstart, there is no systemd running, so it's needed relabel of /run in early boot. That is why /etc/init/fix-selinux-on-run.conf has been added in this release.

At the same time, tmpfiles.conf has been changed to create directories in /run as well.

2. binaries in /lib/upstart
upstart is now compiled with --sbindir=/lib/upstart option so all binaries are located in this directory. All files which used to be in /sbin in previous release are now symlinks. There's been also added /etc/profile.d/ file which adds /lib/upstart into your shell PATH variable. These changes result in these behaviour:

a) if you just type command without absolute path like 'telinit', 'reboot', 'shutdown', ... it will be called utility from upstart instead of systemd. You might have noticed message 'Failed to talk to init daemon.' which is written by systemd utils trying to talk systemd. This is away now.

# strace reboot
execve("/sbin/reboot", ["reboot"], [/* 18 vars */]) = 0
# strace reboot
execve("/lib/upstart/reboot", ["reboot"], [/* 26 vars */]) = 0
b) reboot command used to exec /sbin/shutdown, now it is
execve("/lib/upstart/shutdown", ["/lib/upstart/shutdown", "-r", "now"], [/* 19 vars */]) = 0

F15 update can be found here

Note: You will need new selinux-policy with context label rule -  /lib/upstart/init  init_exec_t  which should be already on the way to updates and rawhide.  It the meantime it can be temporary fixed with following command:
# chcon -t init_exec_t /lib/upstart/init

How to disable upstart job in Fedora 15 and Fedora Rawhide? update
Ok, forget everything from How to disable upstart job in Fedora rawhide? It's dead end and also in some cases it doesn't work well. But there is another way, developed by upstream in 0.9 branch which would be probably used in new ubuntu.

There is bazaar revision 1262 within 0.9 branch introducing override files. Quotation from init(5):

       ·   Files ending in .override are called override files.  If an override file  is
           present,  the  stanzas  it  contains  take precedence over those equivalently
           named stanzas in the corresponding configuration file contents for a particu‐
           lar  job.   The  main  use for override files is to modify how a job will run
           without having to modify its configuration file directly.   See  the  section
           Override File Handling below for further details.

That means if you e.g. want to disable reboot on control-alt-delete, you can create /etc/init/crontrol-alt-delete.override file with manual stanza or changed exec stanza.

Fedora rawhide build with patch backporting this feature can be found at koji as task ID 2927903 now and update for Fedora 15 testing will be pushed soon. is waiting for your karma in bodhi - upstart-1.1-1.fc15 upstart-1.2-1.fc15

How to disable upstart job in Fedora rawhide?
(Warning: czenglish :)

There have been some requests to mark job files as %config(noreplace) in Fedora upstart package. Typical use case is to disable reboot on control-alt-delete, see #447997 - RFE: mark control-alt-delete %config(noreplace), #612175 - mark /etc/init/ files as config files. Job files are more likely scripts than config files, mark them as %config(noreplace) is unsuitable and these files are overwritten with each update.

Since upstart-1.0-2.fc16 (which is currently in Fedora rawhide (f16)) there is new directory /lib/upstart/init for job defaults. All job files from upstart package are installed there. In case upstart is just installed or upgraded from version < 1.0-2, symlinks referencing to /lib/upstart/init are created in /etc/init/.

  cd /lib/upstart/init
  for j in *.conf; do
    if [ ! -e /etc/init/$j ]; then
      ln -sf /lib/upstart/init/$j /etc/init

So starting with this update it is possible to disable or change job without being overwritten by next update.

1. disable job
You can simply remove symlink from /etc/init/ or you can change job (see 2. change job) and add manual stanza to job file.

2. change job
remove symlink and copy default job file from /lib/upstart/init to /etc/init:
# rm /etc/init/control-alt-delete.conf
# cp /lib/upstart/init/control-alt-delete.conf /etc/init
# echo "debug" >> /etc/init/control-alt-delete.conf

Using upstart in Fedora rawhide
Fedora 15 definitively replaced init daemon implementation upstart with new systemd. But it is still possible to use upstart. Only few steps are needed:

1. install upstart and dependencies

# yum install upstart
upstart.x86_64 0:1.0-1.fc16
Dependency Installed:
initscripts-legacy.x86_64 0:9.26-1.fc16

initscripts-legacy.x86_64 is sub-package of initscripts. It contains basic rc scripts including rc.sysinit which were separated from initscripts after change to systemd units was made.

2. configure bootloader
Kernel or initramfs loader (dracut) runs after initialization /sbin/init by default. This can be changed by adding init=<path> to kernel command line. Upstart installs its init to /sbin/upstart. To allow boot with upstart automatically, add new kernel entry to /etc/grub.conf:

title Fedora - upstart (2.6.38-0.rc7.git2.3.fc16.x86_64)
    root (hd0,0)
    kernel /vmlinuz-2.6.38-0.rc7.git2.3.fc16.x86_64 ro root=/dev/mapper/VolGroup-lv_root rd_LVM_LV=VolGroup/lv_root rd_LVM_LV=VolGroup/lv_swap init=/sbin/upstart
    initrd /initramfs-2.6.38-0.rc7.git2.3.fc16.x86_64.img

(note: Change kernel and initrd versions according to your system)

3. enable selinux
Selinux is no more initializated in intramfs as this responsibility was moved to systemd. Upstart can't initialize selinux so there's needed to recreate initramfs with selinux support. Edit /etc/dracut.conf.d/01-dist.conf and recreate initramfs:

# echo 'add_dracutmodules+=" selinux "' >> /etc/dracut.conf.d/01-dist.conf
# dracut --force

4. set default runlevel
upstart's job rcS runs defaul runlevel 3. If you want to boot into runlevel 5, edit your /etc/inittab

# echo 'id:5:initdefault:' >> /etc/inittab

5. reboot


Log in