From 03012f54b1bcd31e0b817fc0222a9a47709c4018 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Sun, 4 Feb 2018 23:22:53 +0000 Subject: Initial commit --- .gitignore | 7 + AUTHORS | 5 + COPYING | 13 + INSTALL | 187 ++++++++++++++ Makefile | 151 +++++++++++ NEWS | 6 + README | 28 +++ README.macosx | 4 + README.solaris | 16 ++ configure | 461 ++++++++++++++++++++++++++++++++++ doc/building.html | 103 ++++++++ doc/index.html | 138 ++++++++++ doc/pamelad.html | 68 +++++ doc/upgrade.html | 28 +++ package/deps-build | 1 + package/deps.mak | 45 ++++ package/info | 4 + package/modes | 1 + package/targets.mak | 14 ++ patch-for-solaris | 21 ++ src/include/pamela/common.h | 101 ++++++++ src/include/pamela/pam.h | 161 ++++++++++++ src/include/pamela/pamela.h | 80 ++++++ src/pamela/deps-exe/pamelad | 2 + src/pamela/deps-lib/pamela | 27 ++ src/pamela/pam_acct_mgmt.c | 11 + src/pamela/pam_authenticate.c | 11 + src/pamela/pam_chauthtok.c | 11 + src/pamela/pam_close_session.c | 11 + src/pamela/pam_end.c | 17 ++ src/pamela/pam_fail_delay.c | 11 + src/pamela/pam_get_item.c | 52 ++++ src/pamela/pam_getenv.c | 32 +++ src/pamela/pam_getenvlist.c | 42 ++++ src/pamela/pam_open_session.c | 11 + src/pamela/pam_putenv.c | 14 ++ src/pamela/pam_set_item.c | 50 ++++ src/pamela/pam_setcred.c | 11 + src/pamela/pam_start.c | 34 +++ src/pamela/pam_strerror.c | 17 ++ src/pamela/pamela-internal.h | 13 + src/pamela/pamela_end.c | 16 ++ src/pamela/pamela_get_item.c | 11 + src/pamela/pamela_getenvlist.c | 9 + src/pamela/pamela_op.c | 123 +++++++++ src/pamela/pamela_pam_response_free.c | 11 + src/pamela/pamela_query_string.c | 20 ++ src/pamela/pamela_set_item.c | 16 ++ src/pamela/pamela_set_item_internal.c | 14 ++ src/pamela/pamela_set_itemv.c | 14 ++ src/pamela/pamela_startf.c | 40 +++ src/pamela/pamela_strerror.c | 11 + src/pamela/pamela_zero.c | 5 + src/pamela/pamelad.c | 385 ++++++++++++++++++++++++++++ tools/gen-deps.sh | 93 +++++++ tools/install.sh | 64 +++++ 56 files changed, 2852 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100644 README.macosx create mode 100644 README.solaris create mode 100755 configure create mode 100644 doc/building.html create mode 100644 doc/index.html create mode 100644 doc/pamelad.html create mode 100644 doc/upgrade.html create mode 100644 package/deps-build create mode 100644 package/deps.mak create mode 100644 package/info create mode 100644 package/modes create mode 100644 package/targets.mak create mode 100755 patch-for-solaris create mode 100644 src/include/pamela/common.h create mode 100644 src/include/pamela/pam.h create mode 100644 src/include/pamela/pamela.h create mode 100644 src/pamela/deps-exe/pamelad create mode 100644 src/pamela/deps-lib/pamela create mode 100644 src/pamela/pam_acct_mgmt.c create mode 100644 src/pamela/pam_authenticate.c create mode 100644 src/pamela/pam_chauthtok.c create mode 100644 src/pamela/pam_close_session.c create mode 100644 src/pamela/pam_end.c create mode 100644 src/pamela/pam_fail_delay.c create mode 100644 src/pamela/pam_get_item.c create mode 100644 src/pamela/pam_getenv.c create mode 100644 src/pamela/pam_getenvlist.c create mode 100644 src/pamela/pam_open_session.c create mode 100644 src/pamela/pam_putenv.c create mode 100644 src/pamela/pam_set_item.c create mode 100644 src/pamela/pam_setcred.c create mode 100644 src/pamela/pam_start.c create mode 100644 src/pamela/pam_strerror.c create mode 100644 src/pamela/pamela-internal.h create mode 100644 src/pamela/pamela_end.c create mode 100644 src/pamela/pamela_get_item.c create mode 100644 src/pamela/pamela_getenvlist.c create mode 100644 src/pamela/pamela_op.c create mode 100644 src/pamela/pamela_pam_response_free.c create mode 100644 src/pamela/pamela_query_string.c create mode 100644 src/pamela/pamela_set_item.c create mode 100644 src/pamela/pamela_set_item_internal.c create mode 100644 src/pamela/pamela_set_itemv.c create mode 100644 src/pamela/pamela_startf.c create mode 100644 src/pamela/pamela_strerror.c create mode 100644 src/pamela/pamela_zero.c create mode 100644 src/pamela/pamelad.c create mode 100755 tools/gen-deps.sh create mode 100755 tools/install.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d0b823 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.o +*.lo +/config.mak +/src/include/pamela/config.h +/pamelad +/libpamela.a.xyzzy +/libpamela.so.xyzzy diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..6b17ed5 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +Main author: + Laurent Bercot + +Contributors: + A. Wilcox diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..361dcb6 --- /dev/null +++ b/COPYING @@ -0,0 +1,13 @@ +Copyright (c) 2018 Laurent Bercot + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..0283d17 --- /dev/null +++ b/INSTALL @@ -0,0 +1,187 @@ +Build Instructions +------------------ + +* Requirements + ------------ + + - A POSIX-compliant C development environment + - GNU make version 3.81 or later + - skalibs version 2.6.3.2 or later: http://skarnet.org/software/skalibs/ + - Linux-PAM version 1.3.0 or later: http://www.linux-pam.org/library/ + + This software will run on any operating system that implements +POSIX.1-2008, available at: + http://pubs.opengroup.org/onlinepubs/9699919799/ +as well as Linux-PAM. As of February 2018, this means only Linux. + + +* Standard usage + -------------- + + ./configure && make && sudo make install + + will work for most users. + It will install the binaries in /bin and the static libraries in +/usr/lib/pamela. + + Please note that static libraries in /usr/lib/pamela *will not* +be found by a default linker invocation: you need -L/usr/lib/pamela. +Other skarnet.org software automatically handles that case if the +default configuration is used, but if you change the configuration, +remember to use the appropriate --with-lib configure option. + + You can strip the binaries and libraries of their extra symbols via +"make strip" before the "make install" phase. It will shave a few bytes +off them. + + The PAM declarations for applications are available in the pamela/pam.h +header. They are not made available in security/pam_appl.h by default +in order to avoid conflicting with a Linux-PAM installation. If you +want to make pamela your default PAM implementation, run + + sudo make install-symlink + +which will make security/pam_appl.h a symlink to pamela/pam.h, +possibly overwriting any previous security/pam_appl.h file. +Please note that if you try and build pamela again *after* doing +this, the pamelad binary (which expects Linux-PAM, not pamela, +in security/pam_appl.h) may not be built correctly. + + +* Customization + ------------- + + You can customize paths via flags given to configure. + See ./configure --help for a list of all available configure options. + + +* Environment variables + --------------------- + + Controlling a build process via environment variables is a big and +dangerous hammer. You should try and pass flags to configure instead; +nevertheless, a few standard environment variables are recognized. + + If the CC environment variable is set, its value will override compiler +detection by configure. The --host=HOST option will still add a HOST- +prefix to the value of CC. + + The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags +auto-detected by configure. To entirely override the flags set by +configure instead, use make variables. + + +* Make variables + -------------- + + You can invoke make with a few variables for more configuration. + + CC, CFLAGS, CPPFLAGS, LDFLAGS, LDLIBS, AR, RANLIB, STRIP, INSTALL and +CROSS_COMPILE can all be overridden on the make command line. This is +an even bigger hammer than running ./configure with environment +variables, so it is advised to only do this when it is the only way of +obtaining the behaviour you want. + + DESTDIR can be given on the "make install" command line in order to +install to a staging directory. + + +* Shared libraries + ---------------- + + Software from skarnet.org is small enough that shared libraries are +generally not worth using. Static linking is simpler and incurs less +runtime overhead and less points of failure: so by default, shared +libraries are not built and binaries are linked against the static +versions of the skarnet.org libraries. Nevertheless, you can: + * build shared libraries: --enable-shared + * link binaries against shared libraries: --disable-allstatic + + +* Static binaries + --------------- + + By default, binaries are linked against static versions of all the +libraries they depend on, except for the libc. You can enforce +linking against the static libc with --enable-static-libc. + + Note that the pamelad binary needs to be able to load the PAM +modules, so it requires dynamic linking. Attempting to statically +link the pamela package is strongly discouraged. + + +* Cross-compilation + ----------------- + + skarnet.org packages centralize all the difficulty of +cross-compilation in one place: skalibs. Once you have +cross-compiled skalibs, the rest is easy. + + * Use the --host=HOST option to configure, HOST being the triplet +for your target. + * Make sure your cross-toolchain binaries (i.e. prefixed with HOST-) +are accessible via your PATH environment variable. + * Make sure to use the correct version of skalibs for your target, +and the correct sysdeps directory, making use of the +--with-include, --with-lib, --with-dynlib and --with-sysdeps +options as necessary. + + +* The slashpackage convention + --------------------------- + + The slashpackage convention (http://cr.yp.to/slashpackage.html) +is a package installation scheme that provides a few guarantees +over other conventions such as the FHS, for instance fixed +absolute pathnames. skarnet.org packages support it: use the +--enable-slashpackage option to configure, or +--enable-slashpackage=DIR for a prefixed DIR/package tree. +This option will activate slashpackage support during the build +and set slashpackage-compatible installation directories. +If $package_home is the home of the package, defined as +DIR/package/$category/$package-$version with the variables +read from the package/info file, then: + + --dynlibdir is set to $package_home/library.so + --bindir is set to $package_home/command + --sbindir is also set to $package_home/command (slashpackage +differentiates root-only binaries by their Unix rights, not their +location in the filesystem) + --libexecdir is also set to $package_home/command (slashpackage +does not need a specific directory for internal binaries) + --libdir is set to $package_home/library + --includedir is set to $package_home/include + + --prefix is pretty much ignored when you use --enable-slashpackage. +You should probably not use both --enable-slashpackage and --prefix. + + When using slashpackage, two additional Makefile targets are +available after "make install": + - "make update" changes the default version of the software to the +freshly installed one. (This is useful when you have several installed +versions of the same software, which slashpackage supports.) + - "make -L global-links" adds links from /command and /library.so to the +default version of the binaries and shared libraries. The "-L" option to +make is necessary because targets are symbolic links, and the default make +behaviour is to check the pointed file's timestamp and not the symlink's +timestamp. + + +* Absolute pathnames + ------------------ + + You may want to use fixed absolute pathnames even if you're not +following the slashpackage convention: for instance, the Nix packaging +system prefers calling binaries with immutable paths rather than rely on +PATH resolution. If you are in that case, use the --enable-absolute-paths +option to configure. This will ensure that programs calling binaries from +this package will call them with their full installation path (in bindir) +without relying on a PATH search. + + +* Out-of-tree builds + ------------------ + + skarnet.org packages do not support out-of-tree builds. They +are small, so it does not cost much to duplicate the entire +source tree if parallel builds are needed. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..610dbb6 --- /dev/null +++ b/Makefile @@ -0,0 +1,151 @@ +# +# This Makefile requires GNU make. +# +# Do not make changes here. +# Use the included .mak files. +# + +it: all + +make_need := 3.81 +ifeq "" "$(strip $(filter $(make_need), $(firstword $(sort $(make_need) $(MAKE_VERSION)))))" +fail := $(error Your make ($(MAKE_VERSION)) is too old. You need $(make_need) or newer) +endif + +CC = $(error Please use ./configure first) + +STATIC_LIBS := +SHARED_LIBS := +INTERNAL_LIBS := +EXTRA_TARGETS := +LIB_DEFS := + +define library_definition +LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy +ifdef DO_SHARED +SHARED_LIBS += lib$(lastword $(subst =, ,$(1))).so.xyzzy +endif +ifdef DO_STATIC +STATIC_LIBS += lib$(lastword $(subst =, ,$(1))).a.xyzzy +endif +endef + +-include config.mak +include package/targets.mak + +$(foreach var,$(LIB_DEFS),$(eval $(call library_definition,$(var)))) + +include package/deps.mak + +version_m := $(basename $(version)) +version_M := $(basename $(version_m)) +version_l := $(basename $(version_M)) +CPPFLAGS_ALL := $(CPPFLAGS_AUTO) $(CPPFLAGS) +CFLAGS_ALL := $(CFLAGS_AUTO) $(CFLAGS) +ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) +CFLAGS_SHARED := -fPIC +else +CFLAGS_SHARED := +endif +LDFLAGS_ALL := $(LDFLAGS_AUTO) $(LDFLAGS) +REALCC = $(CROSS_COMPILE)$(CC) +AR := $(CROSS_COMPILE)ar +RANLIB := $(CROSS_COMPILE)ranlib +STRIP := $(CROSS_COMPILE)strip +INSTALL := ./tools/install.sh + +ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS) +ALL_LIBS := $(SHARED_LIBS) $(STATIC_LIBS) $(INTERNAL_LIBS) +ALL_INCLUDES := $(wildcard src/include/$(package)/*.h) + +all: $(ALL_LIBS) $(ALL_BINS) $(ALL_INCLUDES) + +clean: + @exec rm -f $(ALL_LIBS) $(ALL_BINS) $(wildcard src/*/*.o src/*/*.lo) $(EXTRA_TARGETS) + +distclean: clean + @exec rm -f config.mak src/include/$(package)/config.h + +tgz: distclean + @. package/info && \ + rm -rf /tmp/$$package-$$version && \ + cp -a . /tmp/$$package-$$version && \ + cd /tmp && \ + tar -zpcv --owner=0 --group=0 --numeric-owner --exclude=.git* -f /tmp/$$package-$$version.tar.gz $$package-$$version && \ + exec rm -rf /tmp/$$package-$$version + +strip: $(ALL_LIBS) $(ALL_BINS) +ifneq ($(strip $(STATIC_LIBS)),) + exec $(STRIP) -x -R .note -R .comment -R .note.GNU-stack $(STATIC_LIBS) +endif +ifneq ($(strip $(ALL_BINS)$(SHARED_LIBS)),) + exec $(STRIP) -R .note -R .comment -R .note.GNU-stack $(ALL_BINS) $(SHARED_LIBS) +endif + +install: install-dynlib install-libexec install-bin install-lib install-include +install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so) +install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%) +install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%) +install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a) +install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h) +install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%) + +ifneq ($(exthome),) + +$(DESTDIR)$(exthome): $(DESTDIR)$(home) + exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome) + +update: $(DESTDIR)$(exthome) + +global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) + +$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/% + exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$( diff --git a/README.macosx b/README.macosx new file mode 100644 index 0000000..e8a44d0 --- /dev/null +++ b/README.macosx @@ -0,0 +1,4 @@ + + This package will compile and run on Darwin (MacOS), if there is an implementation +of Linux-PAM there; but the building of shared libraries is not supported. + Make sure you use the --disable-shared option to configure. diff --git a/README.solaris b/README.solaris new file mode 100644 index 0000000..380c8d8 --- /dev/null +++ b/README.solaris @@ -0,0 +1,16 @@ + + This package assumes the existence of a POSIX shell in /bin/sh. + On Solaris, /bin/sh is not POSIX. Most versions of Solaris provide +a POSIX shell in /usr/xpg4/bin/sh. + + To compile this package on Solaris, you will need to run + + ./patch-for-solaris + + before you run ./configure. This script will change the #! invocation +of the configure script and various tools so that a POSIX shell is used +for the compilation process. + + Please note that the Solaris implementation of PAM is slightly +incompatible with Linux-PAM. If you're using pamela on Solaris, please +report your experience to ska-skaware@skarnet.org. diff --git a/configure b/configure new file mode 100755 index 0000000..de87b55 --- /dev/null +++ b/configure @@ -0,0 +1,461 @@ +#!/bin/sh + +. package/info + +usage () { +cat </dev/null 2>&1 && { echo "$1" ; return 0 ; } +$1 +EOF + echo "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" -e "s|\*/|* /|g" +} + +fail () { + echo "$*" + exit 1 +} + +fnmatch () { + eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac" +} + +cmdexists () { + type "$1" >/dev/null 2>&1 +} + +trycc () { + test -z "$CC_AUTO" && cmdexists "$1" && CC_AUTO="$*" +} + +stripdir () { + while eval "fnmatch '*/' \"\${$1}\"" ; do + eval "$1=\${$1%/}" + done +} + +tryflag () { + echo "checking whether compiler accepts $2 ..." + echo "typedef int x;" > "$tmpc" + if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST "$2" -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then + echo " ... yes" + eval "$1=\"\${$1} \$2\"" + eval "$1=\${$1# }" + return 0 + else + echo " ... no" + return 1 + fi +} + +tryldflag () { + echo "checking whether linker accepts $2 ..." + echo "typedef int x;" > "$tmpc" + if $CC_AUTO $CFLAGS_AUTO $CFLAGS $CFLAGS_POST $LDFLAGS_AUTO $LDFLAGS $LDFLAGS_POST -nostdlib "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then + echo " ... yes" + eval "$1=\"\${$1} \$2\"" + eval "$1=\${$1# }" + return 0 + else + echo " ... no" + return 1 + fi +} + + +# Actual script + +CC_AUTO= +CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -iquote src/include-local -Isrc/include" +CPPFLAGS_POST="$CPPFLAGS" +CPPFLAGS= +CFLAGS_AUTO="-pipe -Wall" +CFLAGS_POST="$CFLAGS" +CFLAGS=-O2 +LDFLAGS_AUTO= +LDFLAGS_POST="$LDFLAGS" +LDFLAGS= +LDFLAGS_NOSHARED= +LDFLAGS_SHARED=-shared +prefix= +exec_prefix='$prefix' +dynlibdir='$prefix/lib' +libexecdir='$exec_prefix/libexec' +bindir='$exec_prefix/bin' +libdir='$prefix/lib/$package' +includedir='$prefix/include' +sysdeps='$prefix/lib/skalibs/sysdeps' +manualsysdeps=false +shared=false +static=true +allpic=detect +slashpackage=false +abspath=false +sproot= +home= +exthome= +allstatic=true +evenmorestatic=false +addincpath='' +addlibspath='' +addlibdpath='' +vpaths='' +vpathd='' +build= + +for arg ; do + case "$arg" in + --help) usage ;; + --prefix=*) prefix=${arg#*=} ;; + --exec-prefix=*) exec_prefix=${arg#*=} ;; + --dynlibdir=*) dynlibdir=${arg#*=} ;; + --libexecdir=*) libexecdir=${arg#*=} ;; + --bindir=*) bindir=${arg#*=} ;; + --libdir=*) libdir=${arg#*=} ;; + --includedir=*) includedir=${arg#*=} ;; + --with-sysdeps=*) sysdeps=${arg#*=} manualsysdeps=true ;; + --with-include=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var" ;; + --with-lib=*) var=${arg#*=} ; stripdir var ; addlibspath="$addlibspath -L$var" ; vpaths="$vpaths $var" ;; + --with-dynlib=*) var=${arg#*=} ; stripdir var ; addlibdpath="$addlibdpath -L$var" ; vpathd="$vpathd $var" ;; + --enable-shared|--enable-shared=yes) shared=true ;; + --disable-shared|--enable-shared=no) shared=false ;; + --enable-static|--enable-static=yes) static=true ;; + --disable-static|--enable-static=no) static=false ;; + --enable-allstatic|--enable-allstatic=yes) allstatic=true ;; + --disable-allstatic|--enable-allstatic=no) allstatic=false ; evenmorestatic=false ;; + --enable-static-libc|--enable-static-libc=yes) allstatic=true ; evenmorestatic=true ;; + --disable-static-libc|--enable-static-libc=no) evenmorestatic=false ;; + --enable-all-pic|--enable-all-pic=yes) allpic=true ;; + --disable-all-pic|--enable-all-pic=no) allpic=false ;; + --enable-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;; + --enable-slashpackage) sproot= ; slashpackage=true ;; + --disable-slashpackage) sproot= ; slashpackage=false ;; + --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;; + --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;; + --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;; + --host=*|--target=*) target=${arg#*=} ;; + --build=*) build=${arg#*=} ;; + -* ) echo "$0: unknown option $arg" ;; + *=*) ;; + *) target=$arg ;; + esac +done + +# Add /usr in the default default case +if test -z "$prefix" ; then + if test "$libdir" = '$prefix/lib/$package' ; then + libdir=/usr/lib/$package + fi + if test "$includedir" = '$prefix/include' ; then + includedir=/usr/include + fi + if test "$sysdeps" = '$prefix/lib/skalibs/sysdeps' ; then + sysdeps=/usr/lib/skalibs/sysdeps + fi +fi + +# Expand installation directories +stripdir prefix +for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysdeps sproot ; do + eval tmp=\${$i} + eval $i=$tmp + stripdir $i +done + +# Get usable temp filenames +i=0 +set -C +while : ; do + i=$(($i+1)) + tmpc="./tmp-configure-$$-$PPID-$i.c" + tmpe="./tmp-configure-$$-$PPID-$i.tmp" + 2>|/dev/null > "$tmpc" && break + 2>|/dev/null > "$tmpe" && break + test "$i" -gt 50 && fail "$0: cannot create temporary files" +done +set +C +trap 'rm -f "$tmpc" "$tmpe"' EXIT ABRT INT QUIT TERM HUP + +# Set slashpackage values +if $slashpackage ; then + home=${sproot}/package/${category}/${package}-${version} + exthome=${sproot}/package/${category}/${package} + if $manualsysdeps ; then + : + else + sysdeps=${sproot}/package/prog/skalibs/sysdeps + fi + extbinprefix=${exthome}/command + dynlibdir=${home}/library.so + bindir=${home}/command + libdir=${home}/library + libexecdir=$bindir + includedir=${home}/include + while read dep ; do + addincpath="$addincpath -I${sproot}${dep}/include" + vpaths="$vpaths ${sproot}${dep}/library" + addlibspath="$addlibspath -L${sproot}${dep}/library" + vpathd="$vpathd ${sproot}${dep}/library.so" + addlibdpath="$addlibdpath -L${sproot}${dep}/library.so" + done < package/deps-build +fi + +# Find a C compiler to use +if test -n "$target" && test x${build} != x${target} ; then + cross=${target}- +else + cross= +fi +echo "checking for C compiler..." +trycc ${cross}${CC} +trycc ${cross}gcc +trycc ${cross}clang +trycc ${cross}cc +test -n "$CC_AUTO" || { echo "$0: cannot find a C compiler" ; exit 1 ; } +echo " ... $CC_AUTO" +echo "checking whether C compiler works... " +echo "typedef int x;" > "$tmpc" +if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -c -o /dev/null "$tmpc" 2>"$tmpe" ; then + echo " ... yes" +else + echo " ... no. Compiler output follows:" + cat < "$tmpe" + exit 1 +fi + +echo "checking target system type..." +if test -z "$target" ; then + if test -n "$build" ; then + target=$build ; + else + target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown + fi +fi +echo " ... $target" +if test ! -d $sysdeps || test ! -f $sysdeps/target ; then + echo "$0: error: $sysdeps is not a valid sysdeps directory" + exit 1 +fi +if [ "x$target" != "x$(cat $sysdeps/target)" ] ; then + echo "$0: error: target $target does not match the contents of $sysdeps/target" + exit 1 +fi + +if test $allpic = detect ; then + echo "Checking whether we need to build everything as PIC..." + if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -dM -E - < /dev/null | grep -qF __PIE__ ; then + allpic=true + echo " ... yes" + else + allpic=false + echo " ... no" + fi +fi +if $allpic ; then + tryflag CFLAGS_AUTO -fPIC +fi + +spawn_lib=$(cat $sysdeps/spawn.lib) +socket_lib=$(cat $sysdeps/socket.lib) +sysclock_lib=$(cat $sysdeps/sysclock.lib) +tainnow_lib=$(cat $sysdeps/tainnow.lib) +timer_lib=$(cat $sysdeps/timer.lib) +util_lib=$(cat $sysdeps/util.lib) + +tryflag CFLAGS_AUTO -std=c99 +tryflag CFLAGS -fomit-frame-pointer +tryflag CFLAGS_AUTO -fno-exceptions +tryflag CFLAGS_AUTO -fno-unwind-tables +tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables +tryflag CFLAGS_AUTO -Wa,--noexecstack +tryflag CFLAGS -fno-stack-protector +tryflag CPPFLAGS_AUTO -Werror=implicit-function-declaration +tryflag CPPFLAGS_AUTO -Werror=implicit-int +tryflag CPPFLAGS_AUTO -Werror=pointer-sign +tryflag CPPFLAGS_AUTO -Werror=pointer-arith +tryflag CFLAGS_AUTO -ffunction-sections +tryflag CFLAGS_AUTO -fdata-sections + +tryldflag LDFLAGS_AUTO -Wl,--sort-section=alignment +tryldflag LDFLAGS_AUTO -Wl,--sort-common + +CPPFLAGS_AUTO="${CPPFLAGS_AUTO}${addincpath}" + +if $evenmorestatic ; then + LDFLAGS_NOSHARED=-static +fi + +if $shared ; then + tryldflag LDFLAGS -Wl,--hash-style=both +fi + +LDFLAGS_SHARED="${LDFLAGS_SHARED}${addlibdpath}" + +if $allstatic ; then + LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibspath}" + tryldflag LDFLAGS_NOSHARED -Wl,--gc-sections +else + LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibdpath}" +fi + +if test -z "$vpaths" ; then + while read dep ; do + base=$(basename $dep) ; + vpaths="$vpaths /usr/lib/$base" + addlibspath="$addlibspath -L/usr/lib/$base" + done < package/deps-build +fi + +echo "creating config.mak..." +cmdline=$(quote "$0") +for i ; do cmdline="$cmdline $(quote "$i")" ; done +exec 3>&1 1>config.mak +cat << EOF +# This file was generated by: +# $cmdline +# Any changes made here will be lost if configure is re-run. + +target := $target +package := $package +prefix := $prefix +exec_prefix := $exec_prefix +dynlibdir := $dynlibdir +libexecdir := $libexecdir +bindir := $bindir +libdir := $libdir +includedir := $includedir +sysdeps := $sysdeps +slashpackage := $slashpackage +sproot := $sproot +version := $version +home := $home +exthome := $exthome +SPAWN_LIB := ${spawn_lib} +SOCKET_LIB := ${socket_lib} +SYSCLOCK_LIB := ${sysclock_lib} +TAINNOW_LIB := ${tainnow_lib} +TIMER_LIB := ${timer_lib} +UTIL_LIB := ${util_lib} + +CC := ${CC_AUTO##${cross}} +CPPFLAGS_AUTO := $CPPFLAGS_AUTO +CPPFLAGS := $CPPFLAGS $CPPFLAGS_POST +CFLAGS_AUTO := $CFLAGS_AUTO +CFLAGS := $CFLAGS $CFLAGS_POST +LDFLAGS_AUTO := $LDFLAGS_AUTO +LDFLAGS := $LDFLAGS $LDFLAGS_POST +LDFLAGS_SHARED := $LDFLAGS_SHARED +LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED +CROSS_COMPILE := $cross + +vpath lib%.a$vpaths +vpath lib%.so$vpathd +EOF +if $allstatic ; then + echo ".LIBPATTERNS := lib%.a" + echo "DO_ALLSTATIC := 1" +else + echo ".LIBPATTERNS := lib%.so" +fi +if $static ; then + echo "DO_STATIC := 1" +else + echo "DO_STATIC :=" +fi +if $shared ; then + echo "DO_SHARED := 1" +else + echo "DO_SHARED :=" +fi +if $allpic ; then + echo "STATIC_LIBS_ARE_PIC := 1" +else + echo "STATIC_LIBS_ARE_PIC :=" +fi + +exec 1>&3 3>&- +echo " ... done." + +echo "creating src/include/${package}/config.h..." +mkdir -p -m 0755 src/include/${package} +exec 3>&1 1> src/include/${package}/config.h +cat <&3 3>&- +echo " ... done." diff --git a/doc/building.html b/doc/building.html new file mode 100644 index 0000000..649dc43 --- /dev/null +++ b/doc/building.html @@ -0,0 +1,103 @@ + + + + + + pamela: building an application + + + + + + +

