Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge our PC-BSD specific bits into the 'master' branch to get

ready for some 10-STABLE builds :)
  • Loading branch information...
commit 90834e2a30b0556294613f8dfe52e50b4855d84d 1 parent aa68cbc
Kris Moore kmoore134 authored
Showing with 11,127 additions and 55 deletions.
  1. +3 −0  etc/Makefile
  2. +17 −1 etc/csh.cshrc
  3. +1 −1  etc/defaults/periodic.conf
  4. +1 −1  etc/defaults/rc.conf
  5. +4 −4 etc/freebsd-update.conf
  6. +8 −0 etc/make.conf
  7. +12 −3 etc/profile
  8. +63 −10 etc/rc
  9. +173 −0 etc/rc.conf.pcbsd
  10. +98 −0 etc/rc.delay
  11. +10 −1 etc/rc.resume
  12. +1 −3 etc/rc.subr
  13. +1 −1  etc/root/dot.cshrc
  14. +1 −1  etc/root/dot.profile
  15. +43 −1 etc/sysctl.conf
  16. +1 −0  lib/libpam/modules/modules.inc
  17. +27 −0 lib/libpam/modules/pam_pefs/Makefile
  18. +147 −0 lib/libpam/modules/pam_pefs/pam_pefs.8
  19. +526 −0 lib/libpam/modules/pam_pefs/pam_pefs.c
  20. +1 −0  sbin/Makefile
  21. +24 −0 sbin/pefs/Makefile
  22. +466 −0 sbin/pefs/pefs.8
  23. +1,173 −0 sbin/pefs/pefs_ctl.c
  24. +114 −0 sbin/pefs/pefs_ctl.h
  25. +386 −0 sbin/pefs/pefs_key.c
  26. +282 −0 sbin/pefs/pefs_keychain.c
  27. +48 −0 sbin/pefs/pefs_keychain.h
  28. +113 −0 sbin/pefs/pefs_subr.c
  29. +13 −9 sys/amd64/conf/GENERIC
  30. +2 −2 sys/conf/newvers.sh
  31. +179 −0 sys/crypto/hmac/hmac.c
  32. +55 −0 sys/crypto/hmac/hmac.h
  33. +128 −0 sys/crypto/pkcs5v2/pkcs5v2.c
  34. +36 −0 sys/crypto/pkcs5v2/pkcs5v2.h
  35. +8 −8 sys/crypto/sha2/sha2.c
  36. +2 −0  sys/fs/nullfs/null_subr.c
  37. +282 −0 sys/fs/pefs/pefs.h
  38. +220 −0 sys/fs/pefs/pefs_aesni.c
  39. +43 −0 sys/fs/pefs/pefs_aesni.h
  40. +754 −0 sys/fs/pefs/pefs_crypto.c
  41. +92 −0 sys/fs/pefs/pefs_crypto.h
  42. +394 −0 sys/fs/pefs/pefs_dircache.c
  43. +97 −0 sys/fs/pefs/pefs_dircache.h
  44. +704 −0 sys/fs/pefs/pefs_subr.c
  45. +465 −0 sys/fs/pefs/pefs_vfsops.c
  46. +2,674 −0 sys/fs/pefs/pefs_vnops.c
  47. +186 −0 sys/fs/pefs/pefs_xbase64.c
  48. +208 −0 sys/fs/pefs/pefs_xts.c
  49. +648 −0 sys/fs/pefs/vmac.c
  50. +96 −0 sys/fs/pefs/vmac.h
  51. +1 −0  sys/modules/Makefile
  52. +23 −0 sys/modules/pefs/Makefile
  53. +7 −1 sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c
  54. +66 −8 usr.sbin/freebsd-update/freebsd-update.sh