+pamela
+Software
+skarnet.org +

+ +

Building an application with pamela instead of Linux-PAM

+ +

Prerequisites

+ +
    +
  • The pamela package must have been properly built and installed; +in particular, the pamelad binary must +have been properly linked against Linux-PAM's libpam.so.
  • +
  • The security/pam_appl.h header, usually installed in +/usr/include, must be a symlink to pamela's +pamela/pam.h header. This can be achieved by running +make install-symlink after make install when +building the pamela package.
  • +
  • The application must strictly follow the +Linux-PAM +specification. Note that the page claims that the +pam_set_item() function is declared in security/pam_modules.h, +but it is a mistake: like every PAM function used by applications, it +is declared in security/pam_appl.h.
  • +
  • The pamela headers and library must be installed, as well as the +skalibs headers and library.
  • +
+ +

Compiling

+ +
    +
  • Make sure that the pamela headers and the skalibs headers +are visible in your header search path, and that the +Linux-PAM headers are not.
  • +
  • If the compilation fails, please report the issue to the +skaware mailing-list. pamela is a work in progress, and there +may be compatibility issues that still need to be fixed.
  • +
+ +

Linking

+ +
    +
  • Make sure the pamela library, as well as the skalibs +library, are visible in your library search path.
  • +
  • Do not add -lpam to your linking command line. +Instead, add -lpamela -lskarnet. Depending on the +libc you're using, you may have to add -lrt too.
  • +
  • It is possible to statically link a binary using pamela: +the pamela and skalibs libraries do not use any dynamic loading, +and are suitable for static linking. Only the +pamelad binary uses dynamic module +loading and needs to be dynamically linked, and that is decided +at pamela build time, not at your application's build time.
  • +
  • Check your application binary's dynamic library dependencies +after it has been built. If your binary depends on libpam, +it has been incorrectly made! Your binary should depend on +libpamela and libskarnet, but not libpam. +If you have chosen to link against the static version of pamela +and skalibs, you may not even see the libpamela and +libskarnet dependencies.
  • +