3  etc/Makefile
View
@@ -26,6 +26,7 @@ BIN1= crontab \
login.access \
login.conf \
mac.conf \
+ make.conf \
motd \
netconfig \
network.subr \
@@ -37,6 +38,8 @@ BIN1= crontab \
protocols \
rc \
rc.bsdextended \
+ rc.conf.pcbsd \
+ rc.delay \
rc.firewall \
rc.initdiskless \
rc.sendmail \
18 etc/csh.cshrc
View
@@ -1,3 +1,19 @@
-# $FreeBSD$
+# $FreeBSD: src/etc/csh.cshrc,v 1.3 1999/08/27 23:23:40 peter Exp $
#
# System-wide .cshrc file for csh(1).
+if ( $?LANG ) then
+else
+ setenv LANG en_US.UTF-8
+endif
+#setenv LC_CTYPE en_US.UTF-8
+#setenv LC_COLLATE POSIX
+setenv EDITOR ee
+setenv PAGER less
+setenv BLOCKSIZE K
+
+# Set the MANPATH
+unsetenv MANPATH
+setenv MANPATH `manpath`
+
+# Enable the delete key
+bindkey [3~ delete-char
2  etc/defaults/periodic.conf
View
@@ -175,7 +175,7 @@ weekly_show_info="YES" # scripts returning 1
weekly_show_badconfig="NO" # scripts returning 2
# 310.locate
-weekly_locate_enable="YES" # Update locate weekly
+weekly_locate_enable="NO" # Update locate weekly
# 320.whatis
weekly_whatis_enable="YES" # Update whatis weekly
2  etc/defaults/rc.conf
View
@@ -55,7 +55,7 @@ populate_var="AUTO" # Set to YES to always (re)populate /var, NO to never
cleanvar_enable="YES" # Clean the /var directory
local_startup="/usr/local/etc/rc.d" # startup script dirs.
script_name_sep=" " # Change if your startup scripts' names contain spaces
-rc_conf_files="/etc/rc.conf /etc/rc.conf.local"
+rc_conf_files="/etc/rc.conf.pcbsd /etc/rc.conf /etc/rc.conf.local"
# ZFS support
zfs_enable="NO" # Set to YES to automatically mount ZFS file systems
8 etc/freebsd-update.conf
View
@@ -3,23 +3,23 @@
# Trusted keyprint. Changing this is a Bad Idea unless you've received
# a PGP-signed email from <security-officer@FreeBSD.org> telling you to
# change it and explaining why.
-KeyPrint 800651ef4b4c71c27e60786d7b487188970f4b4169cc055784e21eb71d410cc5
+KeyPrint 771f0e6c8d9de2df1f70a2872a3d25716e6a7a50c32fc4f7ba15746cbf18ce7f
# Server or server pool from which to fetch updates. You can change
# this to point at a specific server if you want, but in most cases
# using a "nearby" server won't provide a measurable improvement in
# performance.
-ServerName update.FreeBSD.org
+ServerName fbsd-update.pcbsd.org
# Components of the base system which should be kept updated.
-Components src world kernel
+Components world kernel
# Example for updating the userland and the kernel source code only:
# Components src/base src/sys world
# Paths which start with anything matching an entry in an IgnorePaths
# statement will be ignored.
-IgnorePaths
+IgnorePaths /boot/kernel/linker.hints
# Paths which start with anything matching an entry in an IDSIgnorePaths
# statement will be ignored by "freebsd-update IDS".
8 etc/make.conf
View
@@ -0,0 +1,8 @@
+# Uncomment this if you want to do port builds with no interaction
+#BATCH=yes
+
+# Keep KDE4 in /usr/local, fixes sharing of icons / mime and others
+KDE4_PREFIX=/usr/local
+
+# Enable PKGNG
+WITH_PKGNG=yes
15 etc/profile
View
@@ -1,4 +1,4 @@
-# $FreeBSD$
+# $FreeBSD: src/etc/profile,v 1.14 2004/06/06 11:46:27 schweikh Exp $
#
# System-wide .profile file for sh(1).
#
@@ -12,7 +12,16 @@
# You should also read the setlocale(3) man page for information
# on how to achieve more precise control of locale settings.
#
-# Check system messages
-# msgs -q
+# Read system messages
+# msgs -f
# Allow terminal messages
# mesg y
+if [ -z "$LANG" -o "$LANG" = "C" ] ; then
+ LANG="en_US.UTF-8"; export LANG
+fi
+#LC_CTYPE="en_US.UTF-8"; export LC_CTYPE
+#LC_COLLATE="POSIX"; export LC_COLLATE
+EDITOR=ee; export EDITOR
+PAGER=less; export PAGER
+BLOCKSIZE=K; export BLOCKSIZE
+
73 etc/rc
View
@@ -99,22 +99,75 @@ done
unset files local_rc
-# Now that disks are mounted, for each dir in $local_startup
-# search for init scripts that use the new rc.d semantics.
-#
-case ${local_startup} in
-[Nn][Oo] | '') ;;
-*) find_local_scripts_new ;;
-esac
+# Check if we are needing to finish up a freebsd-update
+if [ -e "/var/.freebsd-update-finish" ] ; then
+ TERM="cons25" ; export TERM
+ clear
+ echo "Installing FreeBSD updates... Please wait..."
+ /usr/sbin/freebsd-update --non-interactive install
+ if [ -e "/usr/local/bin/pc-softwaremanager" ] ; then
+ /usr/local/bin/pc-extractoverlay desktop
+ else
+ /usr/local/bin/pc-extractoverlay server
+ fi
+
+ rm /var/.freebsd-update-finish 2>/dev/null
+
+ echo "Press ENTER to continue"
+ read -t 30 tmp
+fi
-files=`rcorder ${skip} /etc/rc.d/* ${local_rc} 2>/dev/null`
-for _rc_elem in ${files}; do
+# Tickle /etc/version
+uname -r > /etc/version
+
+if [ "$fastboot_enable" = "YES" ]; then
+ # We are fast-booting
+
+ # List of rc.d scripts we will start before login
+ preLoad="/etc/rc.d/hostname /etc/rc.d/random /etc/rc.d/adjkerntz /etc/rc.d/cleanvar /etc/rc.d/hostid /etc/rc.d/ldconfig /etc/rc.d/zfs /etc/rc.d/zvol /etc/rc.d/cleartmp $fastboot_earlyrc "
+
+ # Start loopback device
+ /etc/rc.d/netif start lo0
+
+ # Run the early scripts now
+ for i in $preLoad
+ do
+ run_rc_script ${i} ${_boot}
+ done
+
+ # Check for USB mouse to start
+ mChk="ums0 ums1"
+ for i in $mChk
+ do
+ if [ -e "/dev/$i" ] ; then
+ /etc/rc.d/moused start $i
+ fi
+ done
+
+ # Start the delayed services after the login is up
+ (sleep 5; nice /bin/sh /etc/rc.delay "$_rc_elem_done$preLoad")&
+else
+ # Performing a normal startup
+
+ # Now that disks are mounted, for each dir in $local_startup
+ # search for init scripts that use the new rc.d semantics.
+ #
+
+ case ${local_startup} in
+ [Nn][Oo] | '') ;;
+ *) find_local_scripts_new ;;
+ esac
+
+ files=`rcorder ${skip} /etc/rc.d/* ${local_rc} 2>/dev/null`
+ for _rc_elem in ${files}; do
case "$_rc_elem_done" in
*" $_rc_elem "*) continue ;;
esac
run_rc_script ${_rc_elem} ${_boot}
-done
+ done
+
+fi
echo ''
date
173 etc/rc.conf.pcbsd
View
@@ -0,0 +1,173 @@
+# PC-BSD rc.conf file
+#
+# WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
+#
+# This file *will* be overwritten during upgrades
+# Place your local changes & overrides into /etc/rc.conf
+#
+# WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
+###########################################################
+
+# Defaults for TrueOS servers
+if [ -e "/etc/defaults/trueos" ] ; then
+
+ # FSCK Enhancements
+ fsck_y_enable="YES"
+
+ # Enable pbid
+ pbid_enable="YES"
+
+ # Enable the Warden
+ warden_enable="YES"
+
+ # Load the following kernel modules
+ kld_list="libiconv libmchain msdosfs_iconv sem ntfs ntfs_iconv udf udf_iconv ext2fs pefs xfs reiserfs smbfs fdescfs linsysfs"
+
+ # Enable ntpd
+ ntpd_enable="YES"
+ ntpd_sync_on_start="YES"
+
+ # Enable IPFW for Warden
+ firewall_enable="YES"
+ firewall_type="open"
+
+ # Build linker.hints files with kldxref(8)
+ # Overwrite old linker.hints at boot
+ kldxref_enable="YES"
+ kldxref_clobber="YES"
+
+ # Enable the crash-reporter for textdumps
+ ix_textdump_enable="YES"
+ ix_diagnose_enable="YES"
+fi
+
+# Defaults for PC-BSD desktops
+if [ -e "/etc/defaults/pcbsd" ] ; then
+
+ background_dhclient="YES"
+ hostname="pcbsd"
+ compat5x_enable="YES"
+ sshd_enable="NO"
+ devd_enable="YES"
+ devfs_system_ruleset="devfsrules_common"
+ ldconfig_paths="/usr/lib/compat /usr/local/lib /usr/local/kde4/lib /usr/local/lib/compat/pkg"
+
+ # Disable Sendmail by default
+ sendmail_enable="NONE"
+ sendmail_submit_enable="NO"
+ sendmail_outbound_enable="NO"
+ sendmail_msp_queue_enable="NO"
+
+ #Enable samba server
+ samba_enable="YES"
+ winbindd_enable="YES"
+
+ # Disable LPD
+ lpd_enable="NO"
+
+ # Enable CUPS
+ cupsd_enable="YES"
+ linux_enable="YES"
+
+ # FSCK Enhancements
+ fsck_y_enable="YES"
+
+ # powerd: adaptive speed while on AC power, adaptive while on battery power
+ powerd_enable="YES"
+ powerd_flags="-a hiadaptive -b adaptive" # set CPU frequency
+
+ # enable HAL / DBUS
+ dbus_enable="YES"
+ hald_enable="YES"
+
+ # Enable the firewall
+ pf_rules="/etc/pf.conf"
+ pf_enable="YES"
+ pf_flags=""
+
+ # Enable sound-support
+ mixer_enable="YES"
+
+ # Enable avahi_daemon
+ avahi_daemon_enable="YES"
+
+ # Start the swapexd daemon
+ swapexd_enable="YES"
+
+ # Enable IPV6 support
+ ipv6_activate_all_interfaces="YES"
+
+ # Enable BSDStats
+ bsdstats_enable="YES"
+
+ # Enable webcamd
+ webcamd_enable="YES"
+
+ # Disable writing syslogs to remote devices by default
+ syslogd_flags="-c -ss"
+
+ # Enable pbid
+ pbid_enable="YES"
+
+ # Enable the gdm display manager
+ gdm_enable="YES"
+
+ # Enable BlueTooth
+ hcsecd_enable="YES"
+ sdpd_enable="YES"
+
+ # Load the following kernel modules
+ kld_list="libiconv libmchain msdosfs_iconv if_bwn if_bwi bwi_v3_ucode bwn_v4_ucode runfw ng_ubt cuse4bsd sem ntfs ntfs_iconv udf udf_iconv ext2fs mmc mmcsd scd geom_uzip pefs xfs reiserfs smbfs fdescfs linsysfs iwn4965fw iwn1000fw iwn5000fw iwn5150fw iwn6000fw iwn6000g2afw iwn6000g2bfw iwn6050fw acpi_video"
+
+ # Clean out temporary files.
+ clear_tmp_enable="YES"
+ clean_tmp_X="YES"
+
+ # Run the pcbsd init service
+ pcbsdinit_enable="YES"
+
+ # Enable anacron
+ anacron_enable="YES"
+
+ # Enable fusefs
+ fusefs_enable="YES"
+
+ # Enable volmand
+ volmand_enable="YES"
+
+ # Enable pefs
+ pefs_enable="YES"
+
+ # Enable moused
+ moused_enable="YES"
+
+ # Enable fast-booting
+ fastboot_enable="YES"
+ fastboot_earlyrc="/etc/rc.d/moused /usr/local/etc/rc.d/pefs /usr/local/etc/rc.d/dbus /usr/local/etc/rc.d/hald /usr/local/etc/rc.d/gdm"
+
+ # Enable the Warden
+ warden_enable="YES"
+
+ # Enable fail2ban
+ fail2ban_enable="YES"
+
+ # Enable uhidd
+ uhidd_enable="YES"
+
+ # Enable ntpd
+ ntpd_enable="YES"
+ ntpd_sync_on_start="YES"
+
+ # Enable IPFW for Warden
+ firewall_enable="YES"
+ firewall_type="open"
+
+ # Build linker.hints files with kldxref(8)
+ # Overwrite old linker.hints at boot
+ kldxref_enable="YES"
+ kldxref_clobber="YES"
+
+ # Enable the crash-reporter for textdumps
+ ix_textdump_enable="YES"
+ ix_diagnose_enable="YES"
+fi
98 etc/rc.delay
View
@@ -0,0 +1,98 @@
+#!/bin/sh
+#
+# Copyright (c) 2000-2004 The FreeBSD Project
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)rc 5.27 (Berkeley) 6/5/91
+# $FreeBSD$
+#
+
+# Delayed system startup script run by /etc/rc after bootup
+# Output and error are redirected to /var/log/rc_delay.log
+
+# Note that almost all of the user-configurable behavior is no longer in
+# this file, but rather in /etc/defaults/rc.conf. Please check that file
+# first before contemplating any changes here. If you do need to change
+# this file for some reason, we would like to know about it.
+
+stty status '^T'
+
+# Set shell to ignore SIGINT (2), but not children;
+# shell catches SIGQUIT (3) and returns to single user.
+#
+trap : 2
+trap "echo 'Boot interrupted'; exit 1" 3
+
+HOME=/
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+export HOME PATH
+
+autoboot=yes
+_boot="faststart"
+rc_fast=yes # run_rc_command(): do fast booting
+_log="/var/log/rc_delay.log"
+echo "Starting delayed services `date`" > $_log
+
+dlv=`/sbin/sysctl -n vfs.nfs.diskless_valid 2> /dev/null`
+if [ ${dlv:=0} -ne 0 -o -f /etc/diskless ]; then
+ sh /etc/rc.initdiskless
+fi
+
+# Run these after determining whether we are booting diskless in order
+# to minimize the number of files that are needed on a diskless system,
+# and to make the configuration file variables available to rc itself.
+#
+. /etc/rc.subr
+load_rc_config 'XXX'
+
+skip="-s nostart"
+if [ `/sbin/sysctl -n security.jail.jailed` -eq 1 ]; then
+ skip="$skip -s nojail"
+ if [ "$early_late_divider" = "FILESYSTEMS" ]; then
+ early_late_divider=NETWORKING
+ fi
+fi
+
+unset files local_rc
+_rc_elem_done="$1"
+
+# Now that disks are mounted, for each dir in $local_startup
+# search for init scripts that use the new rc.d semantics.
+#
+case ${local_startup} in
+[Nn][Oo] | '') ;;
+*) find_local_scripts_new ;;
+esac
+
+files=`rcorder ${skip} /etc/rc.d/* ${local_rc} 2>/dev/null`
+for _rc_elem in ${files}; do
+ case "$_rc_elem_done" in
+ *" $_rc_elem "*) continue ;;
+ esac
+
+ run_rc_script ${_rc_elem} ${_boot} >>${_log}
+done
+
+echo "Finished starting delayed services `date`" >> $_log
+exit 0
11 etc/rc.resume
View
@@ -24,7 +24,7 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# $FreeBSD$
+# $FreeBSD: releng/9.1/etc/rc.resume 232083 2012-02-23 22:10:49Z jkim $
#
# sample run command file for APM Resume Event
@@ -55,4 +55,13 @@ fi
/usr/bin/logger -t $subsystem resumed at `/bin/date +'%Y%m%d %H:%M:%S'`
/bin/sync && /bin/sync && /bin/sync
+# Check if we need to resume wpa_supp
+ifconfig | grep -q 'wlan[0-9]:'
+if [ $? -eq 0 ] ; then
+ /usr/sbin/wpa_cli reassociate
+fi
+
+# Restart moused to fix suspend
+/etc/rc.d/moused restart
+
exit 0
4 etc/rc.subr
View
@@ -668,9 +668,7 @@ run_rc_command()
if [ -n "${rc_quiet}" ]; then
return 0
fi
- echo -n "Cannot '${rc_arg}' $name. Set ${rcvar} to "
- echo -n "YES in /etc/rc.conf or use 'one${rc_arg}' "
- echo "instead of '${rc_arg}'."
+ echo "Will not '${rc_arg}' $name because ${rcvar} is NO."
return 0
fi
fi
2  etc/root/dot.cshrc
View
@@ -15,7 +15,7 @@ alias ll ls -lAF
# A righteous umask
umask 22
-set path = (/sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin $HOME/bin)
+set path = (/usr/local/share/pcbsd/bin /sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin $HOME/bin)
setenv EDITOR vi
setenv PAGER more
2  etc/root/dot.profile
View
@@ -1,6 +1,6 @@
# $FreeBSD$
#
-PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:~/bin
+PATH=/usr/local/share/pcbsd/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:~/bin
export PATH
HOME=/root
export HOME
44 etc/sysctl.conf
View
@@ -1,4 +1,4 @@
-# $FreeBSD$
+# $FreeBSD: src/etc/sysctl.conf,v 1.8 2003/03/13 18:43:50 mux Exp $
#
# This file is read when going to multi-user and its contents piped thru
# ``sysctl'' to adjust kernel values. ``man 5 sysctl.conf'' for details.
@@ -7,3 +7,45 @@
# Uncomment this to prevent users from seeing information about processes that
# are being run under another UID.
#security.bsd.see_other_uids=0
+
+# Disable coredump
+kern.coredump=0
+
+# Up the maxfiles to 4x default
+kern.maxfiles=49312
+
+# Allow users to mount CD's
+vfs.usermount=1
+
+# Autodetect the most recent sound card. Uncomment for Digital output / USB
+#hw.snd.default_auto=1
+
+# Allow pinging in jails
+security.jail.allow_raw_sockets=1
+
+# Required for postgres
+security.jail.sysvipc_allowed=1
+
+# Required for smb
+security.jail.mount_allowed=1
+
+# Solves permission problems for some ports
+security.jail.chflags_allowed=1
+
+# Disable the system speaker
+hw.syscons.bell=0
+
+# Tune for desktop usage
+kern.sched.preempt_thresh=224
+
+# Enable for proper lagg failover
+#net.link.lagg.failover_rx_all=1
+
+# Enable shm_allow_removed
+kern.ipc.shm_allow_removed=1
+
+# Speed up the shutdown process
+kern.shutdown.poweroff_delay=500
+
+# Since we boot from GRUB we will set kern.bootfile manually
+kern.bootfile=/boot/kernel/kernel
1  lib/libpam/modules/modules.inc
View
@@ -19,6 +19,7 @@ MODULES += pam_login_access
MODULES += pam_nologin
MODULES += pam_opie
MODULES += pam_opieaccess
+MODULES += pam_pefs
MODULES += pam_passwdqc
MODULES += pam_permit
MODULES += pam_radius
27 lib/libpam/modules/pam_pefs/Makefile
View
@@ -0,0 +1,27 @@
+# PAM module for pefs
+# $FreeBSD$
+
+SYS= ${.CURDIR}/../../../../sys
+PEFSDIR= ${.CURDIR}/../../../../sbin/pefs
+
+LIB= pam_pefs
+MAN= pam_pefs.8
+SRCS= pam_pefs.c
+SRCS+= pefs_key.c pefs_keychain.c pefs_subr.c
+SRCS+= hmac.c
+SRCS+= pkcs5v2.c
+SRCS+= rijndael-api.c rijndael-api-fst.c rijndael-alg-fst.c
+SRCS+= sha2.c
+
+CFLAGS+= -I${PEFSDIR}
+CFLAGS+= -I${SYS}
+WARNS?= 2
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.include <bsd.lib.mk>
+
+.PATH: ${PEFSDIR}
+.PATH: ${SYS}/crypto/hmac ${SYS}/crypto/pkcs5v2 ${SYS}/crypto/rijndael
+.PATH: ${SYS}/crypto/sha2
147 lib/libpam/modules/pam_pefs/pam_pefs.8
View
@@ -0,0 +1,147 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+.\" Copyright (c) 2009 Gleb Kurtsou
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by ThinkSec AS and
+.\" NAI Labs, the Security Research Division of Network Associates, Inc.
+.\" under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+.\" DARPA CHATS research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 1, 2009
+.Dt PAM_PEFS 8
+.Os
+.Sh NAME
+.Nm pam_pefs
+.Nd pefs PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_pefs
+.Op Ar options
+.Sh DESCRIPTION
+The
+pefs
+authentication service module for PAM,
+.Nm
+provides functionality for two PAM categories:
+authentication
+and session management.
+In terms of the
+.Ar module-type
+parameter, they are the
+.Dq Li auth
+and
+.Dq Li session
+features.
+.Pp
+Module expects pefs file system to be mounted on user home directory
+and fails otherwise.
+.Ss Pefs Authentication Module
+The
+pefs
+authentication component
+provides a function to verify the identity of a user
+.Pq Fn pam_sm_authenticate ,
+by prompting the user for a passphrase and verifying that it exists in
+pefs key chain database.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm use_first_pass
+If the authentication module
+is not the first in the stack,
+and a previous module
+obtained the user's password,
+that password is used
+to authenticate the user.
+If this fails,
+the authentication module returns failure
+without prompting the user for a password.
+This option has no effect
+if the authentication module
+is the first in the stack,
+or if no previous modules
+obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option,
+except that if the previously obtained password fails,
+the user is prompted for another password.
+.It Cm ignore_missing
+Accept any passphrase provided by the user.
+This option is used not to authenticate user, but to preserve keys that
+should be added to pefs file system by session management module.
+Option is incompatible with
+.Cm try_first_pass
+option and should be used with
+.Cm use_first_pass
+option.
+.It Cm delkeys
+Remove keys at the end of last session.
+Module tracks the number of concurrent sessions, removing all keys from
+file system when session count reaches zero.
+.El
+.Ss Pefs Session Management Module
+The
+pefs
+session management component
+provides functions to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+The
+.Fn pam_sm_open_session
+function adds key or key chain decrypted during the authentication phase
+to the pefs file system mounted on user home directory.
+.Sh FILES
+.Bl -tag -width ".Pa $HOME/.pefs.conf" -compact
+.It Pa $HOME/.pefs.conf
+pefs configuration file
+.It Pa $HOME/.pefs.db
+pefs key chain database file
+.El
+.Sh SEE ALSO
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Xr pefs 8
+.Sh AUTHORS
+The
+.Nm
+module was written by
+.An -nosplit
+.An "Gleb Kurtsou" Aq gk@FreeBSD.org .
+.Sh BUGS
+.Fn pam_sm_close_session
+function
+doesn't delete keys added during by
+.Fn pam_sm_open_session .
526 lib/libpam/modules/pam_pefs/pam_pefs.c
View
@@ -0,0 +1,526 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2009 Gleb Kurtsou <gleb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <libutil.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+#include <security/openpam.h>
+
+#include <fs/pefs/pefs.h>
+
+#include "pefs_ctl.h"
+#include "pefs_keychain.h"
+
+#define PEFS_OPT_IGNORE_MISSING "ignore_missing"
+#define PEFS_OPT_DELKEYS "delkeys"
+
+#define PAM_PEFS_KEYS "pam_pefs_keys"
+
+#define PEFS_SESSION_DIR "/var/run/pefs"
+#define PEFS_SESSION_DIR_MODE 0700
+#define PEFS_SESSION_FILE_MODE 0600
+#define PEFS_SESSION_FILE_FLAGS \
+ (O_RDWR | O_NONBLOCK | O_CREAT | O_EXLOCK)
+
+static int pam_pefs_debug;
+
+void
+pefs_warn(const char *fmt, ...)
+{
+ static const char *label = "pam_pefs: ";
+ char buf[BUFSIZ];
+ va_list ap;
+
+ if (pam_pefs_debug == 0)
+ return;
+
+ va_start(ap, fmt);
+ if (strlen(fmt) + sizeof(label) >= sizeof(buf)) {
+ vsyslog(LOG_DEBUG, fmt, ap);
+ } else {
+ strlcpy(buf, label, sizeof(buf));
+ strlcat(buf, fmt, sizeof(buf));
+ vsyslog(LOG_DEBUG, buf, ap);
+ }
+ va_end(ap);
+}
+
+static int
+flopen_retry(const char *filename)
+{
+ int fd, try;
+
+ for (try = 1; try <= 1024; try *= 2) {
+ fd = flopen(filename, PEFS_SESSION_FILE_FLAGS,
+ PEFS_SESSION_FILE_MODE);
+ if (fd != -1)
+ return (fd);
+ else if (errno != EWOULDBLOCK)
+ return (-1);
+ // Exponential back-off up to 1 second
+ usleep(try * 1000000 / 1024);
+ }
+ errno = ETIMEDOUT;
+ return (-1);
+}
+
+static int
+pefs_session_count_incr(const char *user, bool incr)
+{
+ struct stat sb;
+ struct timespec tp_uptime, tp_now;
+ ssize_t offset;
+ int fd, total = 0;
+ char filename[MAXPATHLEN], buf[16];
+ const char *errstr;
+
+ snprintf(filename, sizeof(filename), "%s/%s", PEFS_SESSION_DIR, user);
+
+ if (lstat(PEFS_SESSION_DIR, &sb) == -1) {
+ if (errno != ENOENT) {
+ pefs_warn("unable to access session directory %s: %s",
+ PEFS_SESSION_DIR, strerror(errno));
+ return (-1);
+ }
+ if (mkdir(PEFS_SESSION_DIR, PEFS_SESSION_DIR_MODE) == -1) {
+ pefs_warn("unable to create session directory %s: %s",
+ PEFS_SESSION_DIR, strerror(errno));
+ return (-1);
+ }
+ } else if (!S_ISDIR(sb.st_mode)) {
+ pefs_warn("%s is not a directory", PEFS_SESSION_DIR);
+ return (-1);
+ }
+
+ if ((fd = flopen_retry(filename)) == -1) {
+ pefs_warn("unable to create session counter file %s: %s",
+ filename, strerror(errno));
+ return (-1);
+ }
+
+ if ((offset = pread(fd, buf, sizeof(buf) - 1, 0)) == -1) {
+ pefs_warn("unable to read from the session counter file %s: %s",
+ filename, strerror(errno));
+ close(fd);
+ return (-1);
+ }
+ buf[offset] = '\0';
+ if (offset != 0) {
+ total = strtonum(buf, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ pefs_warn("corrupted session counter file: %s: %s",
+ filename, errstr);
+ }
+
+ /*
+ * Determine if this is the first increment of the session file.
+ *
+ * It is considered the first increment if the session file has not
+ * been modified since the last boot time.
+ */
+ if (incr && total > 0) {
+ if (fstat(fd, &sb) == -1) {
+ pefs_warn("unable to access session counter file %s: %s",
+ filename, strerror(errno));
+ close(fd);
+ return (-1);
+ }
+ /*
+ * Check is messy and will fail if wall clock isn't monotonical
+ * (e.g. because of ntp, DST, leap seconds)
+ */
+ clock_gettime(CLOCK_REALTIME_FAST, &tp_now);
+ clock_gettime(CLOCK_UPTIME_FAST, &tp_uptime);
+ if (sb.st_mtime < tp_now.tv_sec - tp_uptime.tv_sec) {
+ pefs_warn("stale session counter file: %s",
+ filename);
+ total = 0;
+ }
+ }
+
+ lseek(fd, 0L, SEEK_SET);
+ ftruncate(fd, 0L);
+
+ total += incr ? 1 : -1;
+ if (total < 0) {
+ pefs_warn("corrupted session counter file: %s",
+ filename);
+ total = 0;
+ } else
+ pefs_warn("%s: session count %d", user, total);
+
+ buf[0] = '\0';
+ snprintf(buf, sizeof(buf), "%d", total);
+ pwrite(fd, buf, strlen(buf), 0);
+ close(fd);
+
+ return (total);
+}
+
+static int
+pam_pefs_checkfs(const char *homedir)
+{
+ char fsroot[MAXPATHLEN];
+ int error;
+
+ error = pefs_getfsroot(homedir, 0, fsroot, sizeof(fsroot));
+ if (error != 0) {
+ pefs_warn("file system is not mounted: %s", homedir);
+ return (PAM_USER_UNKNOWN);
+ } if (strcmp(fsroot, homedir) != 0) {
+ pefs_warn("file system is not mounted on home dir: %s", fsroot);
+ return (PAM_USER_UNKNOWN);
+ }
+
+ return (PAM_SUCCESS);
+}
+
+/*
+ * Perform key lookup in ~/.pefs;
+ * returns PAM_AUTH_ERR if and only if key wasn't found in database.
+ */
+static int
+pam_pefs_getkeys(struct pefs_keychain_head *kch,
+ const char *homedir, const char *passphrase, int chainflags)
+{
+ struct pefs_xkey k;
+ struct pefs_keyparam kp;
+ int error;
+
+ pefs_keyparam_create(&kp);
+ pefs_keyparam_init(&kp, homedir);
+
+ error = pefs_key_generate(&k, passphrase, &kp);
+ if (error != 0)
+ return (PAM_SERVICE_ERR);
+
+ error = pefs_keychain_get(kch, homedir, chainflags, &k);
+ bzero(&k, sizeof(k));
+ if (error != 0)
+ return (error == PEFS_ERR_NOENT ? PAM_AUTH_ERR :
+ PAM_SERVICE_ERR);
+
+ return (PAM_SUCCESS);
+}
+
+static int
+pam_pefs_addkeys(const char *homedir, struct pefs_keychain_head *kch)
+{
+ struct pefs_keychain *kc;
+ int fd;
+
+ fd = open(homedir, O_RDONLY);
+ if (fd == -1) {
+ pefs_warn("cannot open homedir %s: %s",
+ homedir, strerror(errno));
+ return (PAM_USER_UNKNOWN);
+ }
+
+ TAILQ_FOREACH(kc, kch, kc_entry) {
+ if (ioctl(fd, PEFS_ADDKEY, &kc->kc_key) == -1) {
+ pefs_warn("cannot add key: %s: %s",
+ homedir, strerror(errno));
+ break;
+ }
+ }
+ close(fd);
+
+ return (PAM_SUCCESS);
+}
+
+static int
+pam_pefs_delkeys(const char *homedir)
+{
+ struct pefs_xkey k;
+ int fd;
+
+ fd = open(homedir, O_RDONLY);
+ if (fd == -1) {
+ pefs_warn("cannot open homedir %s: %s",
+ homedir, strerror(errno));
+ return (PAM_USER_UNKNOWN);
+ }
+
+ bzero(&k, sizeof(k));
+ while (1) {
+ if (ioctl(fd, PEFS_GETKEY, &k) == -1)
+ break;
+
+ if (ioctl(fd, PEFS_DELKEY, &k) == -1) {
+ pefs_warn("cannot del key: %s: %s",
+ homedir, strerror(errno));
+ k.pxk_index++;
+ }
+ }
+ close(fd);
+
+ return (PAM_SUCCESS);
+}
+
+static void
+pam_pefs_freekeys(pam_handle_t *pamh __unused, void *data, int pam_err __unused)
+{
+ struct pefs_keychain_head *kch = data;
+
+ pefs_keychain_free(kch);
+ free(kch);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct pefs_keychain_head *kch;
+ struct passwd *pwd;
+ const char *passphrase, *user;
+ const void *item;
+ int pam_err, canretry, chainflags;
+
+ /* Get user name and home directory */
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+ if (pwd->pw_dir == NULL)
+ return (PAM_AUTH_ERR);
+
+ pam_pefs_debug = (openpam_get_option(pamh, PAM_OPT_DEBUG) != NULL);
+
+ chainflags = PEFS_KEYCHAIN_USE;
+ if (openpam_get_option(pamh, PEFS_OPT_IGNORE_MISSING) != NULL)
+ chainflags = PEFS_KEYCHAIN_IGNORE_MISSING;
+
+ canretry = (pam_get_item(pamh, PAM_AUTHTOK, &item) == PAM_SUCCESS &&
+ item != NULL && chainflags != PEFS_KEYCHAIN_IGNORE_MISSING);
+
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ /*
+ * Check to see if the passwd db is available, avoids asking for
+ * password if we cannot even validate it.
+ */
+ pam_err = pam_pefs_checkfs(pwd->pw_dir);
+ openpam_restore_cred(pamh);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+
+retry:
+ /* Get passphrase */
+ pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
+ &passphrase, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ if (*passphrase != '\0') {
+ kch = calloc(1, sizeof(*kch));
+ if (kch == NULL)
+ return (PAM_SYSTEM_ERR);
+
+ /* Switch to user credentials */
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ pam_err = pam_pefs_getkeys(kch, pwd->pw_dir, passphrase,
+ chainflags);
+ if (pam_err == PAM_SUCCESS)
+ pam_set_data(pamh, PAM_PEFS_KEYS, kch,
+ pam_pefs_freekeys);
+ else
+ free(kch);
+
+ /* Switch back to arbitrator credentials */
+ openpam_restore_cred(pamh);
+ } else
+ pam_err = PAM_AUTH_ERR;
+
+ /*
+ * If we tried an old token and didn't get anything, and
+ * try_first_pass was specified, try again after prompting the
+ * user for a new passphrase.
+ */
+ if (pam_err == PAM_AUTH_ERR && canretry != 0 &&
+ openpam_get_option(pamh, "try_first_pass") != NULL) {
+ pam_set_item(pamh, PAM_AUTHTOK, NULL);
+ canretry = 0;
+ goto retry;
+ }
+
+ return (pam_err);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct pefs_keychain_head *kch = NULL;
+ struct passwd *pwd;
+ const char *user;
+ int pam_err, opt_delkeys;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+ if (pwd->pw_dir == NULL)
+ return (PAM_SYSTEM_ERR);
+
+ pam_pefs_debug = (openpam_get_option(pamh, PAM_OPT_DEBUG) != NULL);
+ opt_delkeys = (openpam_get_option(pamh, PEFS_OPT_DELKEYS) != NULL);
+
+ pam_err = pam_get_data(pamh, PAM_PEFS_KEYS,
+ (const void **)(void *)&kch);
+ if (pam_err != PAM_SUCCESS || kch == NULL || TAILQ_EMPTY(kch)) {
+ pam_err = PAM_SUCCESS;
+ opt_delkeys = 0;
+ goto out;
+ }
+
+ /* Switch to user credentials */
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ goto out;
+
+ pam_err = pam_pefs_checkfs(pwd->pw_dir);
+ if (pam_err != PAM_SUCCESS) {
+ openpam_restore_cred(pamh);
+ pam_err = PAM_SUCCESS;
+ opt_delkeys = 0;
+ goto out;
+ }
+
+ pam_err = pam_pefs_addkeys(pwd->pw_dir, kch);
+
+ /* Switch back to arbitrator credentials */
+ openpam_restore_cred(pamh);
+
+out:
+ /* Remove keys from memory */
+ if (kch != NULL)
+ pefs_keychain_free(kch);
+
+ /* Increment login count */
+ if (pam_err == PAM_SUCCESS && opt_delkeys)
+ pefs_session_count_incr(user, true);
+
+ return (pam_err);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ const char *user;
+ int pam_err, opt_delkeys;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+ if (pwd->pw_dir == NULL)
+ return (PAM_SYSTEM_ERR);
+
+ pam_pefs_debug = (openpam_get_option(pamh, PAM_OPT_DEBUG) != NULL);
+ opt_delkeys = (openpam_get_option(pamh, PEFS_OPT_DELKEYS) != NULL);
+ if (!opt_delkeys)
+ return PAM_SUCCESS;
+
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pam_err = pam_pefs_checkfs(pwd->pw_dir);
+ openpam_restore_cred(pamh);
+ if (pam_err != PAM_SUCCESS)
+ return (PAM_SUCCESS);
+
+ /* Decrease login count and remove keys if at zero */
+ pam_err = PAM_SUCCESS;
+ if (pefs_session_count_incr(user, false) == 0) {
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pam_err = pam_pefs_delkeys(pwd->pw_dir);
+ openpam_restore_cred(pamh);
+ }
+
+ return (pam_err);
+}
+
+PAM_MODULE_ENTRY("pam_pefs");
1  sbin/Makefile
View
@@ -58,6 +58,7 @@ SUBDIR=adjkerntz \
newfs_msdos \
nfsiod \
nos-tun \
+ pefs \
ping \
rcorder \
reboot \
24 sbin/pefs/Makefile
View
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+SYS= ${.CURDIR}/../../sys
+.PATH: ${SYS}/crypto/hmac ${SYS}/crypto/pkcs5v2
+.PATH: ${SYS}/crypto/rijndael ${SYS}/crypto/sha2
+
+PROG= pefs
+SRCS= pefs_ctl.c pefs_key.c pefs_keychain.c pefs_subr.c
+SRCS+= hmac.c
+SRCS+= pkcs5v2.c
+SRCS+= rijndael-api.c rijndael-api-fst.c rijndael-alg-fst.c
+SRCS+= sha2.c
+
+MAN= pefs.8
+
+CFLAGS+=-I${SYS}
+WARNS?= 2
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+BINDIR?= /sbin
+
+.include <bsd.prog.mk>
466 sbin/pefs/pefs.8
View
@@ -0,0 +1,466 @@
+.\" Copyright (c) 2005-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+.\" Copyright (c) 2009 Gleb Kurtsou
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 1, 2009
+.Dt PEFS 8
+.Os
+.Sh NAME
+.Nm pefs
+.Nd configure pefs file systems
+.Sh SYNOPSIS
+.Nm
+.Cm mount
+.Op Fl o Ar options
+.Op Ar from filesystem
+.Nm
+.Cm unmount
+.Op Fl fv
+.Ar filesystem
+.Pp
+.Nm
+.Cm addkey
+.Op Fl cCpv
+.Op Fl a Ar alg
+.Op Fl i Ar iterations
+.Op Fl j Ar passfile
+.Op Fl k Ar keyfile
+.Ar filesystem
+.Nm
+.Cm delkey
+.Op Fl cCpv
+.Op Fl i Ar iterations
+.Op Fl j Ar passfile
+.Op Fl k Ar keyfile
+.Ar filesystem
+.Nm
+.Cm flushkeys
+.Ar filesystem
+.Nm
+.Cm getkey
+.Op Fl t
+.Ar file
+.Nm
+.Cm setkey
+.Op Fl cCpvx
+.Op Fl a Ar alg
+.Op Fl i Ar iterations
+.Op Fl j Ar passfile
+.Op Fl k Ar keyfile
+.Ar directory
+.Nm
+.Cm showkeys
+.Op Fl t
+.Ar filesystem
+.Pp
+.Nm
+.Cm addchain
+.Op Fl fpPvZ
+.Op Fl a Ar alg
+.Op Fl i Ar iterations
+.Op Fl j Ar passfile
+.Op Fl k Ar keyfile
+.Op Fl A Ar alg
+.Op Fl I Ar iterations
+.Op Fl J Ar passfile
+.Op Fl K Ar keyfile
+.Ar filesystem
+.Nm
+.Cm delchain
+.Op Fl fFpv
+.Op Fl i Ar iterations
+.Op Fl j Ar passfile
+.Op Fl k Ar keyfile
+.Ar filesystem
+.Nm
+.Cm randomchain
+.Op Fl fv
+.Op Fl i Ar iterations
+.Op Fl j Ar passfile
+.Op Fl k Ar keyfile
+.Ar filesystem
+.Nm
+.Cm showchains
+.Op Fl fp
+.Op Fl i Ar iterations
+.Op Fl j Ar passfile
+.Op Fl k Ar keyfile
+.Ar filesystem
+.Pp
+.Nm
+.Cm showalgs
+.Sh DESCRIPTION
+The
+.Nm
+utility is the user interface for configuring stacked cryptographic file system.
+.Pp
+The following is a list of the most important file system features:
+.Bl -bullet -offset indent -compact
+.It
+Kernel level file system, no user level daemons needed.
+Transparently runs on top of existing file systems.
+.It
+Random per file tweak value used for encryption, which guaranties different
+cipher texts for the same encrypted files.
+.It
+Saves metadata only in encrypted file name, but not in file itself.
+.It
+Supports arbitrary number of keys per file system, default directory key,
+mixing files encrypted with different keys in same directory.
+.It
+Allows defining key chains, can be used to add/delete several keys by
+specifying only master key.
+.It
+Uses modern cryptographic algorithms: AES and Camellia in XTS mode,
+PKCS#5v2 and HKDF for key generation.
+.El
+.Pp
+First argument of
+.Nm
+utility indicates the command to be performed (see the
+.Sx COMMAND OPTIONS
+section for information on options):
+.Bl -tag -width indent
+.It Cm mount
+Mount file system.
+Encryption keys should be specified separately after mounting the file system.
+If no agrumnt specified prints all mounted
+.Nm
+file systems.
+See
+.Xr mount 8
+for more information.
+.It Cm unmount Ar filesystem
+Unmount
+.Ar filesystem .
+.Fl f
+and
+.Fl v
+options can be specified to force unmount or enable verbose mode respectively.
+See
+.Xr umount 8
+for more information.
+.It Cm addkey Ar filesystem
+Add key to the
+.Ar filesystem
+.It Cm delkey Ar filesystem
+Delete key from
+.Ar filesystem .
+Command doesn't accept
+.Fl a Ar alg
+argument because the key fingerprint generated from the key doesn't depend on
+encryption algorithm.
+.It Cm getkey Ar file
+Print fingerprint of the key used by
+.Ar file .
+.It Cm flushkeys Ar filesystem
+Delete all keys from
+.Ar filesystem .
+After the command all opened files would become unavailable.
+.It Cm setkey Ar directory
+Change default key for the
+.Ar directory .
+Default key is used as a new key for files and directories created in the
+.Ar directory .
+Technically just a rename takes place on underlaying file system.
+Keys for entries in the
+.Ar directory
+are not changed and no data is re-encrypted with new key.
+.Fl x
+option can be used to add a new key to file system if it isn't found.
+.It Cm showkeys Ar filesystem
+Print fingerprints if all active keys.
+.It Cm addchain Ar filesystem
+Add a new key chain element.
+Element consists of parent and child keys.
+Parent key is defined by
+.Fl a , Fl i
+and
+.Fl p
+options and child key by equivalent
+.Fl A , Fl I
+and
+.Fl P
+options.
+Element consisting only of a parent key can be constructed by specifying
+.Fl Z
+option.
+.Fl f
+option disables file system type checks making manipulation on key chains
+possible without mounting
+.Nm
+file system.
+See
+.Sx KEY CHAINS
+section for more information.
+.It Cm delchain Ar filesystem
+Delete key chain element defined by parent key.
+Use
+.Fl F
+option to delete all elements from the chain.
+.It Cm randomchain Ar filesystem
+Create random key chain elements.
+Minimum and maximum number of elements is controlled by
+.Fl n Ar min
+and
+.Fl N Ar max
+options.
+The command can be used to add false elements into key chain database, which
+would complicate analysis of key usage patterns by attacker.
+It can also be used be achieve some approximation of deniable encryption.
+.It Cm showchains Ar filesystem
+Print all elements of the key chain staring with given parent key.
+.It Cm showalgs
+Print list of all supported algorithms.
+.El
+.Pp
+.Ss COMMAND OPTIONS
+The following options are available when invoking
+.Nm :
+.Bl -tag -width indent
+.It Fl a Ar alg
+Encryption algorithm to use.
+Use
+.Cm showalgs
+command to get list of supported algorithms.
+The default algorithm is AES-128.
+.It Fl A Ar alg
+Specifies algorithm for the secondary/child key.
+.It Fl c
+Forces key chain lookup.
+Error returned if chain is not found for the key.
+By default lookup errors are silently ignored.
+.It Fl C
+Disables key chain lookup.
+By default if chain is found, keys it consists of are also used for operation.
+.It Fl i Ar iterations
+Number of
+.Ar iterations
+to use with PKCS#5v2.
+If this option is not specified default value of 50000 is used.
+.It Fl I Ar iterations
+Specifies number of
+.Ar iterations
+for the secondary/child key.
+.It Fl j Ar passfile
+Specifies a file which contains the passphrase.
+If
+.Ar passfile
+is given as -, standard input will be used.
+Only the first line (excluding new-line character) is taken from the given
+file.
+This argument can be specified multiple times, which has the effect of
+reassembling a single passphrase split across multiple files.
+Cannot be combined with the
+.Fl p
+option.
+.It Fl J Ar passfile
+Specifies a file which contains the passphrase for secondary/child key.
+Cannot be combined with
+.Fl P
+option.
+.It Fl f
+Forces operation.
+Use to force
+.Cm unmount
+or to disable file system type check for key chain commands.
+.It Fl F
+Used with
+.Cm delchain
+command to delete all elements from a key chain.
+.It Fl k Ar keyfile
+Specifies a file which contains part of the key.
+If
+.Ar keyfile
+is given as -, standard input will be used.
+.It Fl K Ar keyfile
+Specifies a file which contains part of the secondary/child key.
+.It Fl o Ar options
+Mount options passed to
+.Xr mount 8
+utility.
+.It Fl p
+Do not ask for passphrase.
+.It Fl P
+Do not ask for passphrase for secondary/child key.
+.It Fl t
+Test-only mode.
+Do not perform actual operation but check if it can be performed.
+Usable for scripting.
+.It Fl v
+Verbose mode.
+.It Fl x
+Used with
+.Cm setkey
+command.
+Forces adding of the key if it is not specified for the file system.
+.It Fl Z
+Create chain with zero child key.
+Can be useful for
+.Cm addkey Fl c
+command to verify the key before adding it.
+.El
+.Pp
+.Ss KEY CHAINS
+Key chain consists of one or several elements.
+Each element is defined by a
+.Em parent key
+and a
+.Em child key .
+All elements are stored encrypted in a database file.
+.Pp
+Parent key fingerprint is used as an index to access child key in database.
+Chaining is achieved by reusing child key fingerprint as next index.
+.Pp
+.Ss CONFIGURATION FILE
+In addition to command line options some options can be specified in per file
+system configuration file:
+.Em <filesystem>/.pefs.conf .
+.Em .pefs.conf
+is not a regular file, but a symbolic link.
+.Dq Li Name
+of the file referenced by the link consists of a list of options separated by
+colon.
+Supported option list is the following:
+.Bd -literal -offset indent
+.Em algorithm:iterations
+.Ed
+.Pp
+Note that key chain database entries already contain algorithm used, and
+expected use of the configuration file is to specify
+.Em iterations
+option for
+.Xr pam_pefs 8
+or default
+.Em algorithm ,
+if one adds/removes keys often without using key chain database.
+.Pp
+.Sh SYSCTL VARIABLES
+The following
+.Xr sysctl 8
+variables can be used to control the behavior of
+.Nm
+file systems or monitor
+them.
+.Bl -tag -width indent
+.It Va vfs.pefs.nodes
+Number of active nodes.
+Unlike
+.Xr nullfs 8
+.Nm
+doesn't recycle vnodes as early as possible, but expects kernel to recycle
+vnodes when necessary.
+.It Va vfs.pefs.dircache.enable
+Enable directory content caching.
+Content caching can only be enabled for file systems that are known to properly
+propagate changes to upper levels, and it's permanently disabled for the rest.
+When disabled directory cache subsystem is still used as a file name decryption
+cache for all underlying file systems.
+.It Va vfs.pefs.dircache.entries
+Number of entries in directory cache.
+Directory cache is mainly used as a file name decryption cache, but can also be
+used to cache directory content if underlying file system is known to propagate
+changes to upper levels properly.
+.It Va vfs.pefs.dircache.buckets
+Number of dircache hash table buckets.
+Value can be set as a kernel environment variable by specifying it in
+.Ar /boot/loader.conf
+file, or using
+.Xr kenv 1
+utility
+before loading
+.Nm
+kernel module.
+.El
+.Sh EXAMPLES
+Encrypting a directory:
+.Bd -literal -offset indent
+% mkdir ~/Private
+% pefs mount ~/Private ~/Private
+% pefs addkey ~/Private
+Enter passphrase:
+\&...
+% pefs unmount ~/Private
+.Ed
+.Pp
+In such setup one has to manually check if passphrase valid, because
+.Nm
+would accept any key for a file system.
+Key chaining can be used to verify keys:
+.Bd -literal -offset indent
+% mkdir ~/Private
+% pefs addchain -fZ ~/Private
+Enter parent key passphrase:
+Reenter parent key passphrase:
+% pefs mount ~/Private ~/Private
+% pefs addkey -c ~/Private
+Enter passphrase:
+\&...
+% pefs unmount ~/Private
+.Ed
+.Pp
+In the example key chain database file (~/Private/.pefs.db) is created on
+unencrypted underlying file.
+And
+.Cm addkey Fl c
+is used to force key verification.
+Key chain database file is not encrypted by
+.Nm ,
+but it's is internally encrypted by the utility and there should be no risk.
+.Pp
+Set default number of PKCS#5v2 iterations to 100000 for home directory not
+changing default algorithm:
+.Bd -literal -offset indent
+# make sure ~/ is not encrypted
+% ln -s :100000 ~/.pefs.conf
+.Ed
+.Pp
+.Sh DATA AUTHENTICATION
+.Nm
+provides no data integrity checking.
+Thus it's strongly advised to use additional data integrity checking tools.
+.Sh FILES
+.Bl -tag -width <filesystem>/.pefs.conf -compact
+.It Pa <filesystem>/.pefs.conf
+Configuration file (symbolic link).
+.It Pa <filesystem>/.pefs.db
+Key chain database file.
+.El
+.Sh SEE ALSO
+.Xr kenv 1 ,
+.Xr crypto 4 ,
+.Xr nullfs 5 ,
+.Xr geli 8 ,
+.Xr mount 8 ,
+.Xr sysctl 8
+.Xr umount 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Fx x.0 .
+.Sh AUTHORS
+.An Gleb Kurtsou Aq gk@FreeBSD.org
1,173 sbin/pefs/pefs_ctl.c
View
@@ -0,0 +1,1173 @@
+/*-
+ * Copyright (c) 2009 Gleb Kurtsou <gleb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <readpassphrase.h>
+
+#include <fs/pefs/pefs.h>
+
+#include "pefs_ctl.h"
+#include "pefs_keychain.h"
+
+#define PATH_MOUNT "/sbin/mount"
+#define PATH_UMOUNT "/sbin/umount"
+#define PATH_DEVRANDOM "/dev/random"
+
+#define PEFS_KEY_PROMPT_DEFAULT "passphrase"
+
+static void pefs_usage(void);
+static void pefs_usage_alg(void);
+static int pefs_mount(int argc, char *argv[]);
+static int pefs_unmount(int argc, char *argv[]);
+static int pefs_addkey(int argc, char *argv[]);
+static int pefs_setkey(int argc, char *argv[]);
+static int pefs_delkey(int argc, char *argv[]);
+static int pefs_flushkeys(int argc, char *argv[]);
+static int pefs_addchain(int argc, char *argv[]);
+static int pefs_delchain(int argc, char *argv[]);
+static int pefs_randomchain(int argc, char *argv[]);
+static int pefs_showkeys(int argc, char *argv[]);
+static int pefs_getkey(int argc, char *argv[]);
+static int pefs_showchains(int argc, char *argv[]);
+static int pefs_showalgs(int argc, char *argv[]);
+
+typedef int (*command_func_t)(int argc, char **argv);
+typedef int (*keyop_func_t)(struct pefs_keychain_head *kch, int fd,
+ int verbose);
+
+struct command {
+ const char *name;
+ command_func_t func;
+};
+
+static struct command cmds[] = {
+ { "mount", pefs_mount },
+ { "unmount", pefs_unmount },
+ { "umount", pefs_unmount },
+ { "addkey", pefs_addkey },
+ { "setkey", pefs_setkey },
+ { "delkey", pefs_delkey },
+ { "flushkeys", pefs_flushkeys },
+ { "showkeys", pefs_showkeys },
+ { "getkey", pefs_getkey },
+ { "status", pefs_showkeys },
+ { "randomchain", pefs_randomchain },
+ { "addchain", pefs_addchain },
+ { "delchain", pefs_delchain },
+ { "showchains", pefs_showchains },
+ { "showalgs", pefs_showalgs },
+ { NULL, NULL },
+};
+
+void
+pefs_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
+
+static int
+checkargs_fs(int argc, char **argv __unused)
+{
+ if (argc != 1) {
+ if (argc == 0)
+ warnx("missing filesystem argument");
+ else
+ warnx("too many arguments");
+ return (0);
+ }
+
+ return (1);
+}
+
+static void
+initfsroot(int argc, char **argv, int flags, char *fsroot, size_t size)
+{
+ if (!checkargs_fs(argc, argv))
+ pefs_usage();
+
+ if (pefs_getfsroot(argv[0], flags, fsroot, size) != 0)
+ exit(PEFS_ERR_INVALID);
+}
+
+static int
+openx_rdonly(const char *path)
+{
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ warn("cannot open %s", path);
+
+ return (fd);
+
+}
+
+struct pefs_readpassfile_ctx {
+ size_t passphrase_pos;
+ size_t passphrase_sz;
+ char *passphrase;
+};
+
+static int
+pefs_readpassfile_handler(void *a, uint8_t *buf, size_t len, const char *file)
+{
+ struct pefs_readpassfile_ctx *ctx = a;
+ char *s;
+
+ if (strlen(buf) != len) {
+ pefs_warn("invalid passfile content: %s.", file);
+ return (PEFS_ERR_INVALID);
+ }
+
+ s = strchr(buf, '\n');
+ if (s != NULL)
+ *s = '\0';
+ if (strlcat(ctx->passphrase, buf, ctx->passphrase_sz) >=
+ ctx->passphrase_sz) {
+ pefs_warn("passphrase in %s too long.", file);
+ bzero(ctx->passphrase, ctx->passphrase_sz);
+ return (PEFS_ERR_INVALID);
+ }
+
+ return (0);
+}
+
+static int
+pefs_readpassfile(char *passphrase, int passphrase_sz, const char **files,
+ int file_count)
+{
+ struct pefs_readpassfile_ctx ctx;
+ int error;
+
+ ctx.passphrase_pos = 0;
+ ctx.passphrase_sz = passphrase_sz;
+ ctx.passphrase = passphrase;
+
+ bzero(ctx.passphrase, ctx.passphrase_sz);
+
+ error = pefs_readfiles(files, file_count, &ctx,
+ pefs_readpassfile_handler);
+ if (error != 0)
+ bzero(ctx.passphrase, ctx.passphrase_sz);
+ return (error);
+}
+
+static int
+pefs_readpassphrase(char *passphrase, int passphrase_sz, const char *prompt,
+ int verify)
+{
+ char promptbuf[64], buf[BUFSIZ], buf2[BUFSIZ], *p;
+ int i;
+
+ if (verify)
+ verify = 1;
+ if (prompt == NULL)
+ prompt = PEFS_KEY_PROMPT_DEFAULT;
+ for (i = 0; i <= verify; i++) {
+ snprintf(promptbuf, sizeof(promptbuf), "%s %s:",
+ !i ? "Enter" : "Reenter", prompt);
+ p = readpassphrase(promptbuf, !i ? buf : buf2, BUFSIZ,
+ RPP_ECHO_OFF | RPP_REQUIRE_TTY);
+ if (p == NULL || p[0] == '\0') {
+ bzero(buf, sizeof(buf));
+ bzero(buf2, sizeof(buf2));
+ warnx("unable to read passphrase");
+ return (PEFS_ERR_INVALID);
+ }
+ }
+ if (verify && strcmp(buf, buf2) != 0) {
+ bzero(buf, sizeof(buf));
+ bzero(buf2, sizeof(buf2));
+ warnx("passphrases didn't match");
+ return (PEFS_ERR_INVALID);
+ }
+ strlcpy(passphrase, buf, passphrase_sz);
+ bzero(buf2, sizeof(buf2));
+ bzero(buf, sizeof(buf));
+
+ return (0);
+}
+
+static int
+pefs_key_get(struct pefs_xkey *xk, const char *prompt, int verify,
+ struct pefs_keyparam *kp)
+{
+ char buf[BUFSIZ];
+ int error;
+
+ if (kp->kp_passfile_count != 0 && kp->kp_nopassphrase != 0) {
+ pefs_warn("options no-passphrase (-p) and passphrase-file (-j) "
+ "are mutually exclusive.");
+ return (PEFS_ERR_USAGE);
+ }
+
+ buf[0] = '\0';
+ if (kp->kp_passfile_count != 0) {
+ error = pefs_readpassfile(buf, sizeof(buf), kp->kp_passfile,
+ kp->kp_passfile_count);
+ if (error != 0)
+ return (error);
+ } else if (kp->kp_nopassphrase == 0) {
+ error = pefs_readpassphrase(buf, sizeof(buf), prompt, verify);
+ if (error != 0)
+ return (error);
+ }
+
+ error = pefs_key_generate(xk, buf, kp);
+ bzero(buf, sizeof(buf));
+
+ return (error);
+}
+
+static inline void
+pefs_key_showind(struct pefs_xkey *xk, int ind)
+{
+ printf("\t%-4d %016jx %s\n", ind, pefs_keyid_as_int(xk->pxk_keyid),
+ pefs_alg_name(xk));
+}
+
+static inline void
+pefs_key_shownode(struct pefs_xkey *xk, const char *path)
+{
+ const char *basepath;
+
+ basepath = basename(path);
+ if (xk == NULL)
+ printf("Key(%s): <not specified>\n", basepath);
+ else
+ printf("Key(%s): %016jx %s\n", basepath,
+ pefs_keyid_as_int(xk->pxk_keyid), pefs_alg_name(xk));
+}
+
+static int
+pefs_keychain_lookup(struct pefs_keychain_head *kch, const char *fsroot,
+ int chain_flags, struct pefs_keyparam *kp)
+{
+ struct pefs_xkey k;
+ int error;
+
+ error = pefs_keyparam_init(kp, fsroot);
+ if (error != 0)
+ return (error);
+ error = pefs_key_get(&k, NULL, 0, kp);
+ if (error != 0)
+ return (error);
+
+ error = pefs_keychain_get(kch, fsroot, chain_flags, &k);
+ bzero(&k, sizeof(k));
+ if (error)
+ return (PEFS_ERR_INVALID);
+
+ return (0);
+}
+
+static int
+pefs_keyop(keyop_func_t func, int argc, char *argv[])
+{
+ struct pefs_keychain_head kch;
+ struct pefs_keyparam kp;
+ char fsroot[MAXPATHLEN];
+ int error, fd, i;
+ int chain = PEFS_KEYCHAIN_IGNORE_MISSING;
+ int verbose = 0;
+
+ pefs_keyparam_create(&kp);
+ while ((i = getopt(argc, argv, "cCpva:i:j:k:")) != -1)
+ switch(i) {
+ case 'a':
+ if (pefs_keyparam_setalg(&kp, optarg) != 0)
+ pefs_usage_alg();
+ break;
+ case 'c':
+ chain = PEFS_KEYCHAIN_USE;
+ break;
+ case 'C':
+ chain = 0;
+ break;
+ case 'p':
+ kp.kp_nopassphrase = 1;
+ break;
+ case 'i':
+ if (pefs_keyparam_setiterations(&kp, optarg) != 0)
+ pefs_usage();
+ break;
+ case 'j':
+ if (pefs_keyparam_setfile(&kp, kp.kp_passfile,
+ optarg) != 0)
+ pefs_usage();
+ break;
+ case 'k':
+ if (pefs_keyparam_setfile(&kp, kp.kp_keyfile,
+ optarg) != 0)
+ pefs_usage();
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ pefs_usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+
+ error = pefs_keychain_lookup(&kch, fsroot, chain, &kp);
+ if (error != 0)
+ return (error);
+
+ fd = openx_rdonly(fsroot);
+ if (fd == -1) {
+ pefs_keychain_free(&kch);
+ return (PEFS_ERR_IO);
+ }
+
+ error = func(&kch, fd, verbose);
+
+ pefs_keychain_free(&kch);
+
+ close(fd);
+
+ return (error);
+}
+
+static int
+pefs_addkey_op(struct pefs_keychain_head *kch, int fd, int verbose)
+{
+ struct pefs_keychain *kc;
+
+ TAILQ_FOREACH(kc, kch, kc_entry) {
+ if (ioctl(fd, PEFS_ADDKEY, &kc->kc_key) == -1) {
+ warn("cannot add key");
+ return (-1);
+ } else if (verbose)
+ printf("Key added: %016jx\n",
+ pefs_keyid_as_int(kc->kc_key.pxk_keyid));
+ }
+
+ return (0);
+}
+
+static int
+pefs_delkey_op(struct pefs_keychain_head *kch, int fd, int verbose)
+{
+ struct pefs_keychain *kc;
+
+ TAILQ_FOREACH(kc, kch, kc_entry) {
+ if (ioctl(fd, PEFS_DELKEY, &kc->kc_key) == -1) {
+ warn("cannot delete key");
+ } else if (verbose)
+ printf("Key deleted: %016jx\n",
+ pefs_keyid_as_int(kc->kc_key.pxk_keyid));
+ }
+
+ return (0);
+}
+
+static int
+pefs_addkey(int argc, char *argv[])
+{
+ return (pefs_keyop(pefs_addkey_op, argc, argv));
+}
+
+static int
+pefs_delkey(int argc, char *argv[])
+{
+ return (pefs_keyop(pefs_delkey_op, argc, argv));
+}
+
+static int
+pefs_setkey(int argc, char *argv[])
+{
+ struct pefs_keychain_head kch;
+ struct pefs_keychain *kc;
+ struct pefs_keyparam kp;
+ char fsroot[MAXPATHLEN];
+ int error, fd, i;
+ int verbose = 0;
+ int addkey = 0;
+ int chain = PEFS_KEYCHAIN_IGNORE_MISSING;
+
+ pefs_keyparam_create(&kp);
+ while ((i = getopt(argc, argv, "cCpvxa:i:j:k:")) != -1)
+ switch(i) {
+ case 'a':
+ if (pefs_keyparam_setalg(&kp, optarg) != 0)
+ pefs_usage_alg();
+ break;
+ case 'c':
+ chain = PEFS_KEYCHAIN_USE;
+ break;
+ case 'C':
+ chain = 0;
+ break;
+ case 'p':
+ kp.kp_nopassphrase = 1;
+ break;
+ case 'i':
+ if (pefs_keyparam_setiterations(&kp, optarg) != 0)
+ pefs_usage();
+ break;
+ case 'j':
+ if (pefs_keyparam_setfile(&kp, kp.kp_passfile,
+ optarg) != 0)
+ pefs_usage();
+ break;
+ case 'k':
+ if (pefs_keyparam_setfile(&kp, kp.kp_keyfile,
+ optarg) != 0)
+ pefs_usage();
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ addkey = 1;
+ break;
+ default:
+ pefs_usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (chain == PEFS_KEYCHAIN_USE && addkey) {
+ warnx("invalid argument combination: -x -c");
+ return (PEFS_ERR_USAGE);
+ }
+
+ if (argc != 1) {
+ if (argc == 0)
+ warnx("missing directory argument");
+ else
+ warnx("too many arguments");
+ pefs_usage();
+ }
+
+ initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+
+ error = pefs_keychain_lookup(&kch, fsroot, chain, &kp);
+ if (error != 0)
+ return (error);
+
+ fd = openx_rdonly(argv[0]);
+ if (fd == -1) {
+ pefs_keychain_free(&kch);
+ return (PEFS_ERR_IO);
+ }
+
+ if (addkey) {
+ TAILQ_FOREACH(kc, &kch, kc_entry) {
+ if (ioctl(fd, PEFS_ADDKEY, &kc->kc_key) == 0 && verbose)
+ printf("Key added: %016jx\n",
+ pefs_keyid_as_int(kc->kc_key.pxk_keyid));
+ }
+ }
+ kc = TAILQ_FIRST(&kch);
+ if (ioctl(fd, PEFS_SETKEY, &kc->kc_key) == -1) {
+ warn("cannot set key");
+ error = PEFS_ERR_SYS;
+ } else if (verbose)
+ pefs_key_shownode(&kc->kc_key, argv[0]);
+
+ pefs_keychain_free(&kch);
+
+ close(fd);
+
+ return (error);
+}
+
+static int
+pefs_flushkeys(int argc, char *argv[])
+{
+ char fsroot[MAXPATHLEN];
+ int fd;
+
+ initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+
+ fd = openx_rdonly(fsroot);
+ if (fd == -1)
+ return (PEFS_ERR_IO);
+ if (ioctl(fd, PEFS_FLUSHKEYS) == -1) {
+ warn("cannot flush keys");
+ return (PEFS_ERR_IO);
+ }
+ close(fd);
+
+ return (0);
+}
+
+static int
+pefs_getkey(int argc, char *argv[])
+{
+ struct pefs_xkey k;
+ int testonly = 0;
+ int error = 0;
+ int fd, i;
+
+ while ((i = getopt(argc, argv, "t")) != -1)
+ switch(i) {
+ case 't':
+ testonly = 1;
+ break;
+ case '?':
+ default:
+ pefs_usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+ if (argc == 0)
+ warnx("missing file argument");
+ else
+ warnx("too many arguments");
+ pefs_usage();
+ }
+
+ /* only check file system type */
+ if (pefs_getfsroot(argv[0], 0, NULL, 0) != 0)
+ return (PEFS_ERR_INVALID);
+
+ fd = openx_rdonly(argv[0]);
+ if (fd == -1)
+ return (PEFS_ERR_IO);
+
+ bzero(&k, sizeof(k));
+ if (ioctl(fd, PEFS_GETNODEKEY, &k) == -1) {
+ if (errno == ENOENT) {
+ if (testonly == 0)
+ pefs_key_shownode(NULL, argv[0]);
+ else
+ error = PEFS_ERR_GENERIC;
+ } else {
+ warn("cannot get key");
+ error = PEFS_ERR_SYS;
+ }
+ } else if (testonly == 0)
+ pefs_key_shownode(&k, argv[0]);
+
+ close(fd);
+
+ return (error);
+}
+
+static int
+pefs_showkeys(int argc, char *argv[])
+{
+ char fsroot[MAXPATHLEN];
+ struct pefs_xkey k;
+ int testonly = 0;
+ int fd, i;
+
+ while ((i = getopt(argc, argv, "t")) != -1)
+ switch(i) {
+ case 't':
+ testonly = 1;
+ break;
+ case '?':
+ default:
+ pefs_usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+
+ fd = openx_rdonly(fsroot);
+ if (fd == -1)
+ return (PEFS_ERR_IO);
+
+ bzero(&k, sizeof(k));
+ if (ioctl(fd, PEFS_GETKEY, &k) == -1) {
+ if (testonly) {
+ close(fd);
+ return (PEFS_ERR_INVALID);
+ }
+ if (errno == ENOENT)
+ printf("No keys specified\n");
+ else {
+ warn("cannot list keys");
+ close(fd);
+ return (PEFS_ERR_IO);
+ }
+ } else {
+ if (testonly) {
+ close(fd);
+ return (0);
+ }
+ printf("Keys:\n");
+ while (1) {
+ pefs_key_showind(&k, k.pxk_index);
+ k.pxk_index++;
+ if (ioctl(fd, PEFS_GETKEY, &k) == -1)
+ break;
+ }
+ }
+ close(fd);
+
+ return (0);
+}
+
+static int
+pefs_mount(int argc, char *argv[])
+{
+ char **nargv;
+ int nargc, topt, i, shift;
+
+ topt = 0;
+ opterr = 0;
+ while ((i = getopt(argc, argv, "t:")) != -1)
+ switch(i) {
+ case 't':
+ if (strcmp(optarg, PEFS_FSTYPE) != 0) {
+ warnx("invalid file system type: %s",
+ optarg);
+ return (PEFS_ERR_USAGE);
+ }
+ topt = 1;
+ break;
+ default:
+ break;
+ }
+
+ shift = (topt == 0 ? 2 : 0);
+ nargc = argc + shift + 2;
+ nargv = malloc(nargc * sizeof(*nargv));
+ nargv[0] = __DECONST(char *, "pefs mount");
+ if (topt == 0) {
+ nargv[1] = __DECONST(char *, "-t");
+ nargv[2] = __DECONST(char *, PEFS_FSTYPE);
+ }
+ for (i = 0; i < argc; i++)
+ nargv[i + shift + 1] = argv[i];
+ nargv[nargc - 1] = NULL;
+
+ execv(PATH_MOUNT, nargv);
+ warnx("exec %s", PATH_MOUNT);
+
+ return (PEFS_ERR_SYS);
+}
+
+static int
+pefs_unmount(int argc, char *argv[])
+{
+ char **nargv;
+ int i;
+
+ while ((i = getopt(argc, argv, "fv")) != -1)
+ switch(i) {
+ case 'f':
+ case 'v':
+ break;
+ case '?':
+ default:
+ pefs_usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!checkargs_fs(argc, argv))
+ pefs_usage();
+
+ nargv = malloc((argc + 2) * sizeof(*nargv));
+ for (i = 0; i < argc; i++)
+ nargv[i + 1] = argv[i];
+ nargv[0] = __DECONST(char *, "pefs unmount");
+ nargv[argc + 1] = NULL;
+
+ execv(PATH_UMOUNT, nargv);
+ warnx("exec %s", PATH_UMOUNT);
+
+ return (PEFS_ERR_SYS);
+}
+
+static int
+pefs_addchain(int argc, char *argv[])
+{
+ struct pefs_keychain *kc;
+ struct pefs_keychain_head kch;
+ struct {
+ struct pefs_xkey k;
+ struct pefs_keyparam kp;
+ } p[2];
+ struct pefs_xkey *k1 = &p[0].k, *k2 = &p[1].k;
+ struct pefs_keyparam *kpi;
+ char fsroot[MAXPATHLEN];
+ int fsflags = 0, verbose = 0;
+ int zerochainedkey = 0, optchainedkey = 0;
+ int error, i, fd;
+
+ pefs_keyparam_create(&p[0].kp);
+ pefs_keyparam_create(&p[1].kp);
+ while ((i = getopt(argc, argv, "a:A:i:I:j:J:k:K:fpPvZ")) != -1)
+ switch(i) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'f':
+ fsflags |= PEFS_FS_IGNORE_TYPE;
+ break;
+ case 'Z':
+ zerochainedkey = 1;
+ break;
+ case 'a':
+ case 'A':
+ if (isupper(i))
+ optchainedkey = i;
+ kpi = &p[isupper(i) ? 1 : 0].kp;
+ if (pefs_keyparam_setalg(kpi, optarg) != 0)
+ pefs_usage_alg();
+ break;
+ case 'p':
+ case 'P':
+ if (isupper(i))
+ optchainedkey = i;
+ kpi = &p[isupper(i) ? 1 : 0].kp;
+ kpi->kp_nopassphrase = 1;
+ break;
+ case 'i':
+ case 'I':
+ if (isupper(i))
+ optchainedkey = i;
+ kpi = &p[isupper(i) ? 1 : 0].kp;
+ if (pefs_keyparam_setiterations(kpi, optarg) != 0)
+ pefs_usage();
+ break;
+ case 'j':
+ case 'J':
+ if (isupper(i))
+ optchainedkey = i;
+ kpi = &p[isupper(i) ? 1 : 0].kp;
+ if (pefs_keyparam_setfile(kpi, kpi->kp_passfile,
+ optarg) != 0)
+ pefs_usage();
+ break;
+ case 'k':
+ case 'K':
+ if (isupper(i))
+ optchainedkey = i;
+ kpi = &p[isupper(i) ? 1 : 0].kp;
+ if (pefs_keyparam_setfile(kpi, kpi->kp_keyfile,
+ optarg) != 0)
+ pefs_usage();
+ break;
+ default:
+ pefs_usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (optchainedkey && zerochainedkey) {
+ warnx("invalid argument combination: -Z -%c",
+ optchainedkey);
+ return (PEFS_ERR_USAGE);
+ }
+
+ initfsroot(argc, argv, fsflags, fsroot, sizeof(fsroot));
+
+ error = pefs_keyparam_init(&p[0].kp, fsroot);
+ if (error != 0)
+ return (error);
+ error = pefs_keyparam_init(&p[1].kp, fsroot);
+ if (error != 0)
+ return (error);
+
+ error = pefs_key_get(k1, "parent key passphrase", 1, &p[0].kp);
+ if (error != 0) {
+ bzero(p, sizeof(p));
+ return (error);
+ }
+
+ if (zerochainedkey) {
+ fd = openx_rdonly(PATH_DEVRANDOM);
+ if (fd == -1) {
+ bzero(p, sizeof(p));
+ return (PEFS_ERR_IO);
+ }
+ read(fd, k2, sizeof(struct pefs_keychain));
+ close(fd);
+ k2->pxk_alg = PEFS_ALG_INVALID;
+ error = pefs_keychain_set(fsroot, k1, k2);
+ bzero(p, sizeof(p));
+ if (error)
+ return (PEFS_ERR_INVALID);
+ return (0);
+ }
+
+ error = pefs_key_get(k2, "chained key passphrase", 1, &p[1].kp);
+ if (error != 0) {
+ bzero(p, sizeof(p));
+ return (error);
+ }
+