+ +

Programming

+ +
    +
  • pamela strictly implements the +Linux-PAM +API
  • +
  • The pam_start() function will spawn a +pamelad binary running as a child of +the application, until pam_end() is called. At that point +the zombie is reaped.
  • +
  • If the pamelad binary is killed +during the PAM session, all PAM calls will return PAM_ABORT. +The application should then just exit, or call pam_end() +to free resources: nothing more can be done with the session.
  • +
+ +

Running

+ +
    +
  • If your application runs as root, you can set the +PAMELA_UID and PAMELA_GID environment variables to a non-zero +numeric uid and a nonzero numeric gid prior to running it. +The pamelad binary will then drop +its privileges and run under this uid/gid.
  • +
+ + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..3c2f58c --- /dev/null +++ b/doc/index.html @@ -0,0 +1,138 @@ + + + + + + + pamela - a secure PAM implementation + + + + + + +

+Software
+skarnet.org +

+ +

pamela

+ +

don't crack this root of mine

+ +

What is it ?

+ +

+ pamela stands for PAM Encapsulated Loading Architecture. +

+ +

+ It is a library implementing Linux-PAM's +security/pam_appl.h +header, for applications to use instead of the default Linux-PAM +security/pam_appl.h header. pamela wraps all PAM calls and +deports them to a pamelad binary running +as a child of the application, which performs the real calls to +Linux-PAM. +

+ +

+ The advantage of this setup is that it reduces the application's +attack surface considerably. Instead of loading modules into the +application's address space, PAM loads modules into the small, +dedicated pamelad binary, whose main source code is less than 400 +lines long. Also, if the application runs as root, the pamelad +binary can run as an unprivileged user, so modules cannot be used +for privilege elevation. +

+ +
+ +

Installation

+ +

Requirements

+ +
    +
  • A POSIX-compliant system with a standard C development environment, +that supports Linux-PAM - (so, probably a Linux system)
  • +
  • GNU make, version 3.81 or later
  • +
  • skalibs version +2.6.3.2 or later. It's a build-time requirement and a run-time +requirement.
  • +
  • Linux-PAM version 1.3.0 +or later. It's a build-time requirement and a run-time requirement.
  • +
+ +

Licensing

+ +

+ pamela is free software. It is available under the +ISC license. +

+ +

Download

+ +
    +
  • + pamela is a work in progress: there is no numbered version yet.
  • +
  • You can checkout a copy of the +pamela +git repository: +
     git clone git://git.skarnet.org/pamela 
  • +
  • There's also a +GitHub mirror +of the utmps git repository.
  • +
+ +

Compilation

+ +
    +
  • See the enclosed INSTALL file for installation details.
  • +
  • Please note that the build process expects security/pam_appl.h +to be a Linux-PAM header. Because of this, pamela's make install +does not overwrite security/pam_appl.h; instead, the header +exposing PAM functionality is named pamela/pam.h. When you are +positive you can replace the security/pam_appl.h header, +the make install-symlink command will do it for you.
  • +
+ +

Upgrade notes

+ +
    +
  • This page lists the differences to be aware of between +the previous versions of pamela and the current one.
  • +
+ +
+ +

Reference

+ +

Commands

+ + + +

Libraries

+ + + +
+ + +

Related resources

+
+ +

pamela discussion

+ +
    +
  • pamela is discussed on the +skaware mailing-list.
  • +
+ + + diff --git a/doc/pamelad.html b/doc/pamelad.html new file mode 100644 index 0000000..5d93c27 --- /dev/null +++ b/doc/pamelad.html @@ -0,0 +1,68 @@ + + + + + + pamela: the pamelad internal program + + + + + + +

+pamela
+Software
+skarnet.org +

+ +

The pamelad program

+ +

+pamelad is a helper program spawned by the pamela library, at pam_start() time. +It communicates with the main application process, reading requests from it, +performing PAM calls, and returning results to the application process. +

+ +

Interface

+ +

+ pamelad is not meant to be called directly. It is an unexported +program, i.e. a program that the package's library is supposed to find, but +that users should not run. Ideally it's kept outside of users' PATH variable. +

+ +

+ pamelad is declared as a libexec binary, so it will probably be +installed in /usr/libexec/pamelad or /usr/lib/pamela/pamelad, +depending on the admin/distribution's preferences. +

+ +

+ pamelad is run with two arguments, which are the service_name and +user arguments given to the pam_start() call. This will +display in a ps output, which is fine since this information is +not confidential. +

+ +

+ pamelad runs as the same uid and gid as the application. However, to +increase security of applications running as root: +

+ +
    +
  • If the application runs as gid 0 and the PAMELA_GID environment +variable is set, then pamelad will run with a gid set to $PAMELA_GID.
  • +
  • If the application runs as uid 0 and the PAMELA_UID environment +variable is set, then pamelad will run with a uid set to $PAMELA_UID.
  • +
+ +

+ pamelad makes the real calls to Linux-PAM. Keep that in mind when +configuring your PAM authorizations: if you're using the PAMELA_UID and +PAMELA_GID variables, make sure the uid/gid are not used anywhere else, +and give the proper PAM authorizations to that uid/gid pair instead of root. +

+ + + diff --git a/doc/upgrade.html b/doc/upgrade.html new file mode 100644 index 0000000..2d4ba44 --- /dev/null +++ b/doc/upgrade.html @@ -0,0 +1,28 @@ + + + + + + How to upgrade pamela + + + + + + +

+pamela
+Software
+skarnet.org +

+ +

What has changed in pamela

+ +

in 0.0.1.0

+ +

+ Initial release. +

+ + + diff --git a/package/deps-build b/package/deps-build new file mode 100644 index 0000000..05d5af4 --- /dev/null +++ b/package/deps-build @@ -0,0 +1 @@ +/package/prog/skalibs diff --git a/package/deps.mak b/package/deps.mak new file mode 100644 index 0000000..59c6f2a --- /dev/null +++ b/package/deps.mak @@ -0,0 +1,45 @@ +# +# This file has been generated by tools/gen-deps.sh +# + +src/include/pamela/pam.h: src/include/pamela/pamela.h +src/include/pamela/pamela.h: src/include/pamela/common.h +src/pamela/pamela-internal.h: src/include/pamela/pamela.h +src/pamela/pam_acct_mgmt.o src/pamela/pam_acct_mgmt.lo: src/pamela/pam_acct_mgmt.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_authenticate.o src/pamela/pam_authenticate.lo: src/pamela/pam_authenticate.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_chauthtok.o src/pamela/pam_chauthtok.lo: src/pamela/pam_chauthtok.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_close_session.o src/pamela/pam_close_session.lo: src/pamela/pam_close_session.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_end.o src/pamela/pam_end.lo: src/pamela/pam_end.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_fail_delay.o src/pamela/pam_fail_delay.lo: src/pamela/pam_fail_delay.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_get_item.o src/pamela/pam_get_item.lo: src/pamela/pam_get_item.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_getenv.o src/pamela/pam_getenv.lo: src/pamela/pam_getenv.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_getenvlist.o src/pamela/pam_getenvlist.lo: src/pamela/pam_getenvlist.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_open_session.o src/pamela/pam_open_session.lo: src/pamela/pam_open_session.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_putenv.o src/pamela/pam_putenv.lo: src/pamela/pam_putenv.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_set_item.o src/pamela/pam_set_item.lo: src/pamela/pam_set_item.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_setcred.o src/pamela/pam_setcred.lo: src/pamela/pam_setcred.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_start.o src/pamela/pam_start.lo: src/pamela/pam_start.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pam_strerror.o src/pamela/pam_strerror.lo: src/pamela/pam_strerror.c src/include/pamela/pam.h src/include/pamela/pamela.h +src/pamela/pamela_end.o src/pamela/pamela_end.lo: src/pamela/pamela_end.c src/include/pamela/pamela.h +src/pamela/pamela_get_item.o src/pamela/pamela_get_item.lo: src/pamela/pamela_get_item.c src/pamela/pamela-internal.h src/include/pamela/pamela.h +src/pamela/pamela_getenvlist.o src/pamela/pamela_getenvlist.lo: src/pamela/pamela_getenvlist.c src/pamela/pamela-internal.h src/include/pamela/pamela.h +src/pamela/pamela_op.o src/pamela/pamela_op.lo: src/pamela/pamela_op.c src/include/pamela/pamela.h +src/pamela/pamela_pam_response_free.o src/pamela/pamela_pam_response_free.lo: src/pamela/pamela_pam_response_free.c src/include/pamela/pamela.h +src/pamela/pamela_query_string.o src/pamela/pamela_query_string.lo: src/pamela/pamela_query_string.c src/include/pamela/pamela.h +src/pamela/pamela_set_item.o src/pamela/pamela_set_item.lo: src/pamela/pamela_set_item.c src/pamela/pamela-internal.h src/include/pamela/pamela.h +src/pamela/pamela_set_item_internal.o src/pamela/pamela_set_item_internal.lo: src/pamela/pamela_set_item_internal.c src/include/pamela/pamela.h +src/pamela/pamela_set_itemv.o src/pamela/pamela_set_itemv.lo: src/pamela/pamela_set_itemv.c src/pamela/pamela-internal.h src/include/pamela/pamela.h +src/pamela/pamela_startf.o src/pamela/pamela_startf.lo: src/pamela/pamela_startf.c src/include/pamela/config.h src/include/pamela/pamela.h +src/pamela/pamela_strerror.o src/pamela/pamela_strerror.lo: src/pamela/pamela_strerror.c src/pamela/pamela-internal.h src/include/pamela/pamela.h +src/pamela/pamela_zero.o src/pamela/pamela_zero.lo: src/pamela/pamela_zero.c src/include/pamela/pamela.h +src/pamela/pamelad.o src/pamela/pamelad.lo: src/pamela/pamelad.c src/include/pamela/common.h + +ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) +libpamela.a.xyzzy: src/pamela/pam_acct_mgmt.o src/pamela/pam_authenticate.o src/pamela/pam_chauthtok.o src/pamela/pam_close_session.o src/pamela/pam_end.o src/pamela/pam_fail_delay.o src/pamela/pam_get_item.o src/pamela/pam_getenv.o src/pamela/pam_getenvlist.o src/pamela/pam_open_session.o src/pamela/pam_putenv.o src/pamela/pam_set_item.o src/pamela/pam_setcred.o src/pamela/pam_start.o src/pamela/pam_strerror.o src/pamela/pamela_end.o src/pamela/pamela_get_item.o src/pamela/pamela_getenvlist.o src/pamela/pamela_op.o src/pamela/pamela_pam_response_free.o src/pamela/pamela_query_string.o src/pamela/pamela_set_item.o src/pamela/pamela_set_item_internal.o src/pamela/pamela_set_itemv.o src/pamela/pamela_startf.o src/pamela/pamela_strerror.o src/pamela/pamela_zero.o +else +libpamela.a.xyzzy: src/pamela/pam_acct_mgmt.lo src/pamela/pam_authenticate.lo src/pamela/pam_chauthtok.lo src/pamela/pam_close_session.lo src/pamela/pam_end.lo src/pamela/pam_fail_delay.lo src/pamela/pam_get_item.lo src/pamela/pam_getenv.lo src/pamela/pam_getenvlist.lo src/pamela/pam_open_session.lo src/pamela/pam_putenv.lo src/pamela/pam_set_item.lo src/pamela/pam_setcred.lo src/pamela/pam_start.lo src/pamela/pam_strerror.lo src/pamela/pamela_end.lo src/pamela/pamela_get_item.lo src/pamela/pamela_getenvlist.lo src/pamela/pamela_op.lo src/pamela/pamela_pam_response_free.lo src/pamela/pamela_query_string.lo src/pamela/pamela_set_item.lo src/pamela/pamela_set_item_internal.lo src/pamela/pamela_set_itemv.lo src/pamela/pamela_startf.lo src/pamela/pamela_strerror.lo src/pamela/pamela_zero.lo +endif +libpamela.so.xyzzy: EXTRA_LIBS := +libpamela.so.xyzzy: src/pamela/pam_acct_mgmt.lo src/pamela/pam_authenticate.lo src/pamela/pam_chauthtok.lo src/pamela/pam_close_session.lo src/pamela/pam_end.lo src/pamela/pam_fail_delay.lo src/pamela/pam_get_item.lo src/pamela/pam_getenv.lo src/pamela/pam_getenvlist.lo src/pamela/pam_open_session.lo src/pamela/pam_putenv.lo src/pamela/pam_set_item.lo src/pamela/pam_setcred.lo src/pamela/pam_start.lo src/pamela/pam_strerror.lo src/pamela/pamela_end.lo src/pamela/pamela_get_item.lo src/pamela/pamela_getenvlist.lo src/pamela/pamela_op.lo src/pamela/pamela_pam_response_free.lo src/pamela/pamela_query_string.lo src/pamela/pamela_set_item.lo src/pamela/pamela_set_item_internal.lo src/pamela/pamela_set_itemv.lo src/pamela/pamela_startf.lo src/pamela/pamela_strerror.lo src/pamela/pamela_zero.lo +pamelad: EXTRA_LIBS := ${PAM_LIB} +pamelad: src/pamela/pamelad.o -lskarnet diff --git a/package/info b/package/info new file mode 100644 index 0000000..2b5379b --- /dev/null +++ b/package/info @@ -0,0 +1,4 @@ +package=pamela +version=0.0.1.0 +category=admin +package_macro_name=PAMELA diff --git a/package/modes b/package/modes new file mode 100644 index 0000000..e3b7c4e --- /dev/null +++ b/package/modes @@ -0,0 +1 @@ +pamelad 0755 diff --git a/package/targets.mak b/package/targets.mak new file mode 100644 index 0000000..6d1a06b --- /dev/null +++ b/package/targets.mak @@ -0,0 +1,14 @@ +BIN_TARGETS := + +LIBEXEC_TARGETS := pamelad + +LIB_DEFS := PAMELA=pamela + +PAM_LIB := -lpam + +$(DESTDIR)$(includedir)/security/pam_appl.h: $(DESTDIR)$(includedir)/$(package)/pam.h + exec $(INSTALL) -D -l ../$(package)/pam.h $@ + +install-symlink: $(DESTDIR)$(includedir)/security/pam_appl.h + +.PHONY: install-symlink diff --git a/patch-for-solaris b/patch-for-solaris new file mode 100755 index 0000000..2d1296b --- /dev/null +++ b/patch-for-solaris @@ -0,0 +1,21 @@ +#!/usr/xpg4/bin/sh + +patchit () { + echo '#!/usr/xpg4/bin/sh' > $1.tmp + tail -n +2 $1 >> $1.tmp + mv -f $1.tmp $1 + chmod 755 $1 +} + +# Solaris doesn't understand POSIX.1-2008 either. +sed -e 's/XOPEN_SOURCE=700/XOPEN_SOURCE=600/' < configure > configure.tmp +mv -f configure.tmp configure + +patchit ./configure +patchit ./tools/install.sh +patchit ./tools/gen-deps.sh + +echo 'SHELL := /usr/xpg4/bin/sh' > Makefile.tmp +echo >> Makefile.tmp +cat Makefile >> Makefile.tmp +mv -f Makefile.tmp Makefile diff --git a/src/include/pamela/common.h b/src/include/pamela/common.h new file mode 100644 index 0000000..5ae689e --- /dev/null +++ b/src/include/pamela/common.h @@ -0,0 +1,101 @@ +/* ISC license. */ + +#ifndef PAMELA_COMMON_H +#define PAMELA_COMMON_H + +#define PAMELA_BUFSIZE 4096 + +enum pamela_retcode_e +{ + PAMELA_PAM_SUCCESS = 0, + PAMELA_PAM_OPEN_ERR, + PAMELA_PAM_SYMBOL_ERR, + PAMELA_PAM_SERVICE_ERR, + PAMELA_PAM_SYSTEM_ERR, + PAMELA_PAM_BUF_ERR, + PAMELA_PAM_PERM_DENIED, + PAMELA_PAM_AUTH_ERR, + PAMELA_PAM_CRED_INSUFFICIENT, + PAMELA_PAM_AUTHINFO_UNAVAIL, + PAMELA_PAM_USER_UNKNOWN, + PAMELA_PAM_MAXTRIES, + PAMELA_PAM_NEW_AUTHTOK_REQD, + PAMELA_PAM_ACCT_EXPIRED, + PAMELA_PAM_SESSION_ERR, + PAMELA_PAM_CRED_UNAVAIL, + PAMELA_PAM_CRED_EXPIRED, + PAMELA_PAM_CRED_ERR, + PAMELA_PAM_NO_MODULE_DATA, + PAMELA_PAM_CONV_ERR, + PAMELA_PAM_AUTHTOK_ERR, + PAMELA_PAM_AUTHTOK_RECOVERY_ERR, + PAMELA_PAM_AUTHTOK_LOCK_BUSY, + PAMELA_PAM_AUTHTOK_DISABLE_AGING, + PAMELA_PAM_TRY_AGAIN, + PAMELA_PAM_IGNORE, + PAMELA_PAM_ABORT, + PAMELA_PAM_AUTHTOK_EXPIRED, + PAMELA_PAM_MODULE_UNKNOWN, + PAMELA_PAM_BAD_ITEM, + PAMELA_PAM_CONV_AGAIN, + PAMELA_PAM_INCOMPLETE +} ; + + +enum pamela_item_e +{ + PAMELA_ENV = 0, + PAMELA_PAM_SERVICE, + PAMELA_PAM_USER, + PAMELA_PAM_TTY, + PAMELA_PAM_RHOST, + PAMELA_PAM_CONV, + PAMELA_PAM_AUTHTOK, + PAMELA_PAM_OLDAUTHTOK, + PAMELA_PAM_RUSER, + PAMELA_PAM_USER_PROMPT, + PAMELA_PAM_FAIL_DELAY, + PAMELA_PAM_XDISPLAY, + PAMELA_PAM_XAUTHDATA, + PAMELA_PAM_AUTHTOK_TYPE +} ; + + +enum pamela_convmsgtype_e +{ + PAMELA_PAM_PROMPT_ECHO_OFF = 1, + PAMELA_PAM_PROMPT_ECHO_ON, + PAMELA_PAM_ERROR_MSG, + PAMELA_PAM_TEXT_INFO, + PAMELA_PAM_RADIO_TYPE, + PAMELA_PAM_BINARY_PROMPT = 7 +} ; + +#define PAMELA_PAM_CONV_MAX_MESSAGES 1024 + + +enum pamela_op_e +{ + PAMELA_OP_ACCT_MGMT = 1, + PAMELA_OP_AUTHENTICATE, + PAMELA_OP_CHAUTHTOK, + PAMELA_OP_CLOSE_SESSION, + PAMELA_OP_FAIL_DELAY, + PAMELA_OP_OPEN_SESSION, + PAMELA_OP_SETCRED, + PAMELA_OP_SETFAILDELAY, + PAMELA_OP_END +} ; + + + /* flags */ + +#define PAMELA_PAM_SILENT 0x8000U +#define PAMELA_PAM_DISALLOW_NULL_AUTHTOK 0x0001U +#define PAMELA_PAM_ESTABLISH_CRED 0x0002U +#define PAMELA_PAM_DELETE_CRED 0x0004U +#define PAMELA_PAM_REINITIALIZE_CRED 0x0008U +#define PAMELA_PAM_REFRESH_CRED 0x0010U +#define PAMELA_PAM_CHANGE_EXPIRED_AUTHTOK 0x0020U + +#endif diff --git a/src/include/pamela/pam.h b/src/include/pamela/pam.h new file mode 100644 index 0000000..aab7d7d --- /dev/null +++ b/src/include/pamela/pam.h @@ -0,0 +1,161 @@ +/* ISC license. */ + +#ifndef PAMELA_PAM_H +#define PAMELA_PAM_H + + /* + This is pamela's client-side PAM library. + + */ + +#include +#include +#include + +#define __LINUX_PAM__ 1 +#define __LINUX_PAM_MINOR__ 0 + + + /* Return codes */ + +#define _PAM_RETURN_VALUES 32 + +#define PAM_SUCCESS PAMELA_PAM_SUCCESS +#define PAM_OPEN_ERR PAMELA_PAM_OPEN_ERR +#define PAM_SYMBOL_ERR PAMELA_PAM_SYMBOL_ERR +#define PAM_SERVICE_ERR PAMELA_PAM_SERVICE_ERR +#define PAM_SYSTEM_ERR PAMELA_PAM_SYSTEM_ERR +#define PAM_BUF_ERR PAMELA_PAM_BUF_ERR +#define PAM_PERM_DENIED PAMELA_PAM_PERM_DENIED +#define PAM_AUTH_ERR PAMELA_PAM_AUTH_ERR +#define PAM_CRED_INSUFFICIENT PAMELA_PAM_CRED_INSUFFICIENT +#define PAM_AUTHINFO_UNAVAIL PAMELA_PAM_AUTHINFO_UNAVAIL +#define PAM_USER_UNKNOWN PAMELA_PAM_USER_UNKNOWN +#define PAM_MAXTRIES PAMELA_PAM_MAXTRIES +#define PAM_NEW_AUTHTOK_REQD PAMELA_PAM_NEW_AUTHTOK_REQD +#define PAM_ACCT_EXPIRED PAMELA_PAM_ACCT_EXPIRED +#define PAM_SESSION_ERR PAMELA_PAM_SESSION_ERR +#define PAM_CRED_UNAVAIL PAMELA_PAM_CRED_UNAVAIL +#define PAM_CRED_EXPIRED PAMELA_PAM_CRED_EXPIRED +#define PAM_CRED_ERR PAMELA_PAM_CRED_ERR +#define PAM_NO_MODULE_DATA PAMELA_PAM_NO_MODULE_DATA +#define PAM_CONV_ERR PAMELA_PAM_CONV_ERR +#define PAM_AUTHTOK_ERR PAMELA_PAM_AUTHTOK_ERR +#define PAM_AUTHTOK_RECOVERY_ERR PAMELA_PAM_AUTHTOK_RECOVERY_ERR +#define PAM_AUTHTOK_LOCK_BUSY PAMELA_PAM_AUTHTOK_LOCK_BUSY +#define PAM_AUTHTOK_DISABLE_AGING PAMELA_PAM_AUTHTOK_DISABLE_AGING +#define PAM_TRY_AGAIN PAMELA_PAM_TRY_AGAIN +#define PAM_IGNORE PAMELA_PAM_IGNORE +#define PAM_ABORT PAMELA_PAM_ABORT +#define PAM_AUTHTOK_EXPIRED PAMELA_PAM_AUTHTOK_EXPIRED +#define PAM_MODULE_UNKNOWN PAMELA_PAM_MODULE_UNKNOWN +#define PAM_BAD_ITEM PAMELA_PAM_BAD_ITEM +#define PAM_CONV_AGAIN PAMELA_PAM_CONV_AGAIN +#define PAM_INCOMPLETE PAMELA_PAM_INCOMPLETE + + + /* Items */ + +#define PAM_ITEM_MAX 14 /* 13 items + environment */ + +#define PAM_SERVICE PAMELA_PAM_SERVICE +#define PAM_USER PAMELA_PAM_USER +#define PAM_TTY PAMELA_PAM_TTY +#define PAM_RHOST PAMELA_PAM_RHOST +#define PAM_CONV PAMELA_PAM_CONV +#define PAM_AUTHTOK PAMELA_PAM_AUTHTOK +#define PAM_OLDAUTHTOK PAMELA_PAM_OLDAUTHTOK +#define PAM_RUSER PAMELA_PAM_RUSER +#define PAM_USER_PROMPT PAMELA_PAM_USER_PROMPT +#define PAM_FAIL_DELAY PAMELA_PAM_FAIL_DELAY +#define PAM_XDISPLAY PAMELA_PAM_XDISPLAY +#define PAM_XAUTHDATA PAMELA_PAM_XAUTHDATA +#define PAM_AUTHTOK_TYPE PAMELA_PAM_AUTHTOK_TYPE + + + /* Flags */ + +#define PAM_SILENT PAMELA_PAM_SILENT +#define PAM_DISALLOW_NULL_AUTHTOK PAMELA_PAM_DISALLOW_NULL_AUTHTOK +#define PAM_ESTABLISH_CRED PAMELA_PAM_ESTABLISH_CRED +#define PAM_DELETE_CRED PAMELA_PAM_DELETE_CRED +#define PAM_REINITIALIZE_CRED PAMELA_PAM_REINITIALIZE_CRED +#define PAM_REFRESH_CRED PAMELA_PAM_REFRESH_CRED +#define PAM_CHANGE_EXPIRED_AUTHTOK PAMELA_PAM_CHANGE_EXPIRED_AUTHTOK + + + /* Conversation types */ + +#define PAM_PROMPT_ECHO_OFF PAMELA_PAM_PROMPT_ECHO_OFF +#define PAM_PROMPT_ECHO_ON PAMELA_PAM_PROMPT_ECHO_ON +#define PAM_ERROR_MSG PAMELA_PAM_ERROR_MSG +#define PAM_TEXT_INFO PAMELA_PAM_TEXT_INFO +#define PAM_RADIO_TYPE PAMELA_PAM_RADIO_TYPE +#define PAM_BINARY_PROMPT PAMELA_PAM_BINARY_PROMPT + + + /* Misc Linux-PAM stuff */ + +#define PAM_MAX_NUM_MSG 32 +#define PAM_MAX_MSG_SIZE 512 +#define PAM_MAX_RESP_SIZE 512 + +#define PAM_DATA_SILENT PAMELA_PAM_DATA_SILENT + + + /* Data structures and functions */ + +struct pam_message +{ + int msg_style ; + char const *msg ; +} ; + +struct pam_response +{ + char *resp ; + int resp_retcode ; +} ; + +struct pam_conv +{ + int (*conv) (int, struct pam_message const **, struct pam_response **, void *) ; + void *appdata_ptr ; +} ; + +struct pam_xauth_data +{ + int namelen ; + char *name ; + int datalen ; + char *data ; +} ; + +typedef struct pam_handle_s pam_handle_t ; +struct pam_handle_s +{ + pamela_t handle ; + struct pam_xauth_data xauthdata ; + stralloc err[_PAM_RETURN_VALUES] ; + stralloc item[PAM_ITEM_MAX] ; + uint64_t flagerrcached : _PAM_RETURN_VALUES ; + uint64_t flagenvcached : 1 ; +} ; + +extern int pam_start (char const *, char const *, struct pam_conv const *, pam_handle_t **) ; +extern int pam_end (pam_handle_t *, int) ; +extern int pam_set_item (pam_handle_t *, int, void const *) ; +extern int pam_get_item (pam_handle_t *, int, void const **) ; +extern char const *pam_strerror (pam_handle_t *, int) ; +extern int pam_fail_delay (pam_handle_t *, unsigned int) ; +extern int pam_authenticate (pam_handle_t *, int) ; +extern int pam_setcred (pam_handle_t *, int) ; +extern int pam_acct_mgmt (pam_handle_t *, int) ; +extern int pam_chauthtok (pam_handle_t *, int) ; +extern int pam_open_session (pam_handle_t *, int) ; +extern int pam_close_session (pam_handle_t *, int) ; +extern int pam_putenv (pam_handle_t *, char const *) ; +extern char const *pam_getenv (pam_handle_t *, char const *) ; +extern char **pam_getenvlist (pam_handle_t *) ; + +#endif diff --git a/src/include/pamela/pamela.h b/src/include/pamela/pamela.h new file mode 100644 index 0000000..ca45124 --- /dev/null +++ b/src/include/pamela/pamela.h @@ -0,0 +1,80 @@ +/* ISC license. */ + +#ifndef PAMELA_H +#define PAMELA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include + + + /* pam_fail_delay */ + +typedef void pamela_pam_delay_func_t (int, unsigned int, void *) ; +typedef pamela_pam_delay_func_t *pamela_pam_delay_func_t_ref ; + + + /* Conversations */ + +typedef struct pamela_pam_message_s pamela_pam_message_t, *pamela_pam_message_t_ref ; +struct pamela_pam_message_s +{ + int msg_style ; + char const *msg ; +} ; + +typedef struct pamela_pam_response_s pamela_pam_response_t, *pamela_pam_response_t_ref ; +struct pamela_pam_response_s +{ + char *resp ; + int *resp_retcode ; +} ; + +extern void pamela_pam_response_free (pamela_pam_response_t *, uint32_t) ; + +typedef int pamela_pam_conv_func_t (int, pamela_pam_message_t const **, pamela_pam_response_t **, void *) ; +typedef pamela_pam_conv_func_t *pamela_pam_conv_func_t_ref ; + + + /* Client handle */ + +typedef struct pamela_s pamela_t, *pamela_t_ref ; +struct pamela_s +{ + textmessage_receiver_t in ; + textmessage_sender_t out ; + pid_t pid ; + pamela_pam_delay_func_t_ref delayfn ; + pamela_pam_conv_func_t_ref convfn ; + void *aux ; + char inbuf[PAMELA_BUFSIZE] ; +} ; +#define PAMELA_ZERO { TEXTMESSAGE_RECEIVER_ZERO, TEXTMESSAGE_SENDER_ZERO, 0, 0, 0, 0, "" } + +extern pamela_t const pamela_zero ; + + + /* User-facing functions */ + +extern int pamela_startf (pamela_t *, char const *, char const *, pamela_pam_conv_func_t_ref, void *) ; +extern void pamela_end (pamela_t *) ; +extern int pamela_strerror (pamela_t *, unsigned char, stralloc *) ; +extern int pamela_getenvlist (pamela_t *, stralloc *) ; +extern int pamela_get_item (pamela_t *, unsigned char, stralloc *) ; +extern int pamela_set_item (pamela_t *, unsigned char, char const *) ; +extern int pamela_set_itemv (pamela_t *, unsigned char, struct iovec const *, unsigned int) ; +extern int pamela_op (pamela_t *, unsigned char, int) ; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/pamela/deps-exe/pamelad b/src/pamela/deps-exe/pamelad new file mode 100644 index 0000000..3294b7e --- /dev/null +++ b/src/pamela/deps-exe/pamelad @@ -0,0 +1,2 @@ +-lskarnet +${PAM_LIB} diff --git a/src/pamela/deps-lib/pamela b/src/pamela/deps-lib/pamela new file mode 100644 index 0000000..0b749c3 --- /dev/null +++ b/src/pamela/deps-lib/pamela @@ -0,0 +1,27 @@ +pam_acct_mgmt.o +pam_authenticate.o +pam_chauthtok.o +pam_close_session.o +pam_end.o +pam_fail_delay.o +pam_get_item.o +pam_getenv.o +pam_getenvlist.o +pam_open_session.o +pam_putenv.o +pam_set_item.o +pam_setcred.o +pam_start.o +pam_strerror.o +pamela_end.o +pamela_get_item.o +pamela_getenvlist.o +pamela_op.o +pamela_pam_response_free.o +pamela_query_string.o +pamela_set_item.o +pamela_set_item_internal.o +pamela_set_itemv.o +pamela_startf.o +pamela_strerror.o +pamela_zero.o diff --git a/src/pamela/pam_acct_mgmt.c b/src/pamela/pam_acct_mgmt.c new file mode 100644 index 0000000..bd65b2a --- /dev/null +++ b/src/pamela/pam_acct_mgmt.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +int pam_acct_mgmt (pam_handle_t *pamh, int flags) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + return pamela_op(&pamh->handle, PAMELA_OP_ACCT_MGMT, flags) ; +} diff --git a/src/pamela/pam_authenticate.c b/src/pamela/pam_authenticate.c new file mode 100644 index 0000000..5e31b0b --- /dev/null +++ b/src/pamela/pam_authenticate.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +int pam_authenticate (pam_handle_t *pamh, int flags) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + return pamela_op(&pamh->handle, PAMELA_OP_AUTHENTICATE, flags) ; +} diff --git a/src/pamela/pam_chauthtok.c b/src/pamela/pam_chauthtok.c new file mode 100644 index 0000000..53f639f --- /dev/null +++ b/src/pamela/pam_chauthtok.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +int pam_chauthtok (pam_handle_t *pamh, int flags) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + return pamela_op(&pamh->handle, PAMELA_OP_CHAUTHTOK, flags) ; +} diff --git a/src/pamela/pam_close_session.c b/src/pamela/pam_close_session.c new file mode 100644 index 0000000..989bddf --- /dev/null +++ b/src/pamela/pam_close_session.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +int pam_close_session (pam_handle_t *pamh, int flags) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + return pamela_op(&pamh->handle, PAMELA_OP_CLOSE_SESSION, flags) ; +} diff --git a/src/pamela/pam_end.c b/src/pamela/pam_end.c new file mode 100644 index 0000000..8da0dbd --- /dev/null +++ b/src/pamela/pam_end.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include +#include +#include +#include + +int pam_end (pam_handle_t *pamh, int pam_status) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + pamela_op(&pamh->handle, PAMELA_OP_END, pam_status) ; + pamela_end(&pamh->handle) ; + for (unsigned int i = 0 ; i < _PAM_RETURN_VALUES ; i++) stralloc_free(&pamh->err[i]) ; + for (unsigned int i = 0 ; i < PAM_ITEM_MAX ; i++) stralloc_free(&pamh->item[i]) ; + free(pamh) ; + return PAM_SUCCESS ; +} diff --git a/src/pamela/pam_fail_delay.c b/src/pamela/pam_fail_delay.c new file mode 100644 index 0000000..ca5ffb4 --- /dev/null +++ b/src/pamela/pam_fail_delay.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +int pam_fail_delay (pam_handle_t *pamh, unsigned int usec) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + return pamela_op(&pamh->handle, PAMELA_OP_FAIL_DELAY, (int)usec) ; +} diff --git a/src/pamela/pam_get_item.c b/src/pamela/pam_get_item.c new file mode 100644 index 0000000..e9499fd --- /dev/null +++ b/src/pamela/pam_get_item.c @@ -0,0 +1,52 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include + +static int xauthdata_unpack (pam_handle_t *pamh) +{ + uint32_t namelen, datalen ; + uint32_unpack_big(pamh->item[PAM_XAUTHDATA].s, &namelen) ; + uint32_unpack_big(pamh->item[PAM_XAUTHDATA].s + 4, &datalen) ; + if (namelen + datalen + 10 != pamh->item[PAM_XAUTHDATA].len) return 0 ; + pamh->xauthdata.namelen = (int)namelen ; + pamh->xauthdata.datalen = (int)namelen ; + pamh->xauthdata.name = pamh->item[PAM_XAUTHDATA].s + 8 ; + pamh->xauthdata.data = pamh->item[PAM_XAUTHDATA].s + 9 + namelen ; + return 1 ; +} + +int pam_get_item (pam_handle_t *pamh, int item_type, void const **item) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + if (item_type < 1 || item_type >= PAM_ITEM_MAX) return PAM_BAD_ITEM ; + switch (item_type) + { + case PAM_FAIL_DELAY : + *item = (void const *)pamh->handle.delayfn ; + return PAM_SUCCESS ; + case PAM_CONV : + *item = (void const *)pamh->handle.convfn ; + return PAM_SUCCESS ; + default : break ; + } + pamh->item[item_type].len = 0 ; + { + int e = pamela_get_item(&pamh->handle, (unsigned char)item_type, &pamh->item[item_type]) ; + if (e) return e ; + } + switch (item_type) + { + case PAM_XAUTHDATA : + if (!xauthdata_unpack(pamh)) return PAM_ABORT ; + *item = (void const *)&pamh->xauthdata ; + break ; + default : + *item = (void const *)pamh->item[item_type].s ; + break ; + } + return PAM_SUCCESS ; +} diff --git a/src/pamela/pam_getenv.c b/src/pamela/pam_getenv.c new file mode 100644 index 0000000..f743b48 --- /dev/null +++ b/src/pamela/pam_getenv.c @@ -0,0 +1,32 @@ +/* ISC license. */ + +#include +#include +#include +#include + +static char const *getvar (char const *s, size_t len, char const *var) +{ + size_t varlen = strlen(var) ; + size_t i = 0 ; + while (i < len) + { + if (!strncmp(var, s + i, varlen) && s[i + varlen] == '=') break ; + i += strlen(s + i) + 1 ; + } + return i < len ? s + i + varlen + 1 : 0 ; +} + +char const *pam_getenv (pam_handle_t *pamh, char const *name) +{ + stralloc *sa ; + if (!pamh) return 0 ; + sa = &pamh->item[PAMELA_ENV] ; + if (!pamh->flagenvcached) + { + sa->len = 0 ; + if (!pamela_getenvlist(&pamh->handle, sa)) return 0 ; + pamh->flagenvcached = 1 ; + } + return getvar(sa->s, sa->len, name) ; +} diff --git a/src/pamela/pam_getenvlist.c b/src/pamela/pam_getenvlist.c new file mode 100644 index 0000000..18b0da3 --- /dev/null +++ b/src/pamela/pam_getenvlist.c @@ -0,0 +1,42 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include + +char **pam_getenvlist (pam_handle_t *pamh) +{ + stralloc *sa ; + char **arr ; + char *p ; + size_t n ; + size_t i = 0 ; + if (!pamh) return 0 ; + sa = &pamh->item[PAMELA_ENV] ; + if (!pamh->flagenvcached) + { + sa->len = 0 ; + if (!pamela_getenvlist(&pamh->handle, sa)) return 0 ; + pamh->flagenvcached = 1 ; + } + n = byte_count(sa->s, sa->len, 0) ; + arr = malloc((n+1) * sizeof(char *)) ; + if (!arr) return 0 ; + p = sa->s ; + for (; i < n ; i++) + { + arr[i] = strdup(p) ; + if (!arr[i]) goto err ; + p += strlen(p) + 1 ; + } + arr[n] = 0 ; + return arr ; + + err: + while (i--) free(arr[i]) ; + free(arr) ; + return 0 ; +} diff --git a/src/pamela/pam_open_session.c b/src/pamela/pam_open_session.c new file mode 100644 index 0000000..25881b7 --- /dev/null +++ b/src/pamela/pam_open_session.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +int pam_open_session (pam_handle_t *pamh, int flags) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + return pamela_op(&pamh->handle, PAMELA_OP_OPEN_SESSION, flags) ; +} diff --git a/src/pamela/pam_putenv.c b/src/pamela/pam_putenv.c new file mode 100644 index 0000000..066d447 --- /dev/null +++ b/src/pamela/pam_putenv.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include +#include + +int pam_putenv (pam_handle_t *pamh, char const *name_value) +{ + int e ; + if (!pamh) return PAM_SYSTEM_ERR ; + e = pamela_set_item(&pamh->handle, PAMELA_ENV, name_value) ; + if (e) return e ; + pamh->flagenvcached = 0 ; + return PAM_SUCCESS ; +} diff --git a/src/pamela/pam_set_item.c b/src/pamela/pam_set_item.c new file mode 100644 index 0000000..03e08c0 --- /dev/null +++ b/src/pamela/pam_set_item.c @@ -0,0 +1,50 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include + +static int xauthdata_pack_and_set (pamela_t *a, struct pam_xauth_data const *d) +{ + if (d->namelen < 0 || d->datalen < 0) return PAM_SYSTEM_ERR ; + { + char buf[8] ; + struct iovec v[3] = + { + { .iov_base = buf, .iov_len = 8 }, + { .iov_base = d->name, .iov_len = d->namelen + 1 }, + { .iov_base = d->data, .iov_len = d->datalen + 1 } + } ; + uint32_pack_big(buf, (uint32_t)d->namelen) ; + uint32_pack_big(buf + 4, (uint32_t)d->datalen) ; + return pamela_set_itemv(a, PAM_XAUTHDATA, v, 3) ; + } +} + +int pam_set_item (pam_handle_t *pamh, int item_type, void const *item) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + if (item_type < 1 || item_type >= PAM_ITEM_MAX) return PAM_BAD_ITEM ; + switch (item_type) + { + case PAM_FAIL_DELAY : + { + int e ; + pamh->handle.delayfn = (pamela_pam_delay_func_t_ref)item ; + e = pamela_op(&pamh->handle, PAMELA_OP_SETFAILDELAY, 0) ; + if (e != PAM_SUCCESS) return e ; + break ; + } + case PAM_CONV : + pamh->handle.convfn = (pamela_pam_conv_func_t_ref)item ; + break ; + case PAM_XAUTHDATA : + return xauthdata_pack_and_set(&pamh->handle, (struct pam_xauth_data const *)item) ; + default : + return pamela_set_item(&pamh->handle, (uint32_t)item_type, (char const *)item) ; + } + return PAM_SUCCESS ; +} diff --git a/src/pamela/pam_setcred.c b/src/pamela/pam_setcred.c new file mode 100644 index 0000000..eddd2f9 --- /dev/null +++ b/src/pamela/pam_setcred.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +int pam_setcred (pam_handle_t *pamh, int flags) +{ + if (!pamh) return PAM_SYSTEM_ERR ; + return pamela_op(&pamh->handle, PAMELA_OP_SETCRED, flags) ; +} diff --git a/src/pamela/pam_start.c b/src/pamela/pam_start.c new file mode 100644 index 0000000..3847080 --- /dev/null +++ b/src/pamela/pam_start.c @@ -0,0 +1,34 @@ +/* ISC license. */ + +#include +#include +#include +#include + +static int pamela_dummy_conv (int num_msg, pamela_pam_message_t const **msg, pamela_pam_response_t **resp, void *aux) +{ + (void)num_msg ; + (void)msg ; + (void)resp ; + (void)aux ; + return PAMELA_PAM_CONV_ERR ; +} + +int pam_start (char const *service_name, char const *user, struct pam_conv const *pam_conversation, pam_handle_t **pamh) +{ + int e ; + pam_handle_t *a = malloc(sizeof(pam_handle_t)) ; + if (!a) return PAM_BUF_ERR ; + a->handle = pamela_zero ; + a->flagerrcached = a->flagenvcached = 0 ; + for (unsigned int i = 0 ; i < _PAM_RETURN_VALUES ; i++) a->err[i] = stralloc_zero ; + for (unsigned int i = 0 ; i < PAM_ITEM_MAX ; i++) a->item[i] = stralloc_zero ; + e = pamela_startf(&a->handle, service_name, user, pam_conversation && pam_conversation->conv ? (pamela_pam_conv_func_t_ref)pam_conversation->conv : &pamela_dummy_conv, pam_conversation ? pam_conversation->appdata_ptr : 0) ; + if (e) + { + free(a) ; + return e ; + } + *pamh = a ; + return PAM_SUCCESS ; +} diff --git a/src/pamela/pam_strerror.c b/src/pamela/pam_strerror.c new file mode 100644 index 0000000..fee63df --- /dev/null +++ b/src/pamela/pam_strerror.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include +#include + +char const *pam_strerror (pam_handle_t *pamh, int errnum) +{ + if (errnum < 0 || errnum >= _PAM_RETURN_VALUES) return 0 ; + if (!(pamh->flagerrcached & (1ULL << errnum))) + { + pamh->err[errnum].len = 0 ; + if (!pamela_strerror(&pamh->handle, (unsigned char)errnum, &pamh->err[errnum])) return 0 ; + if (!stralloc_0(&pamh->err[errnum])) return 0 ; + pamh->flagerrcached |= (1ULL << errnum) ; + } + return (char const *)pamh->err[errnum].s ; +} diff --git a/src/pamela/pamela-internal.h b/src/pamela/pamela-internal.h new file mode 100644 index 0000000..8de3a20 --- /dev/null +++ b/src/pamela/pamela-internal.h @@ -0,0 +1,13 @@ +/* ISC license. */ + +#ifndef PAMELA_INTERNAL_H +#define PAMELA_INTERNAL_H + +#include +#include +#include + +extern int pamela_query_string (pamela_t *, char const *, size_t, stralloc *) ; +extern int pamela_set_item_internal (pamela_t *, struct iovec const *, unsigned int) ; + +#endif diff --git a/src/pamela/pamela_end.c b/src/pamela/pamela_end.c new file mode 100644 index 0000000..09bb186 --- /dev/null +++ b/src/pamela/pamela_end.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include +#include +#include + +void pamela_end (pamela_t *a) +{ + int wstat ; + fd_close(textmessage_sender_fd(&a->out)) ; + textmessage_sender_free(&a->out) ; + fd_close(textmessage_receiver_fd(&a->in)) ; + textmessage_receiver_free(&a->in) ; + waitpid_nointr(a->pid, &wstat, 0) ; + *a = pamela_zero ; +} diff --git a/src/pamela/pamela_get_item.c b/src/pamela/pamela_get_item.c new file mode 100644 index 0000000..14fa56e --- /dev/null +++ b/src/pamela/pamela_get_item.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include "pamela-internal.h" + +int pamela_get_item (pamela_t *a, unsigned char what, stralloc *sa) +{ + char s[2] = "G" ; + s[1] = what ; + return pamela_query_string(a, s, 2, sa) ; +} diff --git a/src/pamela/pamela_getenvlist.c b/src/pamela/pamela_getenvlist.c new file mode 100644 index 0000000..ecc5013 --- /dev/null +++ b/src/pamela/pamela_getenvlist.c @@ -0,0 +1,9 @@ +/* ISC license. */ + +#include +#include "pamela-internal.h" + +int pamela_getenvlist (pamela_t *a, stralloc *sa) +{ + return pamela_query_string(a, "V", 1, sa) ; +} diff --git a/src/pamela/pamela_op.c b/src/pamela/pamela_op.c new file mode 100644 index 0000000..2d8ff76 --- /dev/null +++ b/src/pamela/pamela_op.c @@ -0,0 +1,123 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline int pamela_fail_delay (pamela_t *a, int r, unsigned int usec) +{ + (*a->delayfn)(r, usec, a->aux) ; + if (!textmessage_timed_send(&a->out, "D", 1, 0, 0)) return PAMELA_PAM_ABORT ; + return PAMELA_PAM_SUCCESS ; +} + +static inline int pamela_converse_and_answer (pamela_t *a, char const *s, size_t len) +{ + pamela_pam_response_t *res ; + uint32_t n ; + int e ; + char ans[2] = "C" ; + if (len < 4) return PAMELA_PAM_ABORT ; + uint32_unpack_big(s, &n) ; + s += 4 ; len -= 4 ; + if (n > PAMELA_PAM_CONV_MAX_MESSAGES) return PAMELA_PAM_ABORT ; + if (len < n * 5) return PAMELA_PAM_ABORT ; + { + pamela_pam_message_t messages[n] ; + pamela_pam_message_t const *arr[n] ; + for (uint32_t i = 0 ; i < n ; i++) + { + uint32_t u ; + uint32_unpack_big(s + 4 * i, &u) ; + messages[i].msg_style = u ; + arr[i] = &messages[i] ; + } + s += n * 4 ; len -= n * 4 ; + for (uint32_t i = 0 ; i < n ; i++) + { + size_t pos = strnlen(s, len) ; + if (pos == len) return PAMELA_PAM_ABORT ; + messages[i].msg = s ; + s += pos + 1 ; len -= pos + 1 ; + } + if (len) return PAMELA_PAM_ABORT ; + e = (*a->convfn)((int)n, arr, &res, a->aux) ; + } + if (e != PAMELA_PAM_SUCCESS) + { + ans[1] = (unsigned char)e ; + if (!textmessage_timed_send(&a->out, ans, 2, 0, 0)) return PAMELA_PAM_ABORT ; + } + else + { + struct iovec v[n+1] ; + v[0].iov_base = ans ; + v[0].iov_len = 2 ; + for (uint32_t i = 0 ; i < n ; i++) + { + v[i+1].iov_base = res[i].resp ; + v[i+1].iov_len = strlen(res[i].resp) + 1 ; + } + if (!textmessage_timed_sendv(&a->out, v, n+1, 0, 0)) + { + pamela_pam_response_free(res, n) ; + return PAMELA_PAM_ABORT ; + } + pamela_pam_response_free(res, n) ; + } + return PAMELA_PAM_SUCCESS ; +} + +int pamela_op (pamela_t *a, unsigned char type, int num) +{ + { + char pack[sizeof(int)] ; + struct iovec v[3] = + { + { .iov_base = "O", .iov_len = 1 }, + { .iov_base = &type, .iov_len = 1 }, + { .iov_base = pack, .iov_len = sizeof(int) } + } ; + int_pack_big(pack, num) ; + if (!textmessage_timed_sendv(&a->out, v, 3, 0, 0)) return PAMELA_PAM_SYSTEM_ERR ; + } + for (;;) + { + struct iovec v ; + char const *s ; + if (textmessage_timed_receive(&a->in, &v, 0, 0) <= 0) return PAMELA_PAM_ABORT ; + if (v.iov_len < 2) return PAMELA_PAM_ABORT ; + s = v.iov_base ; + switch (s[0]) + { + case 'o' : /* operation returns */ + if (v.iov_len != 2) return PAMELA_PAM_ABORT ; + return s[1] ; + case 'c' : /* conversation request */ + { + int e = pamela_converse_and_answer(a, s + 1, v.iov_len - 1) ; + if (e != PAMELA_PAM_SUCCESS) return e ; + break ; + } + case 'd' : /* fail_delay request */ + { + uint32_t u ; + int r ; + unsigned int usec ; + if (v.iov_len != 9) return PAMELA_PAM_ABORT ; + uint32_unpack_big(s + 1, &u) ; r = u ; + uint32_unpack_big(s + 5, &u) ; usec = u ; + r = pamela_fail_delay(a, r, usec) ; + if (r != PAMELA_PAM_SUCCESS) return r ; + break ; + } + default : return PAMELA_PAM_ABORT ; + } + } +} diff --git a/src/pamela/pamela_pam_response_free.c b/src/pamela/pamela_pam_response_free.c new file mode 100644 index 0000000..496928b --- /dev/null +++ b/src/pamela/pamela_pam_response_free.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include +#include + +void pamela_pam_response_free (pamela_pam_response_t *res, uint32_t n) +{ + for (uint32_t i = 0 ; i < n ; i++) free(res[i].resp) ; + free(res) ; +} diff --git a/src/pamela/pamela_query_string.c b/src/pamela/pamela_query_string.c new file mode 100644 index 0000000..27c131f --- /dev/null +++ b/src/pamela/pamela_query_string.c @@ -0,0 +1,20 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include + +int pamela_query_string (pamela_t *a, char const *s, size_t len, stralloc *sa) +{ + struct iovec v ; + if (!textmessage_timed_send(&a->out, s, len, 0, 0)) return 0 ; + if (textmessage_timed_receive(&a->in, &v, 0, 0) <= 0) return 0 ; + if (!v.iov_len) return (errno = EPROTO, 0) ; + s = v.iov_base ; + if (s[0]) return (errno = s[0], 0) ; + if (!stralloc_catb(sa, s + 1, v.iov_len - 1)) return 0 ; + return 1 ; +} diff --git a/src/pamela/pamela_set_item.c b/src/pamela/pamela_set_item.c new file mode 100644 index 0000000..faa3ee1 --- /dev/null +++ b/src/pamela/pamela_set_item.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include +#include +#include "pamela-internal.h" + +int pamela_set_item (pamela_t *a, unsigned char type, char const *s) +{ + struct iovec const v[3] = + { + { .iov_base = "S", .iov_len = 1 }, + { .iov_base = &type, .iov_len = 1 }, + { .iov_base = (char *)s, .iov_len = strlen(s) + 1 } + } ; + return pamela_set_item_internal(a, v, 3) ; +} diff --git a/src/pamela/pamela_set_item_internal.c b/src/pamela/pamela_set_item_internal.c new file mode 100644 index 0000000..ca92903 --- /dev/null +++ b/src/pamela/pamela_set_item_internal.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include +#include +#include + +int pamela_set_item_internal (pamela_t *a, struct iovec const *v, unsigned int n) +{ + struct iovec r ; + if (!textmessage_timed_sendv(&a->out, v, n, 0, 0)) return PAMELA_PAM_SYSTEM_ERR ; + if (textmessage_timed_receive(&a->in, &r, 0, 0) <= 0) return PAMELA_PAM_ABORT ; + if (r.iov_len != 1) return PAMELA_PAM_ABORT ; + return ((unsigned char const *)r.iov_base)[0] ; +} diff --git a/src/pamela/pamela_set_itemv.c b/src/pamela/pamela_set_itemv.c new file mode 100644 index 0000000..7f64d5a --- /dev/null +++ b/src/pamela/pamela_set_itemv.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include +#include +#include "pamela-internal.h" + +int pamela_set_itemv (pamela_t *a, unsigned char type, struct iovec const *v, unsigned int n) +{ + struct iovec vv[n+2] ; + vv[0].iov_base = "S" ; vv[0].iov_len = 1 ; + vv[1].iov_base = &type ; vv[1].iov_len = 1 ; + for (unsigned int i = 0 ; i < n ; i++) vv[i+2] = v[i] ; + return pamela_set_item_internal(a, vv, n+2) ; +} diff --git a/src/pamela/pamela_startf.c b/src/pamela/pamela_startf.c new file mode 100644 index 0000000..4d7ff46 --- /dev/null +++ b/src/pamela/pamela_startf.c @@ -0,0 +1,40 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include +#include + +int pamela_startf (pamela_t *a, char const *service_name, char const *user, pamela_pam_conv_func_t_ref convfn, void *aux) +{ + char const *argv[4] = { PAMELA_LIBEXECPREFIX "pamelad", service_name, user, 0 } ; + int fd[2] ; + pid_t pid = child_spawn2(argv[0], argv, (char const *const *)environ, fd) ; + int e = PAMELA_PAM_ABORT ; + struct iovec v ; + if (!pid) return 0 ; + textmessage_receiver_init(&a->in, fd[0], a->inbuf, PAMELA_BUFSIZE, TEXTMESSAGE_MAXLEN) ; + if (textmessage_timed_receive(&a->in, &v, 0, 0) <= 0) goto err ; + if (v.iov_len != 1) goto ferr ; + e = ((unsigned char const *)v.iov_base)[0] ; if (e) goto ferr ; + a->pid = pid ; + a->delayfn = 0 ; + a->convfn = convfn ; + a->aux = aux ; + textmessage_sender_init(&a->out, fd[1]) ; + return e ; + + ferr: + textmessage_receiver_free(&a->in) ; + err: + fd_close(fd[1]) ; + fd_close(fd[0]) ; + { + int wstat ; + waitpid_nointr(pid, &wstat, 0) ; + } + return e ; +} diff --git a/src/pamela/pamela_strerror.c b/src/pamela/pamela_strerror.c new file mode 100644 index 0000000..2e72a01 --- /dev/null +++ b/src/pamela/pamela_strerror.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include +#include "pamela-internal.h" + +int pamela_strerror (pamela_t *a, unsigned char e, stralloc *sa) +{ + char s[2] = "E" ; + s[1] = e ; + return pamela_query_string(a, s, 2, sa) ; +} diff --git a/src/pamela/pamela_zero.c b/src/pamela/pamela_zero.c new file mode 100644 index 0000000..70b3682 --- /dev/null +++ b/src/pamela/pamela_zero.c @@ -0,0 +1,5 @@ +/* ISC license. */ + +#include + +pamela_t const pamela_zero = PAMELA_ZERO ; diff --git a/src/pamela/pamelad.c b/src/pamela/pamelad.c new file mode 100644 index 0000000..0a55f66 --- /dev/null +++ b/src/pamela/pamelad.c @@ -0,0 +1,385 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USAGE "pamelad service_name user" + +static int cont = 1 ; +static pam_handle_t *pamh ; + + + /* Utility */ + +static void get (struct iovec *v) +{ + ssize_t r = textmessage_timed_receive(textmessage_receiver_0, v, 0, 0) ; + if (r < 0) _exit(1) ; + if (!r) _exit(0) ; +} + +static void put (char const *s, size_t len) +{ + if (!textmessage_timed_send(textmessage_sender_1, s, len, 0, 0)) + _exit(1) ; +} + +static void putv (struct iovec const *v, unsigned int n) +{ + if (!textmessage_timed_sendv(textmessage_sender_1, v, n, 0, 0)) + _exit(1) ; +} + +static inline void env_free (char **envp) +{ + char **p = envp ; + while (*p) free(*p++) ; + free(envp) ; +} + + + /* If the app customizes fail_delay */ + +static void custom_delay (int retval, unsigned int usec, void *aux) +{ + struct iovec v ; + char pack[9] = "d" ; + uint32_pack_big(pack+1, (uint32_t)retval) ; + uint32_pack_big(pack+5, (uint32_t)usec) ; + put(pack, 9) ; + get(&v) ; + if (v.iov_len != 1 || ((char const *)v.iov_base)[0] != 'D') _exit(1) ; + (void)aux ; +} + + + /* Conversation */ + +static void freeres (struct pam_response *res, unsigned int i) +{ + while (i--) free(res[i].resp) ; + free(res) ; +} + +static int converse (int n, struct pam_message const **msg, struct pam_response **resp, void *aux) +{ + if (n < 0 || n > PAMELA_PAM_CONV_MAX_MESSAGES) return PAM_SYSTEM_ERR ; + { + char pack[n * 4] ; + struct iovec v[n+2] ; + v[0].iov_base = "c" ; + v[0].iov_len = 1 ; + v[1].iov_base = pack ; + v[1].iov_len = n << 2 ; + for (uint32_t i = 0 ; i < n ; i++) uint32_pack_big(pack + 4 * i, (uint32_t)msg[i]->msg_style) ; + for (uint32_t i = 0 ; i < n ; i++) + { + v[i+2].iov_base = (char *)msg[i]->msg ; + v[i+2].iov_len = strlen(msg[i]->msg) + 1 ; + } + putv(v, n+2) ; + } + { + struct pam_response *res ; + struct iovec v ; + char const *s ; + size_t len ; + get(&v) ; + if (v.iov_len < 2) return PAM_ABORT ; + s = v.iov_base ; + len = v.iov_len - 2 ; + if (s[0] != 'C') return PAM_ABORT ; + if (s[1]) return s[1] ; + res = malloc(n * sizeof(struct pam_response)) ; + if (!res) return PAM_BUF_ERR ; + for (uint32_t i = 0 ; i < n ; i++) + { + size_t pos = strnlen(s, len) ; + if (pos == len) return PAM_ABORT ; + res[i].resp_retcode = 0 ; + res[i].resp = strdup(s) ; + if (!res[i].resp) + { + freeres(res, i) ; + return PAM_BUF_ERR ; + } + s += pos + 1 ; len -= pos + 1 ; + } + if (len) + { + freeres(res, n) ; + return PAM_ABORT ; + } + *resp = res ; + } + (void)aux ; + return PAM_SUCCESS ; +} + + + /* Protocol and actions */ + +static void do_strerror (int num) +{ + char const *x = pam_strerror(pamh, num) ; + if (!x) + { + char c = errno ; + put(&c, 1) ; + } + else + { + struct iovec v[2] = + { + { .iov_base = "", .iov_len = 1 }, + { .iov_base = (char *)x, .iov_len = strlen(x) + 1 } + } ; + putv(v, 2) ; + } +} + +static void do_getenvlist (void) +{ + char **envp = pam_getenvlist(pamh) ; + if (!envp) + { + char c = errno ; + put(&c, 1) ; + } + else + { + size_t n = env_len((char const *const *)envp) ; + struct iovec v[n+1] ; + v[0].iov_base = "" ; + v[0].iov_len = 1 ; + for (size_t i = 0 ; i < n ; i++) + { + v[i+1].iov_base = envp[i] ; + v[i+1].iov_len = strlen(envp[i]) + 1 ; + } + putv(v, n+1) ; + env_free(envp) ; + } +} + +static void do_getitem (int num) +{ + void const *item ; + int e = pam_get_item(pamh, num, &item) ; + if (e != PAM_SUCCESS) + { + char c = e ; + put(&c, 1) ; + return ; + } + switch (num) + { + case PAMELA_PAM_FAIL_DELAY : + case PAMELA_PAM_CONV : + { + char c = PAMELA_PAM_BAD_ITEM ; + put(&c, 1) ; + break ; + } + case PAMELA_PAM_XAUTHDATA : + { + struct pam_xauth_data const *p = item ; + char pack[8] ; + struct iovec v[4] = + { + { .iov_base = "", .iov_len = 1 }, + { .iov_base = pack, .iov_len = 8 }, + { .iov_base = p->name, .iov_len = p->namelen + 1 }, + { .iov_base = p->data, .iov_len = p->datalen + 1 } + } ; + uint32_pack_big(pack, (uint32_t)p->namelen) ; + uint32_pack_big(pack + 4, (uint32_t)p->datalen) ; + putv(v, 4) ; + break ; + } + default : + { + struct iovec v[2] = + { + { .iov_base = "", .iov_len = 1 }, + { .iov_base = (char *)item, .iov_len = strlen((char const *)item) + 1 } + } ; + putv(v, 2) ; + break ; + } + } +} + +static void do_setitem (int num, char const *s, size_t len) +{ + char c ; + switch (num) + { + case PAMELA_PAM_FAIL_DELAY : + case PAMELA_PAM_CONV : + baditem: + c = PAMELA_PAM_BAD_ITEM ; + break ; + case PAMELA_ENV : + if (s[len-1]) goto baditem ; + c = pam_putenv(pamh, s) ; + break ; + case PAMELA_PAM_XAUTHDATA : + { + struct pam_xauth_data xd ; + uint32_t u ; + if (len < 10) goto baditem ; + uint32_unpack_big(s, &u) ; + xd.namelen = u ; + uint32_unpack_big(s + 4, &u) ; + xd.datalen = u ; + if (len != 10 + xd.namelen + xd.datalen) goto baditem ; + xd.name = (char *)s + 8 ; + xd.data = (char *)s + 9 + xd.namelen ; + c = pam_set_item(pamh, PAM_XAUTHDATA, &xd) ; + break ; + } + default : + if (s[len-1]) goto baditem ; + c = pam_set_item(pamh, num, s) ; + break ; + } + put(&c, 1) ; +} + +static void do_op (char type, int num) +{ + char s[2] = "o" ; + switch (type) + { + case PAMELA_OP_ACCT_MGMT : + s[1] = pam_acct_mgmt(pamh, num) ; + break ; + case PAMELA_OP_AUTHENTICATE : + s[1] = pam_authenticate(pamh, num) ; + break ; + case PAMELA_OP_CHAUTHTOK : + s[1] = pam_chauthtok(pamh, num) ; + break ; + case PAMELA_OP_CLOSE_SESSION : + s[1] = pam_close_session(pamh, num) ; + break ; + case PAMELA_OP_FAIL_DELAY : + s[1] = pam_fail_delay(pamh, (unsigned int)num) ; + break ; + case PAMELA_OP_OPEN_SESSION : + s[1] = pam_open_session(pamh, num) ; + break ; + case PAMELA_OP_SETCRED : + s[1] = pam_setcred(pamh, num) ; + break ; + case PAMELA_OP_SETFAILDELAY : + s[1] = pam_set_item(pamh, PAM_FAIL_DELAY, &custom_delay) ; + break ; + case PAMELA_OP_END : + s[1] = pam_end(pamh, num) ; + break ; + default : + s[1] = PAM_ABORT ; + break ; + } + put(s, 2) ; + if (type == PAMELA_OP_END) _exit(0) ; +} + + + /* Main */ + +int main (int argc, char const *const *argv) +{ + PROG = "pamelad" ; + if (argc < 3) strerr_dieusage(100, USAGE) ; + if (ndelay_on(0) < 0) strerr_diefu2sys(111, "ndelay_on ", "0") ; + if (ndelay_on(1) < 0) strerr_diefu2sys(111, "ndelay_on ", "1") ; + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + + if (!getgid()) + { + char const *x = getenv("PAMELA_GID") ; + if (x) + { + gid_t g ; + if (!gid0_scan(x, &g)) + strerr_warnw1x("invalid PAMELA_GID, keeping gid 0") ; + else setgid(g) ; + } + } + if (!getuid()) + { + char const *x = getenv("PAMELA_UID") ; + if (x) + { + uid_t u ; + if (!uid0_scan(x, &u)) + strerr_warnw1x("invalid PAMELA_UID, keeping uid 0") ; + else setuid(u) ; + } + } + + { + struct pam_conv conv = { .conv = &converse, .appdata_ptr = 0 } ; + char c = pam_start(argv[1], argv[2], &conv, &pamh) ; + put(&c, 1) ; + if (c != PAM_SUCCESS) return 2 ; + } + + while (cont) + { + struct iovec v ; + char const *s ; + size_t len ; + get(&v) ; + len = v.iov_len ; + if (!len) return 1 ; + s = v.iov_base ; + switch (s[0]) + { + case 'E' : + if (len != 2) return 1 ; + do_strerror(s[1]) ; + break ; + case 'V' : + if (len != 1) return 1 ; + do_getenvlist() ; + break ; + case 'G' : + if (len != 2) return 1 ; + do_getitem(s[1]) ; + break ; + case 'S' : + if (len < 3) return 1 ; + do_setitem(s[1], s + 2, len - 2) ; + break ; + case 'O' : + { + unsigned int arg ; + if (len != 2 + sizeof(int)) return 1 ; + uint_unpack(s + 2, &arg) ; + do_op(s[1], (int)arg) ; + break ; + } + default : return 1 ; + } + } + return 0 ; +} diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh new file mode 100755 index 0000000..6383ac2 --- /dev/null +++ b/tools/gen-deps.sh @@ -0,0 +1,93 @@ +#!/bin/sh -e + +. package/info + +echo '#' +echo '# This file has been generated by tools/gen-deps.sh' +echo '#' +echo + +for dir in src/include/${package} src/* ; do + for file in $(ls -1 $dir | grep -- \\.h$) ; do + { + grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ; + grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2 + } | sort -u | { + deps= + while read dep ; do + if echo $dep | grep -q "^${package}/" ; then + deps="$deps src/include/$dep" + elif test -f "${dir}/$dep" ; then + deps="$deps ${dir}/$dep" + else + deps="$deps src/include-local/$dep" + fi + done + if test -n "$deps" ; then + echo "${dir}/${file}:${deps}" + fi + } + done +done + +for dir in src/* ; do + for file in $(ls -1 $dir | grep -- \\.c$) ; do + { + grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ; + grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2 + } | sort -u | { + deps=" ${dir}/$file" + while read dep ; do + if echo $dep | grep -q "^${package}/" ; then + deps="$deps src/include/$dep" + elif test -f "${dir}/$dep" ; then + deps="$deps ${dir}/$dep" + else + deps="$deps src/include-local/$dep" + fi + done + o=$(echo $file | sed s/\\.c$/.o/) + lo=$(echo $file | sed s/\\.c$/.lo/) + echo "${dir}/${o} ${dir}/${lo}:${deps}" + } + done +done +echo + +for dir in $(ls -1 src | grep -v ^include) ; do + for file in $(ls -1 src/$dir/deps-lib) ; do + deps= + libs= + while read dep ; do + if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then + libs="$libs $dep" + else + deps="$deps src/$dir/$dep" + fi + done < src/$dir/deps-lib/$file + echo 'ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)' + echo "lib${file}.a.xyzzy:$deps" + echo else + echo "lib${file}.a.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')" + echo endif + echo "lib${file}.so.xyzzy: EXTRA_LIBS :=$libs" + echo "lib${file}.so.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')" + done + + for file in $(ls -1 src/$dir/deps-exe) ; do + deps= + libs= + while read dep ; do + if echo $dep | grep -q -- \\.o$ ; then + dep="src/$dir/$dep" + fi + if echo $dep | grep -q -- '^\${.*_LIB}' ; then + libs="$libs $dep" + else + deps="$deps $dep" + fi + done < src/$dir/deps-exe/$file + echo "$file: EXTRA_LIBS :=$libs" + echo "$file: src/$dir/$file.o$deps" + done +done diff --git a/tools/install.sh b/tools/install.sh new file mode 100755 index 0000000..89f9428 --- /dev/null +++ b/tools/install.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +usage() { + echo "usage: $0 [-D] [-l] [-m mode] src dst" 1>&2 + exit 1 +} + +mkdirp=false +symlink=false +mode=0755 + +while getopts Dlm: name ; do + case "$name" in + D) mkdirp=true ;; + l) symlink=true ;; + m) mode=$OPTARG ;; + ?) usage ;; + esac +done +shift $(($OPTIND - 1)) + +test "$#" -eq 2 || usage +src=$1 +dst=$2 +tmp="$dst.tmp.$$" + +case "$dst" in + */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;; +esac + +set -C +set -e + +if $mkdirp ; then + umask 022 + case "$2" in + */*) mkdir -p "${dst%/*}" ;; + esac +fi + +trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP + +umask 077 + +if $symlink ; then + ln -s "$src" "$tmp" +else + cat < "$1" > "$tmp" + chmod "$mode" "$tmp" +fi + +mv -f "$tmp" "$dst" +if test -d "$dst" ; then + rm -f "$dst/$(basename $tmp)" + if $symlink ; then + mkdir "$tmp" + ln -s "$src" "$tmp/$(basename $dst)" + mv -f "$tmp/$(basename $dst)" "${dst%/*}" + rmdir "$tmp" + else + echo "$0: $dst is a directory" 1>&2 + exit 1 + fi +fi -- cgit 1.4.1