nss-pam-ldapd-0.9.6/ 0000755 0001750 0000144 00000000000 12537361547 011200 5 0000000 0000000 nss-pam-ldapd-0.9.6/ldapns.schema 0000644 0001750 0000144 00000001204 12106526306 013544 0000000 0000000 # LDAP Name Service Additional Schema
# Source: pam_ldap package by Luke Howard
# Has not been published in Internet Draft or RFC.
attributetype ( 1.3.6.1.4.1.5322.17.2.1 NAME 'authorizedService'
DESC 'IANA GSS-API authorized service name'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
objectclass ( 1.3.6.1.4.1.5322.17.1.1 NAME 'authorizedServiceObject'
DESC 'Auxiliary object class for adding authorizedService attribute'
SUP top
AUXILIARY
MAY authorizedService )
objectclass ( 1.3.6.1.4.1.5322.17.1.2 NAME 'hostObject'
DESC 'Auxiliary object class for adding host attribute'
SUP top
AUXILIARY
MAY host )
nss-pam-ldapd-0.9.6/config.guess 0000744 0001750 0000144 00000123550 12537036355 013440 0000000 0000000 #! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2014 Free Software Foundation, Inc.
timestamp='2014-03-23'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see .
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# Originally written by Per Bothner.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
Output the configuration name of the system \`$me' is run on.
Operation modes:
-h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
Report bugs and patches to ."
version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
Try \`$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
echo "$timestamp" ; exit ;;
--version | -v )
echo "$version" ; exit ;;
--help | --h* | -h )
echo "$usage"; exit ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
break ;;
-* )
echo "$me: invalid option $1$help" >&2
exit 1 ;;
* )
break ;;
esac
done
if test $# != 0; then
echo "$me: too many arguments$help" >&2
exit 1
fi
trap 'exit 1' 1 2 15
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.
# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated.
# Portable tmp directory creation inspired by the Autoconf team.
set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
{ tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
dummy=$tmp/dummy ;
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
case $CC_FOR_BUILD,$HOST_CC,$CC in
,,) echo "int x;" > $dummy.c ;
for c in cc gcc c89 c99 ; do
if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
CC_FOR_BUILD="$c"; break ;
fi ;
done ;
if test x"$CC_FOR_BUILD" = x ; then
CC_FOR_BUILD=no_compiler_found ;
fi
;;
,,*) CC_FOR_BUILD=$CC ;;
,*,*) CC_FOR_BUILD=$HOST_CC ;;
esac ; set_cc_for_build= ;'
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
PATH=$PATH:/.attbin ; export PATH
fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
case "${UNAME_SYSTEM}" in
Linux|GNU|GNU/*)
# If the system lacks a compiler, then just pick glibc.
# We could probably try harder.
LIBC=gnu
eval $set_cc_for_build
cat <<-EOF > $dummy.c
#include
#if defined(__UCLIBC__)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
#else
LIBC=gnu
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
;;
esac
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
# compatibility and a consistent mechanism for selecting the
# object file format.
#
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || echo unknown)`
case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
os=netbsd
else
os=netbsdelf
fi
;;
*)
os=netbsd
;;
esac
# The OS release
# Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need
# kernel version information, so it can be replaced with a
# suitable tag, in the style of linux-gnu.
case "${UNAME_VERSION}" in
Debian*)
release='-gnu'
;;
*)
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
exit ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
exit ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;;
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;;
*:SolidBSD:*:*)
echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
exit ;;
macppc:MirBSD:*:*)
echo powerpc-unknown-mirbsd${UNAME_RELEASE}
exit ;;
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
;;
*5.*)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
UNAME_MACHINE="alpha" ;;
"EV4.5 (21064)")
UNAME_MACHINE="alpha" ;;
"LCA4 (21066/21068)")
UNAME_MACHINE="alpha" ;;
"EV5 (21164)")
UNAME_MACHINE="alphaev5" ;;
"EV5.6 (21164A)")
UNAME_MACHINE="alphaev56" ;;
"EV5.6 (21164PC)")
UNAME_MACHINE="alphapca56" ;;
"EV5.7 (21164PC)")
UNAME_MACHINE="alphapca57" ;;
"EV6 (21264)")
UNAME_MACHINE="alphaev6" ;;
"EV6.7 (21264A)")
UNAME_MACHINE="alphaev67" ;;
"EV6.8CB (21264C)")
UNAME_MACHINE="alphaev68" ;;
"EV6.8AL (21264B)")
UNAME_MACHINE="alphaev68" ;;
"EV6.8CX (21264D)")
UNAME_MACHINE="alphaev68" ;;
"EV6.9A (21264/EV69A)")
UNAME_MACHINE="alphaev69" ;;
"EV7 (21364)")
UNAME_MACHINE="alphaev7" ;;
"EV7.9 (21364A)")
UNAME_MACHINE="alphaev79" ;;
esac
# A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
exit $exitcode ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
# of the specific Alpha model?
echo alpha-pc-interix
exit ;;
21064:Windows_NT:50:3)
echo alpha-dec-winnt3.5
exit ;;
Amiga*:UNIX_System_V:4.0:*)
echo m68k-unknown-sysv4
exit ;;
*:[Aa]miga[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-amigaos
exit ;;
*:[Mm]orph[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-morphos
exit ;;
*:OS/390:*:*)
echo i370-ibm-openedition
exit ;;
*:z/VM:*:*)
echo s390-ibm-zvmoe
exit ;;
*:OS400:*:*)
echo powerpc-ibm-os400
exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit ;;
arm*:riscos:*:*|arm*:RISCOS:*:*)
echo arm-unknown-riscos
exit ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
echo hppa1.1-hitachi-hiuxmpp
exit ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
if test "`(/bin/universe) 2>/dev/null`" = att ; then
echo pyramid-pyramid-sysv3
else
echo pyramid-pyramid-bsd
fi
exit ;;
NILE*:*:*:dcosx)
echo pyramid-pyramid-svr4
exit ;;
DRS?6000:unix:4.0:6*)
echo sparc-icl-nx6
exit ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
case `/usr/bin/uname -p` in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
s390x:SunOS:*:*)
echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
echo i386-pc-auroraux${UNAME_RELEASE}
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
SUN_ARCH="i386"
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH="x86_64"
fi
fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
Series*|S4*)
UNAME_RELEASE=`uname -v`
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
exit ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos${UNAME_RELEASE}
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
echo m68k-sun-sunos${UNAME_RELEASE}
;;
sun4)
echo sparc-sun-sunos${UNAME_RELEASE}
;;
esac
exit ;;
aushp:SunOS:*:*)
echo sparc-auspex-sunos${UNAME_RELEASE}
exit ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
# > m68000). The system name ranges from "MiNT" over "FreeMiNT"
# to the lowercase version "mint" (or "freemint"). Finally
# the system name "TOS" denotes a system which is actually not
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
echo m68k-milan-mint${UNAME_RELEASE}
exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
echo m68k-hades-mint${UNAME_RELEASE}
exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
echo m68k-unknown-mint${UNAME_RELEASE}
exit ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
exit ;;
powerpc:machten:*:*)
echo powerpc-apple-machten${UNAME_RELEASE}
exit ;;
RISC*:Mach:*:*)
echo mips-dec-mach_bsd4.3
exit ;;
RISC*:ULTRIX:*:*)
echo mips-dec-ultrix${UNAME_RELEASE}
exit ;;
VAX*:ULTRIX*:*:*)
echo vax-dec-ultrix${UNAME_RELEASE}
exit ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
echo clipper-intergraph-clix${UNAME_RELEASE}
exit ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#ifdef __cplusplus
#include /* for printf() prototype */
int main (int argc, char *argv[]) {
#else
int main (argc, argv) int argc; char *argv[]; {
#endif
#if defined (host_mips) && defined (MIPSEB)
#if defined (SYSTYPE_SYSV)
printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_SVR4)
printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
#endif
#endif
exit (-1);
}
EOF
$CC_FOR_BUILD -o $dummy $dummy.c &&
dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
SYSTEM_NAME=`$dummy $dummyarg` &&
{ echo "$SYSTEM_NAME"; exit; }
echo mips-mips-riscos${UNAME_RELEASE}
exit ;;
Motorola:PowerMAX_OS:*:*)
echo powerpc-motorola-powermax
exit ;;
Motorola:*:4.3:PL8-*)
echo powerpc-harris-powermax
exit ;;
Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
echo powerpc-harris-powermax
exit ;;
Night_Hawk:Power_UNIX:*:*)
echo powerpc-harris-powerunix
exit ;;
m88k:CX/UX:7*:*)
echo m88k-harris-cxux7
exit ;;
m88k:*:4*:R4*)
echo m88k-motorola-sysv4
exit ;;
m88k:*:3*:R3*)
echo m88k-motorola-sysv3
exit ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
[ ${TARGET_BINARY_INTERFACE}x = x ]
then
echo m88k-dg-dgux${UNAME_RELEASE}
else
echo m88k-dg-dguxbcs${UNAME_RELEASE}
fi
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
echo m88k-motorola-sysv3
exit ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
echo m88k-tektronix-sysv3
exit ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
echo m68k-tektronix-bsd
exit ;;
*:IRIX*:*:*)
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
exit ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i*86:AIX:*:*)
echo i386-ibm-aix
exit ;;
ia64:AIX:*:*)
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
exit ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include
main()
{
if (!__power_pc())
exit(1);
puts("powerpc-ibm-aix3.2.5");
exit(0);
}
EOF
if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
then
echo "$SYSTEM_NAME"
else
echo rs6000-ibm-aix3.2.5
fi
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
echo rs6000-ibm-aix3.2.4
else
echo rs6000-ibm-aix3.2
fi
exit ;;
*:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
exit ;;
*:AIX:*:*)
echo rs6000-ibm-aix
exit ;;
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
echo romp-ibm-bsd4.4
exit ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
exit ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
echo rs6000-bull-bosx
exit ;;
DPX/2?00:B.O.S.:*:*)
echo m68k-bull-sysv3
exit ;;
9000/[34]??:4.3bsd:1.*:*)
echo m68k-hp-bsd
exit ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
echo m68k-hp-bsd4.4
exit ;;
9000/[34678]??:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
case "${UNAME_MACHINE}" in
9000/31? ) HP_ARCH=m68000 ;;
9000/[34]?? ) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
32) HP_ARCH="hppa2.0n" ;;
64) HP_ARCH="hppa2.0w" ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
esac ;;
esac
fi
if [ "${HP_ARCH}" = "" ]; then
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#define _HPUX_SOURCE
#include
#include
int main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
#endif
long cpu = sysconf (_SC_CPU_VERSION);
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
case CPU_PA_RISC2_0:
#if defined(_SC_KERNEL_BITS)
switch (bits)
{
case 64: puts ("hppa2.0w"); break;
case 32: puts ("hppa2.0n"); break;
default: puts ("hppa2.0"); break;
} break;
#else /* !defined(_SC_KERNEL_BITS) */
puts ("hppa2.0"); break;
#endif
default: puts ("hppa1.0"); break;
}
exit (0);
}
EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
if [ ${HP_ARCH} = "hppa2.0w" ]
then
eval $set_cc_for_build
# hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
# 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
# generating 64-bit code. GNU and HP use different nomenclature:
#
# $ CC_FOR_BUILD=cc ./config.guess
# => hppa2.0w-hp-hpux11.23
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
then
HP_ARCH="hppa2.0w"
else
HP_ARCH="hppa64"
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
exit ;;
ia64:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
echo ia64-hp-hpux${HPUX_REV}
exit ;;
3050*:HI-UX:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include
int
main ()
{
long cpu = sysconf (_SC_CPU_VERSION);
/* The order matters, because CPU_IS_HP_MC68K erroneously returns
true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
results, however. */
if (CPU_IS_PA_RISC (cpu))
{
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
default: puts ("hppa-hitachi-hiuxwe2"); break;
}
}
else if (CPU_IS_HP_MC68K (cpu))
puts ("m68k-hitachi-hiuxwe2");
else puts ("unknown-hitachi-hiuxwe2");
exit (0);
}
EOF
$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
{ echo "$SYSTEM_NAME"; exit; }
echo unknown-hitachi-hiuxwe2
exit ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
echo hppa1.1-hp-bsd
exit ;;
9000/8??:4.3bsd:*:*)
echo hppa1.0-hp-bsd
exit ;;
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
echo hppa1.0-hp-mpeix
exit ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
echo hppa1.1-hp-osf
exit ;;
hp8??:OSF1:*:*)
echo hppa1.0-hp-osf
exit ;;
i*86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
echo ${UNAME_MACHINE}-unknown-osf1mk
else
echo ${UNAME_MACHINE}-unknown-osf1
fi
exit ;;
parisc*:Lites*:*:*)
echo hppa1.1-hp-lites
exit ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
exit ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
exit ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
exit ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
exit ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*[A-Z]90:*:*:*)
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
-e 's/\.[^.]*$/.X/'
exit ;;
CRAY*TS:*:*:*)
echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*T3E:*:*:*)
echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*SV1:*:*:*)
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
*:UNICOS/mp:*:*)
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
exit ;;
sparc*:BSD/OS:*:*)
echo sparc-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
amd64)
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
esac
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
exit ;;
*:MINGW64*:*)
echo ${UNAME_MACHINE}-pc-mingw64
exit ;;
*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
*:MSYS*:*)
echo ${UNAME_MACHINE}-pc-msys
exit ;;
i*:windows32*:*)
# uname -m includes "-pc" on this system.
echo ${UNAME_MACHINE}-mingw32
exit ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit ;;
*:Interix*:*)
case ${UNAME_MACHINE} in
x86)
echo i586-pc-interix${UNAME_RELEASE}
exit ;;
authenticamd | genuineintel | EM64T)
echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;;
IA64)
echo ia64-unknown-interix${UNAME_RELEASE}
exit ;;
esac ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
exit ;;
8664:Windows_NT:*)
echo x86_64-pc-mks
exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
# UNAME_MACHINE based on the output of uname instead of i386?
echo i586-pc-interix
exit ;;
i*:UWIN*:*)
echo ${UNAME_MACHINE}-pc-uwin
exit ;;
amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
echo x86_64-unknown-cygwin
exit ;;
p*:CYGWIN*:*)
echo powerpcle-unknown-cygwin
exit ;;
prep*:SunOS:5.*:*)
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
*:GNU:*:*)
# the GNU system
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
aarch64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
PCA57) UNAME_MACHINE=alphapca56 ;;
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arc:Linux:*:* | arceb:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arm*:Linux:*:*)
eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
else
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
fi
fi
exit ;;
avr32*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
cris:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
hexagon:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
i*86:Linux:*:*)
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef ${UNAME_MACHINE}
#undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=${UNAME_MACHINE}el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=${UNAME_MACHINE}
#else
CPU=
#endif
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
openrisc*:Linux:*:*)
echo or1k-unknown-linux-${LIBC}
exit ;;
or32:Linux:*:* | or1k*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
padre:Linux:*:*)
echo sparc-unknown-linux-${LIBC}
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-${LIBC}
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
*) echo hppa-unknown-linux-${LIBC} ;;
esac
exit ;;
ppc64:Linux:*:*)
echo powerpc64-unknown-linux-${LIBC}
exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-${LIBC}
exit ;;
ppc64le:Linux:*:*)
echo powerpc64le-unknown-linux-${LIBC}
exit ;;
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC}
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;;
sh64*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
tile*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;;
x86_64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
# sysname and nodename.
echo i386-sequent-sysv4
exit ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit ;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# is probably installed.
echo ${UNAME_MACHINE}-pc-os2-emx
exit ;;
i*86:XTS-300:*:STOP)
echo ${UNAME_MACHINE}-unknown-stop
exit ;;
i*86:atheos:*:*)
echo ${UNAME_MACHINE}-unknown-atheos
exit ;;
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;;
i*86:*DOS:*:*)
echo ${UNAME_MACHINE}-pc-msdosdjgpp
exit ;;
i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
else
echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
fi
exit ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
exit ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
&& UNAME_MACHINE=i686
(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
&& UNAME_MACHINE=i686
echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
else
echo ${UNAME_MACHINE}-pc-sysv32
fi
exit ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configury will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit ;;
paragon:*:*:*)
echo i860-intel-osf1
exit ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
fi
exit ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
echo m68010-convergent-sysv
exit ;;
mc68k:UNIX:SYSTEM5:3.51m)
echo m68k-convergent-sysv
exit ;;
M680?0:D-NIX:5.3:*)
echo m68k-diab-dnix
exit ;;
M68*:*:R3V[5678]*:*)
test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4; exit; } ;;
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
OS_REL='.3'
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
exit ;;
TSUNAMI:LynxOS:2.*:*)
echo sparc-unknown-lynxos${UNAME_RELEASE}
exit ;;
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;;
SM[BE]S:UNIX_SV:*:*)
echo mips-dde-sysv${UNAME_RELEASE}
exit ;;
RM*:ReliantUNIX-*:*:*)
echo mips-sni-sysv4
exit ;;
RM*:SINIX-*:*:*)
echo mips-sni-sysv4
exit ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
echo ${UNAME_MACHINE}-sni-sysv4
else
echo ns32k-sni-sysv
fi
exit ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says
echo i586-unisys-sysv4
exit ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes .
# How about differentiating between stratus architectures? -djm
echo hppa1.1-stratus-sysv4
exit ;;
*:*:*:FTX*)
# From seanf@swdc.stratus.com.
echo i860-stratus-sysv4
exit ;;
i*86:VOS:*:*)
# From Paul.Green@stratus.com.
echo ${UNAME_MACHINE}-stratus-vos
exit ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
echo hppa1.1-stratus-vos
exit ;;
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
exit ;;
news*:NEWS-OS:6*:*)
echo mips-sony-newsos6
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
exit ;;
BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
echo powerpc-apple-beos
exit ;;
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
exit ;;
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
echo i586-pc-haiku
exit ;;
x86_64:Haiku:*:*)
echo x86_64-unknown-haiku
exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
exit ;;
SX-5:SUPER-UX:*:*)
echo sx5-nec-superux${UNAME_RELEASE}
exit ;;
SX-6:SUPER-UX:*:*)
echo sx6-nec-superux${UNAME_RELEASE}
exit ;;
SX-7:SUPER-UX:*:*)
echo sx7-nec-superux${UNAME_RELEASE}
exit ;;
SX-8:SUPER-UX:*:*)
echo sx8-nec-superux${UNAME_RELEASE}
exit ;;
SX-8R:SUPER-UX:*:*)
echo sx8r-nec-superux${UNAME_RELEASE}
exit ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;;
*:Rhapsody:*:*)
echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
eval $set_cc_for_build
if test "$UNAME_PROCESSOR" = unknown ; then
UNAME_PROCESSOR=powerpc
fi
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
i386) UNAME_PROCESSOR=x86_64 ;;
powerpc) UNAME_PROCESSOR=powerpc64 ;;
esac
fi
fi
elif test "$UNAME_PROCESSOR" = i386 ; then
# Avoid executing cc on OS X 10.9, as it ships with a stub
# that puts up a graphical alert prompting to install
# developer tools. Any system running Mac OS X 10.7 or
# later (Darwin 11 and later) is required to have a 64-bit
# processor. This is not true of the ARM version of Darwin
# that Apple uses in portable devices.
UNAME_PROCESSOR=x86_64
fi
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = "x86"; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
exit ;;
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
NEO-?:NONSTOP_KERNEL:*:*)
echo neo-tandem-nsk${UNAME_RELEASE}
exit ;;
NSE-*:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
NSR-?:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
exit ;;
BS2000:POSIX*:*:*)
echo bs2000-siemens-sysv
exit ;;
DS/*:UNIX_System_V:*:*)
echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
exit ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
if test "$cputype" = "386"; then
UNAME_MACHINE=i386
else
UNAME_MACHINE="$cputype"
fi
echo ${UNAME_MACHINE}-unknown-plan9
exit ;;
*:TOPS-10:*:*)
echo pdp10-unknown-tops10
exit ;;
*:TENEX:*:*)
echo pdp10-unknown-tenex
exit ;;
KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
echo pdp10-dec-tops20
exit ;;
XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
echo pdp10-xkl-tops20
exit ;;
*:TOPS-20:*:*)
echo pdp10-unknown-tops20
exit ;;
*:ITS:*:*)
echo pdp10-unknown-its
exit ;;
SEI:*:*:SEIUX)
echo mips-sei-seiux${UNAME_RELEASE}
exit ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
*:*VMS:*:*)
UNAME_MACHINE=`(uname -p) 2>/dev/null`
case "${UNAME_MACHINE}" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
V*) echo vax-dec-vms ; exit ;;
esac ;;
*:XENIX:*:SysV)
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
exit ;;
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
exit ;;
i*86:AROS:*:*)
echo ${UNAME_MACHINE}-pc-aros
exit ;;
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
esac
cat >&2 < in order to provide the needed
information to handle your system.
config.guess timestamp = $timestamp
uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`
/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
hostinfo = `(hostinfo) 2>/dev/null`
/bin/universe = `(/bin/universe) 2>/dev/null`
/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
/bin/arch = `(/bin/arch) 2>/dev/null`
/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
UNAME_MACHINE = ${UNAME_MACHINE}
UNAME_RELEASE = ${UNAME_RELEASE}
UNAME_SYSTEM = ${UNAME_SYSTEM}
UNAME_VERSION = ${UNAME_VERSION}
EOF
exit 1
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
nss-pam-ldapd-0.9.6/INSTALL 0000644 0001750 0000144 00000036610 12537036355 012153 0000000 0000000 Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell command `./configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
nss-pam-ldapd-0.9.6/pynslcd/ 0000755 0001750 0000144 00000000000 12537361545 012652 5 0000000 0000000 nss-pam-ldapd-0.9.6/pynslcd/config.py 0000644 0001750 0000144 00000003071 12270764162 014406 0000000 0000000
# config.py - routines for getting configuration information
#
# Copyright (C) 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import cfg
import common
import constants
class ConfigGetRequest(common.Request):
action = constants.NSLCD_ACTION_CONFIG_GET
def read_parameters(self, fp):
return dict(cfgopt=fp.read_int32())
# TODO: log call with parameters
def write(self, value):
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
self.fp.write_string(value)
self.fp.write_int32(constants.NSLCD_RESULT_END)
def handle_request(self, parameters):
cfgopt = parameters['cfgopt']
if cfgopt == constants.NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE:
self.write(cfg.pam_password_prohibit_message or '')
else:
# return empty response
self.fp.write_int32(constants.NSLCD_RESULT_END)
nss-pam-ldapd-0.9.6/pynslcd/cache.py 0000644 0001750 0000144 00000015010 12476337763 014213 0000000 0000000
# cache.py - caching layer for pynslcd
#
# Copyright (C) 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import datetime
import os
import sys
import sqlite3
# TODO: probably create a config table
# FIXME: have some way to remove stale entries from the cache if all items from LDAP are queried (perhas use TTL from all request)
class regroup(object):
def __init__(self, results, group_by=None, group_column=None):
"""Regroup the results in the group column by the key columns."""
self.group_by = tuple(group_by)
self.group_column = group_column
self.it = iter(results)
self.tgtkey = self.currkey = self.currvalue = object()
def keyfunc(self, row):
return tuple(row[x] for x in self.group_by)
def __iter__(self):
return self
def next(self):
# find a start row
while self.currkey == self.tgtkey:
self.currvalue = next(self.it) # Exit on StopIteration
self.currkey = self.keyfunc(self.currvalue)
self.tgtkey = self.currkey
# turn the result row into a list of columns
row = list(self.currvalue)
# replace the group column
row[self.group_column] = list(self._grouper(self.tgtkey))
return row
def _grouper(self, tgtkey):
"""Generate the group columns."""
while self.currkey == tgtkey:
value = self.currvalue[self.group_column]
if value is not None:
yield value
self.currvalue = next(self.it) # Exit on StopIteration
self.currkey = self.keyfunc(self.currvalue)
class Query(object):
"""Helper class to build an SQL query for the cache."""
def __init__(self, query):
self.query = query
self.wheres = []
self.parameters = []
def add_where(self, where, parameters):
self.wheres.append(where)
self.parameters += parameters
def execute(self, con):
query = self.query
if self.wheres:
query += ' WHERE ' + ' AND '.join(self.wheres)
cursor = con.cursor()
return cursor.execute(query, self.parameters)
class Cache(object):
"""The description of the cache."""
retrieve_sql = None
retrieve_by = dict()
group_by = ()
group_columns = ()
def __init__(self):
self.con = _get_connection()
self.db = sys.modules[self.__module__].__name__
if not hasattr(self, 'tables'):
self.tables = ['%s_cache' % self.db]
self.create()
def create(self):
"""Create the needed tables if neccesary."""
self.con.executescript(self.create_sql)
def store(self, *values):
"""Store the values in the cache for the specified table.
The order of the values is the order returned by the Reques.convert()
function."""
# split the values into simple (flat) values and one-to-many values
simple_values = []
multi_values = []
for v in values:
if isinstance(v, (list, tuple, set)):
multi_values.append(v)
else:
simple_values.append(v)
# insert the simple values
simple_values.append(datetime.datetime.now())
args = ', '.join(len(simple_values) * ('?', ))
self.con.execute('''
INSERT OR REPLACE INTO %s
VALUES
(%s)
''' % (self.tables[0], args), simple_values)
# insert the one-to-many values
for n, vlist in enumerate(multi_values):
self.con.execute('''
DELETE FROM %s
WHERE `%s` = ?
''' % (self.tables[n + 1], self.db), (values[0], ))
self.con.executemany('''
INSERT INTO %s
VALUES
(?, ?)
''' % (self.tables[n + 1]), ((values[0], x) for x in vlist))
def retrieve(self, parameters):
"""Retrieve all items from the cache based on the parameters
supplied."""
query = Query(self.retrieve_sql or '''
SELECT *
FROM %s
''' % self.tables[0])
if parameters:
for k, v in parameters.items():
where = self.retrieve_by.get(k, '`%s`.`%s` = ?' % (self.tables[0], k))
query.add_where(where, where.count('?') * [v])
# group by
# FIXME: find a nice way to turn group_by and group_columns into names
results = query.execute(self.con)
group_by = list(self.group_by + self.group_columns)
for column in self.group_columns[::-1]:
group_by.pop()
results = regroup(results, group_by, column)
# strip the mtime from the results
return (list(x)[:-1] for x in results)
def __enter__(self):
return self.con.__enter__();
def __exit__(self, *args):
return self.con.__exit__(*args);
# the connection to the sqlite database
_connection = None
# FIXME: make tread safe (is this needed the way the caches are initialised?)
def _get_connection():
global _connection
if _connection is None:
filename = '/tmp/pynslcd_cache.sqlite'
dirname = os.path.dirname(filename)
if not os.path.isdir(dirname):
os.mkdir(dirname)
connection = sqlite3.connect(
filename, detect_types=sqlite3.PARSE_DECLTYPES,
check_same_thread=False)
connection.row_factory = sqlite3.Row
# initialise connection properties
connection.executescript('''
-- store temporary tables in memory
PRAGMA temp_store = MEMORY;
-- disable sync() on database (corruption on disk failure)
PRAGMA synchronous = OFF;
-- put journal in memory (corruption if crash during transaction)
PRAGMA journal_mode = MEMORY;
''')
_connection = connection
return _connection
nss-pam-ldapd-0.9.6/pynslcd/pynslcd.py 0000744 0001750 0000144 00000032117 12476337763 014634 0000000 0000000 #!/usr/bin/env python
# pynslcd.py - main daemon module
#
# Copyright (C) 2010-2015 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import logging
import logging.handlers
import os
import signal
import sys
import syslog
import threading
import daemon
import ldap
from tio import TIOStream
import cfg
import common
import constants
import invalidator
import mypidfile
import search
# the name of the program
program_name = 'pynslcd'
# flag to indicate whether we are in debugging mode
debugging = 0
# flag to indicate we shouldn't daemonize
nofork = False
# flag to indicate user requested the --check option
checkonly = False
class MyFormatter(logging.Formatter):
def format(self, record):
record.prefix = 'DEBUG: ' if record.levelno == logging.DEBUG else ''
return super(MyFormatter, self).format(record)
class MySysLogHandler(logging.Handler):
mapping = {
logging.DEBUG: syslog.LOG_DEBUG,
logging.INFO: syslog.LOG_INFO,
logging.WARNING: syslog.LOG_WARNING,
logging.ERROR: syslog.LOG_ERR,
logging.CRITICAL: syslog.LOG_CRIT,
}
def __init__(self):
super(MySysLogHandler, self).__init__()
syslog.openlog(program_name, syslog.LOG_PID, syslog.LOG_DAEMON)
def emit(self, record):
priority = self.mapping.get(record.levelno, syslog.LOG_WARNING)
msg = self.format(record)
for line in msg.splitlines():
syslog.syslog(priority, line)
# configure logging
stderrhandler = logging.StreamHandler(sys.stderr)
stderrhandler.setFormatter(MyFormatter('pynslcd: %(prefix)s%(message)s'))
logging.getLogger().addHandler(stderrhandler)
logging.getLogger().setLevel(logging.INFO)
def display_version(fp):
fp.write('%(PACKAGE_STRING)s\n'
'Written by Arthur de Jong.\n'
'\n'
'Copyright (C) 2010-2015 Arthur de Jong\n'
'This is free software; see the source for copying conditions. There is NO\n'
'warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n'
% {'PACKAGE_STRING': constants.PACKAGE_STRING, })
def display_usage(fp):
fp.write("Usage: %(program_name)s [OPTION]...\n"
"Name Service LDAP connection daemon.\n"
" -c, --check check if the daemon already is running\n"
" -d, --debug don't fork and print debugging to stderr\n"
" -n, --nofork don't fork\n"
" --help display this help and exit\n"
" --version output version information and exit\n"
"\n"
"Report bugs to <%(PACKAGE_BUGREPORT)s>.\n"
% {'program_name': program_name,
'PACKAGE_BUGREPORT': constants.PACKAGE_BUGREPORT, })
def parse_cmdline():
"""Parse command-line arguments."""
import getopt
global program_name
program_name = sys.argv[0] or program_name
try:
optlist, args = getopt.gnu_getopt(
sys.argv[1:], 'cdnhV',
('check', 'debug', 'nofork', 'help', 'version'))
for flag, arg in optlist:
if flag in ('-c', '--check'):
global checkonly
checkonly = True
elif flag in ('-d', '--debug'):
global debugging
debugging += 1
elif flag in ('-n', '--nofork'):
global nofork
nofork = True
elif flag in ('-h', '--help'):
display_usage(sys.stdout)
sys.exit(0)
elif flag in ('-V', '--version'):
display_version(sys.stdout)
sys.exit(0)
if len(args):
raise getopt.GetoptError('unrecognized option \'%s\'' % args[0], args[0])
except getopt.GetoptError, reason:
sys.stderr.write(
"%(program_name)s: %(reason)s\n"
"Try '%(program_name)s --help' for more information.\n" % {
'program_name': program_name,
'reason': reason,
})
sys.exit(1)
def create_socket():
"""Returns a socket ready to answer requests from the client."""
import socket
import fcntl
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
# remove existing named socket
try:
os.unlink(constants.NSLCD_SOCKET)
except OSError:
pass # ignore any problems
# bind to named socket
sock.bind(constants.NSLCD_SOCKET)
# close the file descriptor on exit
fcntl.fcntl(sock, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
# set permissions of socket so anybody can do requests
os.chmod(constants.NSLCD_SOCKET, 0666)
# start listening for connections
sock.listen(socket.SOMAXCONN)
return sock
def log_newsession():
pass
# FIXME: implement
def getpeercred(fd):
"""Return uid, gid and pid of calling application."""
import struct
import socket
try:
SO_PEERCRED = getattr(socket, 'SO_PEERCRED', 17)
creds = fd.getsockopt(socket.SOL_SOCKET, SO_PEERCRED, struct.calcsize('3i'))
pid, uid, gid = struct.unpack('3i', creds)
return uid, gid, pid
except socket.error:
return None, None, None
handlers = {}
handlers.update(common.get_handlers('config'))
handlers.update(common.get_handlers('alias'))
handlers.update(common.get_handlers('ether'))
handlers.update(common.get_handlers('group'))
handlers.update(common.get_handlers('host'))
handlers.update(common.get_handlers('netgroup'))
handlers.update(common.get_handlers('network'))
handlers.update(common.get_handlers('passwd'))
handlers.update(common.get_handlers('protocol'))
handlers.update(common.get_handlers('rpc'))
handlers.update(common.get_handlers('service'))
handlers.update(common.get_handlers('shadow'))
handlers.update(common.get_handlers('pam'))
handlers.update(common.get_handlers('usermod'))
def acceptconnection(session):
# accept a new connection
conn, addr = nslcd_serversocket.accept()
# See: http://docs.python.org/library/socket.html#socket.socket.settimeout
fp = None
try:
# indicate new connection to logging module (generates unique id)
log_newsession()
# log connection
uid, gid, pid = getpeercred(conn)
logging.debug('connection from pid=%r uid=%r gid=%r', pid, uid, gid)
# create a stream object
fp = TIOStream(conn)
# read request
version = fp.read_int32()
if version != constants.NSLCD_VERSION:
logging.debug('wrong nslcd version id (%r)', version)
return
action = fp.read_int32()
try:
handler = handlers[action]
except KeyError:
logging.warning('invalid action id: 0x%08x', action)
return
handler(fp, session, uid)()
finally:
if fp:
fp.close()
def disable_nss_ldap():
"""Disable the nss_ldap module to avoid lookup loops."""
import ctypes
try:
lib = ctypes.CDLL(constants.NSS_LDAP_SONAME)
except OSError:
return # ignore errors in opening NSS module
try:
ctypes.c_int.in_dll(
lib, '_nss_%s_enablelookups' % constants.MODULE_NAME).value = 0
except ValueError:
logging.warn('probably older NSS module loaded', exc_info=True)
try:
version_info = (ctypes.c_char_p * 2).in_dll(lib, '_nss_ldap_version')
logging.debug('NSS_LDAP %s %s', version_info[0], version_info[1])
except ValueError:
logging.warn('probably older NSS module loaded', exc_info=True)
def worker():
session = search.Connection()
while True:
try:
acceptconnection(session)
except:
logging.exception('exception in worker')
# ignore all exceptions, just keep going
if __name__ == '__main__':
# parse options
parse_cmdline()
# clean the environment
os.environ.clear()
os.environ['HOME'] = '/'
os.environ['TMPDIR'] = '/tmp'
os.environ['LDAPNOINIT'] = '1'
# set log level
if debugging:
logging.getLogger().setLevel(logging.DEBUG)
# disable ldap lookups of host names to avoid lookup loop
disable_nss_ldap()
# TODO: implement
#if myldap_set_debuglevel(cfg.debug) != LDAP_SUCCESS:
# sys.exit(1)
# read configuration file
cfg.read(constants.NSLCD_CONF_PATH)
# set process title
try:
import setproctitle
setproctitle.setproctitle('pynslcd')
except ImportError:
pass
# set a default umask for the pidfile and socket
os.umask(0022)
# see if someone already locked the pidfile
pidfile = mypidfile.MyPIDLockFile(constants.NSLCD_PIDFILE)
# see if --check option was given
if checkonly:
if pidfile.is_locked():
logging.debug('pidfile (%s) is locked', constants.NSLCD_PIDFILE)
sys.exit(0)
else:
logging.debug('pidfile (%s) is not locked', constants.NSLCD_PIDFILE)
sys.exit(1)
# normal check for pidfile locked
if pidfile.is_locked():
logging.error('daemon may already be active, cannot acquire lock (%s)',
constants.NSLCD_PIDFILE)
sys.exit(1)
# daemonize
if debugging or nofork:
ctx = pidfile
else:
ctx = daemon.DaemonContext(
pidfile=pidfile,
signal_map={
signal.SIGTERM: 'terminate',
signal.SIGINT: 'terminate',
signal.SIGPIPE: None,
})
# start daemon
with ctx:
try:
# start normal logging as configured
if not debugging:
for method, level in cfg.logs:
if method == 'syslog':
handler = MySysLogHandler()
handler.setFormatter(MyFormatter('%(prefix)s%(message)s'))
else:
handler = logging.FileHandler(method, encoding='utf-8')
handler.setFormatter(MyFormatter('%(asctime)s %(prefix)s%(message)s'))
handler.setLevel(level)
logging.getLogger().addHandler(handler)
logging.getLogger().setLevel(min(level for method, level in cfg.logs))
logging.getLogger().removeHandler(stderrhandler)
logging.info('version %s starting', constants.VERSION)
# start invalidator sub-process if needed
if cfg.reconnect_invalidate:
invalidator.start_invalidator()
# create socket
nslcd_serversocket = create_socket()
# load supplementary groups
if cfg.uid is not None:
import pwd
import grp
u = pwd.getpwnam(cfg.uid)
if cfg.gid is None:
gid = u.pw_gid
else:
gid = grp.getgrnam(cfg.gid).gr_gid
# set supplementary groups, gid and uid
os.initgroups(u.pw_name, gid)
os.setgid(gid)
os.setuid(u.pw_uid)
os.environ['HOME'] = u.pw_dir
logging.info('accepting connections')
# set global LDAP configuration
if cfg.tls_reqcert is not None:
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, cfg.tls_reqcert)
if cfg.tls_cacertdir:
ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, cfg.tls_cacertdir)
if cfg.tls_cacertfile:
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, cfg.tls_cacertfile)
if cfg.tls_randfile:
ldap.set_option(ldap.OPT_X_TLS_RANDOM_FILE, cfg.tls_randfile)
if cfg.tls_ciphers:
ldap.set_option(ldap.OPT_X_TLS_CIPHER_SUITE, cfg.tls_ciphers)
if cfg.tls_cert:
ldap.set_option(ldap.OPT_X_TLS_CERTFILE, cfg.tls_cert)
if cfg.tls_key:
ldap.set_option(ldap.OPT_X_TLS_KEYFILE, cfg.tls_key)
# start worker threads
threads = []
for i in range(cfg.threads):
thread = threading.Thread(target=worker, name='thread%d' % i)
thread.setDaemon(True)
thread.start()
logging.debug('started thread %s', thread.getName())
threads.append(thread)
# wait for all threads to die
for thread in threads:
thread.join(10000)
except:
logging.exception('main loop exit')
# no need to re-raise since we are exiting anyway
nss-pam-ldapd-0.9.6/pynslcd/shadow.py 0000644 0001750 0000144 00000011117 12530340161 014412 0000000 0000000
# shadow.py - lookup functions for shadow information
#
# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import cache
import cfg
import common
import constants
import search
attmap = common.Attributes(uid='uid',
userPassword='"*"',
shadowLastChange='"${shadowLastChange:--1}"',
shadowMin='"${shadowMin:--1}"',
shadowMax='"${shadowMax:--1}"',
shadowWarning='"${shadowWarning:--1}"',
shadowInactive='"${shadowInactive:--1}"',
shadowExpire='"${shadowExpire:--1}"',
shadowFlag='"${shadowFlag:-0}"')
filter = '(objectClass=shadowAccount)'
class Search(search.LDAPSearch):
case_sensitive = ('uid', )
limit_attributes = ('uid', )
required = ('uid', )
class Cache(cache.Cache):
create_sql = '''
CREATE TABLE IF NOT EXISTS `shadow_cache`
( `uid` TEXT PRIMARY KEY,
`userPassword` TEXT,
`shadowLastChange` INTEGER,
`shadowMin` INTEGER,
`shadowMax` INTEGER,
`shadowWarning` INTEGER,
`shadowInactive` INTEGER,
`shadowExpire` INTEGER,
`shadowFlag` INTEGER,
`mtime` TIMESTAMP NOT NULL );
'''
class ShadowRequest(common.Request):
def write(self, name, passwd, lastchangedate, mindays, maxdays, warndays,
inactdays, expiredate, flag):
self.fp.write_string(name)
self.fp.write_string(passwd)
self.fp.write_int32(lastchangedate)
self.fp.write_int32(mindays)
self.fp.write_int32(maxdays)
self.fp.write_int32(warndays)
self.fp.write_int32(inactdays)
self.fp.write_int32(expiredate)
self.fp.write_int32(flag)
def convert(self, dn, attributes, parameters):
names = attributes['uid']
try:
passwd = attributes['userPassword'][0]
except IndexError:
passwd = None
if not passwd or self.calleruid != 0:
passwd = '*'
# function for making an int
def mk_int(attr):
try:
return int(attr)
except TypeError:
return None
# get lastchange date
lastchangedate = mk_int(attributes.get('shadowLastChange', [0])[0])
# we expect an AD 64-bit datetime value;
# we should do date=date/864000000000-134774
# but that causes problems on 32-bit platforms,
# first we devide by 1000000000 by stripping the
# last 9 digits from the string and going from there */
if attmap['shadowLastChange'] == 'pwdLastSet':
lastchangedate = (lastchangedate / 864000000000) - 134774
# get longs
mindays = mk_int(attributes.get('shadowMin', [-1])[0])
maxdays = mk_int(attributes.get('shadowMax', [-1])[0])
warndays = mk_int(attributes.get('shadowWarning', [-1])[0])
inactdays = mk_int(attributes.get('shadowInactive', [-1])[0])
expiredate = mk_int(attributes.get('shadowExpire', [-1])[0])
flag = mk_int(attributes.get('shadowFlag', [0])[0])
if attmap['shadowFlag'] == 'pwdLastSet':
if flag & 0x10000:
maxdays = -1
flag = 0
# return results
for name in names:
yield (name, passwd, lastchangedate, mindays, maxdays, warndays,
inactdays, expiredate, flag)
class ShadowByNameRequest(ShadowRequest):
action = constants.NSLCD_ACTION_SHADOW_BYNAME
def read_parameters(self, fp):
return dict(uid=fp.read_string())
class ShadowAllRequest(ShadowRequest):
action = constants.NSLCD_ACTION_SHADOW_ALL
def handle_request(self, parameters):
if not cfg.nss_disable_enumeration:
return super(ShadowAllRequest, self).handle_request(parameters)
nss-pam-ldapd-0.9.6/pynslcd/rpc.py 0000644 0001750 0000144 00000005767 12273004010 013721 0000000 0000000
# rpc.py - rpc name lookup routines
#
# Copyright (C) 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import cache
import common
import constants
import search
attmap = common.Attributes(cn='cn', oncRpcNumber='oncRpcNumber')
filter = '(objectClass=oncRpc)'
class Search(search.LDAPSearch):
case_sensitive = ('cn', )
canonical_first = ('cn', )
required = ('cn', 'oncRpcNumber')
class Cache(cache.Cache):
tables = ('rpc_cache', 'rpc_alias_cache')
create_sql = '''
CREATE TABLE IF NOT EXISTS `rpc_cache`
( `cn` TEXT PRIMARY KEY,
`oncRpcNumber` INTEGER NOT NULL,
`mtime` TIMESTAMP NOT NULL );
CREATE TABLE IF NOT EXISTS `rpc_alias_cache`
( `rpc` TEXT NOT NULL,
`cn` TEXT NOT NULL,
FOREIGN KEY(`rpc`) REFERENCES `rpc_cache`(`cn`)
ON DELETE CASCADE ON UPDATE CASCADE );
CREATE INDEX IF NOT EXISTS `rpc_alias_idx` ON `rpc_alias_cache`(`rpc`);
'''
retrieve_sql = '''
SELECT `rpc_cache`.`cn` AS `cn`, `rpc_alias_cache`.`cn` AS `alias`,
`oncRpcNumber`, `mtime`
FROM `rpc_cache`
LEFT JOIN `rpc_alias_cache`
ON `rpc_alias_cache`.`rpc` = `rpc_cache`.`cn`
'''
retrieve_by = dict(
cn='''
( `rpc_cache`.`cn` = ? OR
`rpc_cache`.`cn` IN (
SELECT `by_alias`.`rpc`
FROM `rpc_alias_cache` `by_alias`
WHERE `by_alias`.`cn` = ?))
''',
)
group_by = (0, ) # cn
group_columns = (1, ) # alias
class RpcRequest(common.Request):
def write(self, name, aliases, number):
self.fp.write_string(name)
self.fp.write_stringlist(aliases)
self.fp.write_int32(number)
def convert(self, dn, attributes, parameters):
names = attributes['cn']
yield (names[0], names[1:], int(attributes['oncRpcNumber'][0]))
class RpcByNameRequest(RpcRequest):
action = constants.NSLCD_ACTION_RPC_BYNAME
def read_parameters(self, fp):
return dict(cn=fp.read_string())
class RpcByNumberRequest(RpcRequest):
action = constants.NSLCD_ACTION_RPC_BYNUMBER
def read_parameters(self, fp):
return dict(oncRpcNumber=fp.read_int32())
class RpcAllRequest(RpcRequest):
action = constants.NSLCD_ACTION_RPC_ALL
nss-pam-ldapd-0.9.6/pynslcd/attmap.py 0000644 0001750 0000144 00000013061 12530340135 014414 0000000 0000000
# attmap.py - attribute mapping class
#
# Copyright (C) 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
"""Module for handling attribute mappings used for LDAP searches.
>>> attrs = Attributes(uid='uid',
... userPassword='userPassword',
... uidNumber='uidNumber',
... gidNumber='gidNumber',
... gecos='"${gecos:-$cn}"',
... homeDirectory='homeDirectory',
... loginShell='loginShell')
>>> 'cn' in attrs.attributes()
True
>>> attrs.translate({'uid': ['UIDVALUE', '2nduidvalue'], 'cn': ['COMMON NAME', ]})
{'uid': ['UIDVALUE', '2nduidvalue'], 'loginShell': [], 'userPassword': [], 'uidNumber': [], 'gidNumber': [], 'gecos': ['COMMON NAME'], 'homeDirectory': []}
>>> attrs['uidNumber'] # a representation fit for logging and filters
'uidNumber'
>>> attrs['gecos']
'"${gecos:-$cn}"'
"""
import re
from ldap.filter import escape_filter_chars
import ldap.dn
from expr import Expression
# exported names
__all__ = ('Attributes', )
# TODO: support objectSid attributes
# regular expression to match function attributes
attribute_func_re = re.compile('^(?P[a-z]+)\((?P.*)\)$')
class SimpleMapping(str):
"""Simple mapping to another attribute name."""
def attributes(self):
return [self]
def mk_filter(self, value):
return '(%s=%s)' % (
self, escape_filter_chars(str(value))
)
def values(self, variables):
"""Expand the expression using the variables specified."""
return variables.get(self, [])
class ExpressionMapping(str):
"""Class for parsing and expanding an expression."""
def __init__(self, value):
"""Parse the expression as a string."""
self.expression = Expression(value)
super(ExpressionMapping, self).__init__(value)
def values(self, variables):
"""Expand the expression using the variables specified."""
return [self.expression.value(variables)]
def attributes(self):
"""Return the attributes defined in the expression."""
return self.expression.variables()
class FunctionMapping(str):
"""Mapping to a function to another attribute."""
def __init__(self, mapping):
self.mapping = mapping
m = attribute_func_re.match(mapping)
self.attribute = m.group('attribute')
self.function = getattr(self, m.group('function'))
super(FunctionMapping, self).__init__(mapping)
def upper(self, value):
return value.upper()
def lower(self, value):
return value.lower()
def attributes(self):
return [self.attribute]
def mk_filter(self, value):
return '(%s=%s)' % (
self.attribute, escape_filter_chars(value)
)
def values(self, variables):
return [self.function(value)
for value in variables.get(self.attribute, [])]
class Attributes(dict):
"""Dictionary-like class for handling attribute mapping."""
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
def __setitem__(self, attribute, mapping):
# translate the mapping into a mapping object
if mapping[0] == '"' and mapping[-1] == '"':
mapping = ExpressionMapping(mapping[1:-1])
elif '(' in mapping:
mapping = FunctionMapping(mapping)
else:
mapping = SimpleMapping(mapping)
super(Attributes, self).__setitem__(attribute, mapping)
def update(self, *args, **kwargs):
for arg in args:
other = dict(arg)
for key in other:
self[key] = other[key]
for key in kwargs:
self[key] = kwargs[key]
def attributes(self):
"""Return the list of attributes that are referenced in this
attribute mapping. These are the attributes that should be
requested in the search."""
attributes = set()
for mapping in self.itervalues():
attributes.update(mapping.attributes())
return list(attributes)
def mk_filter(self, attribute, value):
"""Construct a search filter for searching for the attribute value
combination."""
mapping = self.get(attribute, SimpleMapping(attribute))
return mapping.mk_filter(value)
def translate(self, variables):
"""Return a dictionary with every attribute mapped to their value from
the specified variables."""
results = dict()
for attribute, mapping in self.iteritems():
results[attribute] = mapping.values(variables)
return results
def get_rdn_value(self, dn, attribute):
"""Extract the attribute value from from DN if possible. Return None
otherwise."""
return self.translate(dict(
(x, [y])
for x, y, z in ldap.dn.str2dn(dn)[0]
))[attribute][0]
nss-pam-ldapd-0.9.6/pynslcd/search.py 0000644 0001750 0000144 00000017637 12270764162 014423 0000000 0000000
# search.py - functions for searching the LDAP database
#
# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import logging
import sys
import ldap
import ldap.ldapobject
import cfg
# global indicator that there was some error connection to an LDAP server
server_error = False
# global indicator of first search operation
first_search = True
class Connection(ldap.ldapobject.ReconnectLDAPObject):
def __init__(self):
ldap.ldapobject.ReconnectLDAPObject.__init__(self, cfg.uri,
retry_max=1, retry_delay=cfg.reconnect_retrytime)
# set connection-specific LDAP options
if cfg.ldap_version:
self.set_option(ldap.OPT_PROTOCOL_VERSION, cfg.ldap_version)
if cfg.deref:
self.set_option(ldap.OPT_DEREF, cfg.deref)
if cfg.timelimit:
self.set_option(ldap.OPT_TIMELIMIT, cfg.timelimit)
self.set_option(ldap.OPT_TIMEOUT, cfg.timelimit)
self.set_option(ldap.OPT_NETWORK_TIMEOUT, cfg.timelimit)
if cfg.referrals:
self.set_option(ldap.OPT_REFERRALS, cfg.referrals)
if cfg.sasl_canonicalize is not None:
self.set_option(ldap.OPT_X_SASL_NOCANON, not cfg.sasl_canonicalize)
self.set_option(ldap.OPT_RESTART, True)
# TODO: register a connection callback (like dis?connect_cb() in myldap.c)
if cfg.ssl or cfg.uri.startswith('ldaps://'):
self.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_HARD)
# TODO: the following should probably be done on the first search
# together with binding, not when creating the connection object
if cfg.ssl == 'STARTTLS':
self.start_tls_s()
def reconnect_after_fail(self):
import invalidator
logging.info('connected to LDAP server %s', cfg.uri)
invalidator.invalidate()
def search_s(self, *args, **kwargs):
# wrapper function to keep the global server_error state
global server_error, first_search
try:
res = ldap.ldapobject.ReconnectLDAPObject.search_s(self, *args, **kwargs)
except ldap.SERVER_DOWN:
server_error = True
raise
if server_error or first_search:
self.reconnect_after_fail()
server_error = False
first_search = False
return res
class LDAPSearch(object):
"""
Class that performs an LDAP search. Subclasses are expected to define the
actual searches and should implement the following members:
case_sensitive - check that these attributes are present in the response
if they were in the request
case_insensitive - check that these attributes are present in the
response if they were in the request
limit_attributes - override response attributes with request attributes
(ensure that only one copy of the value is returned)
required - attributes that are required
canonical_first - search the DN for these attributes and ensure that
they are listed first in the attribute values
mk_filter() (optional) - function that returns the LDAP search filter
The module that contains the Search class can also contain the following
definitions:
bases - list of search bases to be used, if absent or empty falls back
to cfg.bases
scope - search scope, falls back to cfg.scope if absent or empty
filter - an LDAP search filter
attmap - an attribute mapping definition (using he Attributes class)
"""
canonical_first = []
required = []
case_sensitive = []
case_insensitive = []
limit_attributes = []
def __init__(self, conn, base=None, scope=None, filter=None,
attributes=None, parameters=None):
self.conn = conn
# load information from module that defines the class
module = sys.modules[self.__module__]
if base:
self.bases = [base]
else:
self.bases = getattr(module, 'bases', cfg.bases)
self.scope = scope or getattr(module, 'scope', cfg.scope)
self.filter = filter or getattr(module, 'filter', None)
self.attmap = getattr(module, 'attmap', None)
self.attributes = attributes or self.attmap.attributes()
self.parameters = parameters or {}
def __iter__(self):
return self.items()
def items(self):
"""Return the results from the search."""
filter = self.mk_filter()
for base in self.bases:
logging.debug('LDAPSearch(base=%r, filter=%r)', base, filter)
try:
for entry in self.conn.search_s(base, self.scope, filter, self.attributes):
if entry[0]:
entry = self._transform(entry[0], entry[1])
if entry:
yield entry
except ldap.NO_SUCH_OBJECT:
# FIXME: log message
pass
def mk_filter(self):
"""Return the active search filter (based on the read parameters)."""
if self.parameters:
return '(&%s%s)' % (
self.filter,
''.join(self.attmap.mk_filter(attribute, value)
for attribute, value in self.parameters.items()))
return self.filter
def _transform(self, dn, attributes):
"""Handle a single search result entry filtering it with the request
parameters, search options and attribute mapping."""
# translate the attributes using the attribute mapping
if self.attmap:
attributes = self.attmap.translate(attributes)
# make sure value from DN is first value
for attr in self.canonical_first:
primary_value = self.attmap.get_rdn_value(dn, attr)
if primary_value:
values = attributes[attr]
if primary_value in values:
values.remove(primary_value)
attributes[attr] = [primary_value] + values
# check that these attributes have at least one value
for attr in self.required:
if not attributes.get(attr, None):
logging.warning('%s: %s: missing', dn, self.attmap[attr])
return
# check that requested attribute is present (case sensitive)
for attr in self.case_sensitive:
value = self.parameters.get(attr, None)
if value and str(value) not in attributes[attr]:
logging.debug('%s: %s: does not contain %r value', dn, self.attmap[attr], value)
return # not found, skip entry
# check that requested attribute is present (case insensitive)
for attr in self.case_insensitive:
value = self.parameters.get(attr, None)
if value and str(value).lower() not in (x.lower() for x in attributes[attr]):
logging.debug('%s: %s: does not contain %r value', dn, self.attmap[attr], value)
return # not found, skip entry
# limit attribute values to requested value
for attr in self.limit_attributes:
if attr in self.parameters:
attributes[attr] = [self.parameters[attr]]
# return the entry
return dn, attributes
nss-pam-ldapd-0.9.6/pynslcd/network.py 0000644 0001750 0000144 00000010165 12273004007 014620 0000000 0000000
# network.py - lookup functions for network names and addresses
#
# Copyright (C) 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import cache
import common
import constants
import search
attmap = common.Attributes(cn='cn',
ipNetworkNumber='ipNetworkNumber')
filter = '(objectClass=ipNetwork)'
class Search(search.LDAPSearch):
canonical_first = ('cn', )
required = ('cn', )
class Cache(cache.Cache):
tables = ('network_cache', 'network_alias_cache', 'network_address_cache')
create_sql = '''
CREATE TABLE IF NOT EXISTS `network_cache`
( `cn` TEXT PRIMARY KEY COLLATE NOCASE,
`mtime` TIMESTAMP NOT NULL );
CREATE TABLE IF NOT EXISTS `network_alias_cache`
( `network` TEXT NOT NULL COLLATE NOCASE,
`cn` TEXT NOT NULL COLLATE NOCASE,
FOREIGN KEY(`network`) REFERENCES `network_cache`(`cn`)
ON DELETE CASCADE ON UPDATE CASCADE );
CREATE INDEX IF NOT EXISTS `network_alias_idx` ON `network_alias_cache`(`network`);
CREATE TABLE IF NOT EXISTS `network_address_cache`
( `network` TEXT NOT NULL COLLATE NOCASE,
`ipNetworkNumber` TEXT NOT NULL,
FOREIGN KEY(`network`) REFERENCES `network_cache`(`cn`)
ON DELETE CASCADE ON UPDATE CASCADE );
CREATE INDEX IF NOT EXISTS `network_address_idx` ON `network_address_cache`(`network`);
'''
retrieve_sql = '''
SELECT `network_cache`.`cn` AS `cn`,
`network_alias_cache`.`cn` AS `alias`,
`network_address_cache`.`ipNetworkNumber` AS `ipNetworkNumber`,
`network_cache`.`mtime` AS `mtime`
FROM `network_cache`
LEFT JOIN `network_alias_cache`
ON `network_alias_cache`.`network` = `network_cache`.`cn`
LEFT JOIN `network_address_cache`
ON `network_address_cache`.`network` = `network_cache`.`cn`
'''
retrieve_by = dict(
cn='''
( `network_cache`.`cn` = ? OR
`network_cache`.`cn` IN (
SELECT `by_alias`.`network`
FROM `network_alias_cache` `by_alias`
WHERE `by_alias`.`cn` = ?))
''',
ipNetworkNumber='''
`network_cache`.`cn` IN (
SELECT `by_ipNetworkNumber`.`network`
FROM `network_address_cache` `by_ipNetworkNumber`
WHERE `by_ipNetworkNumber`.`ipNetworkNumber` = ?)
''',
)
group_by = (0, ) # cn
group_columns = (1, 2) # alias, ipNetworkNumber
class NetworkRequest(common.Request):
def write(self, networkname, aliases, addresses):
self.fp.write_string(networkname)
self.fp.write_stringlist(aliases)
self.fp.write_int32(len(addresses))
for address in addresses:
self.fp.write_address(address)
def convert(self, dn, attributes, parameters):
netnames = attributes['cn']
yield (netnames[0], netnames[1:], attributes['ipNetworkNumber'])
class NetworkByNameRequest(NetworkRequest):
action = constants.NSLCD_ACTION_NETWORK_BYNAME
def read_parameters(self, fp):
return dict(cn=fp.read_string())
class NetworkByAddressRequest(NetworkRequest):
action = constants.NSLCD_ACTION_NETWORK_BYADDR
def read_parameters(self, fp):
return dict(ipNetworkNumber=fp.read_address())
class NetworkAllRequest(NetworkRequest):
action = constants.NSLCD_ACTION_NETWORK_ALL
nss-pam-ldapd-0.9.6/pynslcd/pam.py 0000644 0001750 0000144 00000034445 12530346244 013723 0000000 0000000
# pam.py - functions authentication, authorisation and session handling
#
# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import logging
import random
import socket
import time
from ldap.controls.ppolicy import PasswordPolicyControl, PasswordPolicyError
from ldap.filter import escape_filter_chars
import ldap
import cfg
import common
import constants
import passwd
import search
import shadow
random = random.SystemRandom()
def authenticate(binddn, password):
# open a new connection
conn = search.Connection()
# bind using the specified credentials
pwctrl = PasswordPolicyControl()
res, data, msgid, ctrls = conn.simple_bind_s(binddn, password, serverctrls=[pwctrl])
# go over bind result server controls
for ctrl in ctrls:
if ctrl.controlType == PasswordPolicyControl.controlType:
# found a password policy control
logging.debug('PasswordPolicyControl found: error=%s (%s), timeBeforeExpiration=%s, graceAuthNsRemaining=%s',
'None' if ctrl.error is None else PasswordPolicyError(ctrl.error).prettyPrint(),
ctrl.error, ctrl.timeBeforeExpiration, ctrl.graceAuthNsRemaining)
if ctrl.error == 0: # passwordExpired
return conn, constants.NSLCD_PAM_AUTHTOK_EXPIRED, PasswordPolicyError(ctrl.error).prettyPrint()
elif ctrl.error == 1: # accountLocked
return conn, constants.NSLCD_PAM_ACCT_EXPIRED, PasswordPolicyError(ctrl.error).prettyPrint()
elif ctrl.error == 2: # changeAfterReset
return conn, constants.NSLCD_PAM_NEW_AUTHTOK_REQD, 'Password change is needed after reset'
elif ctrl.error:
return conn, constants.NSLCD_PAM_PERM_DENIED, PasswordPolicyError(ctrl.error).prettyPrint()
elif ctrl.timeBeforeExpiration is not None:
return conn, constants.NSLCD_PAM_NEW_AUTHTOK_REQD, 'Password will expire in %d seconds' % ctrl.timeBeforeExpiration
elif ctrl.graceAuthNsRemaining is not None:
return conn, constants.NSLCD_PAM_NEW_AUTHTOK_REQD, 'Password expired, %d grace logins left' % ctrl.graceAuthNsRemaining
# perform search for own object (just to do any kind of search)
results = search.LDAPSearch(conn, base=binddn, scope=ldap.SCOPE_BASE,
filter='(objectClass=*)', attributes=['dn', ])
for entry in results:
if entry[0] == binddn:
return conn, constants.NSLCD_PAM_SUCCESS, ''
# if our DN wasn't found raise an error to signal bind failure
raise ldap.NO_SUCH_OBJECT()
def pwmod(conn, userdn, oldpassword, newpassword):
# perform request without old password
try:
conn.passwd_s(userdn, None, newpassword)
except ldap.LDAPError:
# retry with old password
if oldpassword:
conn.passwd_s(userdn, oldpassword, newpassword)
else:
raise
def update_lastchange(conns, userdn):
"""Try to update the shadowLastChange attribute of the entry."""
attribute = shadow.attmap['shadowLastChange']
if attribute == '${shadowLastChange:--1}':
attribute = 'shadowLastChange'
if not attribute or '$' in attribute:
raise ValueError('shadowLastChange has unsupported mapping')
# build the value for the new attribute
if attribute.lower() == 'pwdlastset':
# for AD we use another timestamp */
value = '%d000000000' % (time.time() / 100L + (134774L * 864L))
else:
# time in days since Jan 1, 1970
value = '%d' % (time.time() / (60 * 60 * 24))
# perform the modification, return at first success
for conn in conns:
try:
conn.modify_s(userdn, [(ldap.MOD_REPLACE, attribute, [value])])
return
except ldap.LDAPError:
pass # ignore error and try next connection
class PAMRequest(common.Request):
def validate(self, parameters):
"""This method checks the provided username for validity and fills
in the DN if needed."""
# check username for validity
common.validate_name(parameters['username'])
# look up user DN
entry = passwd.uid2entry(self.conn, parameters['username'])
if not entry:
# FIXME: we should close the stream with an empty response here
raise ValueError('%r: user not found' % parameters['username'])
# save the DN
parameters['userdn'] = entry[0]
# get the "real" username
value = passwd.attmap.get_rdn_value(entry[0], 'uid')
if not value:
# get the username from the uid attribute
values = entry[1]['uid']
if not values or not values[0]:
logging.warning('%s: is missing a %s attribute', entry[0], passwd.attmap['uid'])
value = values[0]
# check the username
if value and not common.is_valid_name(value):
raise ValueError('%s: has invalid %s attribute', entry[0], passwd.attmap['uid'])
# check if the username is different and update it if needed
if value != parameters['username']:
logging.info('username changed from %r to %r', parameters['username'], value)
parameters['username'] = value
class PAMAuthenticationRequest(PAMRequest):
action = constants.NSLCD_ACTION_PAM_AUTHC
def read_parameters(self, fp):
return dict(username=fp.read_string(),
service=fp.read_string(),
ruser=fp.read_string(),
rhost=fp.read_string(),
tty=fp.read_string(),
password=fp.read_string())
# TODO: log call with parameters
def write(self, username, authc=constants.NSLCD_PAM_SUCCESS,
authz=constants.NSLCD_PAM_SUCCESS, msg=''):
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
self.fp.write_int32(authc)
self.fp.write_string(username)
self.fp.write_int32(authz)
self.fp.write_string(msg)
self.fp.write_int32(constants.NSLCD_RESULT_END)
def handle_request(self, parameters):
# if the username is blank and rootpwmoddn is configured, try to
# authenticate as administrator, otherwise validate request as usual
if not parameters['username'] and cfg.rootpwmoddn:
# authenticate as rootpwmoddn
binddn = cfg.rootpwmoddn
# if the caller is root we will allow the use of rootpwmodpw
if not parameters['password'] and self.calleruid == 0 and cfg.rootpwmodpw:
password = cfg.rootpwmodpw
elif parameters['password']:
password = parameters['password']
else:
raise ValueError('password missing')
else:
self.validate(parameters)
binddn = parameters['userdn']
password = parameters['password']
# try authentication
try:
conn, authz, msg = authenticate(binddn, password)
except ldap.INVALID_CREDENTIALS, e:
try:
msg = e[0]['desc']
except:
msg = str(e)
logging.debug('bind failed: %s', msg)
self.write(parameters['username'], authc=constants.NSLCD_PAM_AUTH_ERR, msg=msg)
return
if authz != constants.NSLCD_PAM_SUCCESS:
logging.warning('%s: %s: %s', binddn, parameters['username'], msg)
else:
logging.debug('bind successful')
# FIXME: perform shadow attribute checks with check_shadow()
self.write(parameters['username'], authz=authz, msg=msg)
class PAMAuthorisationRequest(PAMRequest):
action = constants.NSLCD_ACTION_PAM_AUTHZ
def read_parameters(self, fp):
return dict(username=fp.read_string(),
service=fp.read_string(),
ruser=fp.read_string(),
rhost=fp.read_string(),
tty=fp.read_string())
# TODO: log call with parameters
def write(self, authz=constants.NSLCD_PAM_SUCCESS, msg=''):
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
self.fp.write_int32(authz)
self.fp.write_string(msg)
self.fp.write_int32(constants.NSLCD_RESULT_END)
def check_authzsearch(self, parameters):
if not cfg.pam_authz_searches:
return
# escape all parameters
variables = dict((k, escape_filter_chars(v)) for k, v in parameters.items())
variables.update(
hostname=escape_filter_chars(socket.gethostname()),
fqdn=escape_filter_chars(socket.getfqdn()),
dn=variables['userdn'],
uid=variables['username'],
)
# go over all authz searches
for x in cfg.pam_authz_searches:
filter = x.value(variables)
logging.debug('trying pam_authz_search "%s"', filter)
srch = search.LDAPSearch(self.conn, filter=filter, attributes=('dn', ))
try:
dn, values = srch.items().next()
except StopIteration:
logging.error('pam_authz_search "%s" found no matches', filter)
raise
logging.debug('pam_authz_search found "%s"', dn)
def handle_request(self, parameters):
# fill in any missing userdn, etc.
self.validate(parameters)
# check authorisation search
try:
self.check_authzsearch(parameters)
except StopIteration:
self.write(constants.NSLCD_PAM_PERM_DENIED,
'LDAP authorisation check failed')
return
# all tests passed, return OK response
self.write()
class PAMPasswordModificationRequest(PAMRequest):
action = constants.NSLCD_ACTION_PAM_PWMOD
def read_parameters(self, fp):
return dict(username=fp.read_string(),
service=fp.read_string(),
ruser=fp.read_string(),
rhost=fp.read_string(),
tty=fp.read_string(),
asroot=fp.read_int32(),
oldpassword=fp.read_string(),
newpassword=fp.read_string())
# TODO: log call with parameters
def write(self, rc=constants.NSLCD_PAM_SUCCESS, msg=''):
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
self.fp.write_int32(rc)
self.fp.write_string(msg)
self.fp.write_int32(constants.NSLCD_RESULT_END)
def handle_request(self, parameters):
# fill in any missing userdn, etc.
self.validate(parameters)
# check if pam_password_prohibit_message is set
if cfg.pam_password_prohibit_message:
self.write(constants.NSLCD_PAM_PERM_DENIED,
cfg.pam_password_prohibit_message)
return
# check if the the user passed the rootpwmoddn
if parameters['asroot']:
binddn = cfg.rootpwmoddn
# check if rootpwmodpw should be used
if not parameters['oldpassword'] and self.calleruid == 0 and cfg.rootpwmodpw:
password = cfg.rootpwmodpw
elif parameters['oldpassword']:
password = parameters['oldpassword']
else:
raise ValueError('password missing')
else:
binddn = parameters['userdn']
password = parameters['oldpassword']
# TODO: check if shadow properties allow password change
# perform password modification
try:
conn, authz, msg = authenticate(binddn, password)
pwmod(conn, parameters['userdn'], parameters['oldpassword'], parameters['newpassword'])
# try to update lastchange with normal or user connection
update_lastchange((self.conn, conn), parameters['userdn'])
except ldap.INVALID_CREDENTIALS, e:
try:
msg = e[0]['desc']
except:
msg = str(e)
logging.debug('pwmod failed: %s', msg)
self.write(constants.NSLCD_PAM_PERM_DENIED, msg)
return
logging.debug('pwmod successful')
self.write()
SESSION_ID_LENGTH = 25
SESSION_ID_ALPHABET = (
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"01234567890"
)
def generate_session_id():
return ''.join(
random.choice(SESSION_ID_ALPHABET)
for i in range(SESSION_ID_LENGTH)
)
class PAMSessionOpenRequest(PAMRequest):
action = constants.NSLCD_ACTION_PAM_SESS_O
def read_parameters(self, fp):
return dict(username=fp.read_string(),
service=fp.read_string(),
ruser=fp.read_string(),
rhost=fp.read_string(),
tty=fp.read_string())
# TODO: log call with parameters
def write(self, sessionid):
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
self.fp.write_string(sessionid)
self.fp.write_int32(constants.NSLCD_RESULT_END)
def handle_request(self, parameters):
# generate a session id
session_id = generate_session_id()
self.write(session_id)
class PAMSessionCloseRequest(PAMRequest):
action = constants.NSLCD_ACTION_PAM_SESS_C
def read_parameters(self, fp):
return dict(username=fp.read_string(),
service=fp.read_string(),
ruser=fp.read_string(),
rhost=fp.read_string(),
tty=fp.read_string(),
session_id=fp.read_string())
# TODO: log call with parameters
def write(self):
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
self.fp.write_int32(constants.NSLCD_RESULT_END)
def handle_request(self, parameters):
self.write()
nss-pam-ldapd-0.9.6/pynslcd/usermod.py 0000644 0001750 0000144 00000011407 12270764162 014621 0000000 0000000
# usermod.py - functions for modifying user information
#
# Copyright (C) 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import ctypes
import ctypes.util
import logging
import os
import os.path
import ldap
import cfg
import constants
import pam
import passwd
def list_shells():
"""List the shells from /etc/shells."""
libc = ctypes.CDLL(ctypes.util.find_library("c"))
libc.setusershell()
while True:
shell = ctypes.c_char_p(libc.getusershell()).value
if not shell:
break
yield shell
libc.endusershell()
class UserModRequest(pam.PAMRequest):
action = constants.NSLCD_ACTION_USERMOD
def read_parameters(self, fp):
username = fp.read_string()
asroot = fp.read_int32()
password = fp.read_string()
mods = {}
while True:
key = fp.read_int32()
if key == constants.NSLCD_USERMOD_END:
break
mods[key] = fp.read_string()
return dict(username=username,
asroot=asroot,
password=password,
mods=mods)
def write_result(self, mod, message):
self.fp.write_int32(mod)
self.fp.write_string(message)
def handle_request(self, parameters):
# fill in any missing userdn, etc.
self.validate(parameters)
is_root = (self.calleruid == 0) and parameters['asroot']
mods = []
# check if the the user passed the rootpwmoddn
if parameters['asroot']:
binddn = cfg.rootpwmoddn
# check if rootpwmodpw should be used
if not parameters['password'] and is_root and cfg.rootpwmodpw:
password = cfg.rootpwmodpw
else:
password = parameters['password']
else:
binddn = parameters['userdn']
password = parameters['password']
# write response header
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
# check home directory modification
homedir = parameters['mods'].get(constants.NSLCD_USERMOD_HOMEDIR)
if homedir:
if is_root:
mods.append((ldap.MOD_REPLACE, passwd.attmap['homeDirectory'], [homedir]))
elif not os.path.isabs(homedir):
self.write_result(constants.NSLCD_USERMOD_HOMEDIR,
'should be an absolute path')
elif not os.path.isdir(homedir):
self.write_result(constants.NSLCD_USERMOD_HOMEDIR,
'not a directory')
else:
mods.append((ldap.MOD_REPLACE, passwd.attmap['homeDirectory'], [homedir]))
# check login shell modification
shell = parameters['mods'].get(constants.NSLCD_USERMOD_SHELL)
if shell:
if is_root:
mods.append((ldap.MOD_REPLACE, passwd.attmap['loginShell'], [shell]))
elif shell not in list_shells():
self.write_result(constants.NSLCD_USERMOD_SHELL,
'unlisted shell')
elif not os.path.isfile(shell) or not os.access(shell, os.X_OK):
self.write_result(constants.NSLCD_USERMOD_SHELL,
'not an executable')
else:
mods.append((ldap.MOD_REPLACE, passwd.attmap['loginShell'], [shell]))
# get a connection and perform the modification
if mods:
try:
conn, authz, msg = pam.authenticate(binddn, password)
conn.modify_s(parameters['userdn'], mods)
logging.info('changed information for %s', parameters['userdn'])
except (ldap.INVALID_CREDENTIALS, ldap.INSUFFICIENT_ACCESS), e:
try:
msg = e[0]['desc']
except:
msg = str(e)
logging.debug('modification failed: %s', msg)
self.write_result(constants.NSLCD_USERMOD_RESULT, msg)
# write closing statement
self.fp.write_int32(constants.NSLCD_USERMOD_END)
self.fp.write_int32(constants.NSLCD_RESULT_END)
nss-pam-ldapd-0.9.6/pynslcd/expr.py 0000644 0001750 0000144 00000015431 12270764162 014122 0000000 0000000
# expr.py - expression handling functions
#
# Copyright (C) 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
"""Module for handling expressions used for LDAP searches.
>>> expr = Expression('foo=$foo')
>>> expr.value(dict(foo='XX'))
'foo=XX'
>>> expr = Expression('foo=${foo:-$bar}')
>>> expr.value(dict(foo='', bar='YY'))
'foo=YY'
>>> expr.value(dict(bar=['YY', 'ZZ']))
'foo=YY'
>>> Expression(r'${passwd#{crypt\}}').value(dict(passwd='{crypt}HASH'))
'HASH'
>>> Expression('${var#trim}').value(dict(var='notrimme'))
'notrimme'
>>> Expression('${var#?trim}').value(dict(var='xtrimme'))
'me'
>>> Expression('${var#*trim}').value(dict(var='xxxtrimme'))
'me'
>>> Expression('${var%.txt}').value(dict(var='foo.txt'))
'foo'
>>> Expression('${x#$y}').value(dict(x='a/b', y='a'))
'/b'
>>> Expression('${var#t*is}').value(dict(var='this is a test'))
' is a test'
>>> Expression('${var##t*is}').value(dict(var='this is a test'))
' a test'
>>> Expression('${var%t*st}').value(dict(var='this is a test'))
'this is a '
>>> Expression('${var%%t*st}').value(dict(var='this is a test'))
''
"""
import fnmatch
import re
# exported names
__all__ = ('Expression', )
# TODO: do more expression validity checking
class MyIter(object):
"""Custom iterator-like class with a back() method."""
def __init__(self, value):
self.value = value
self.pos = 0
def next(self):
self.pos += 1
try:
return self.value[self.pos - 1]
except IndexError:
return None
def back(self):
self.pos -= 1
def __iter__(self):
return self
def get_name(self):
"""Read a variable name from the value iterator."""
name = ''
for c in self:
if not c or not c.isalnum():
self.back()
return name
name += c
return name
class DollarExpression(object):
"""Class for handling a variable $xxx ${xxx}, ${xxx:-yyy} or ${xxx:+yyy}
expression."""
def __init__(self, value):
"""Parse the expression as the start of a $-expression."""
self.op = None
self.expr = None
c = value.next()
if c == '{':
self.name = value.get_name()
c = value.next()
if c == '}':
return
elif c == ':':
self.op = c + value.next()
elif c in ('#', '%'):
c2 = value.next()
if c2 in ('#', '%'):
c += c2
else:
value.back()
self.op = c
else:
raise ValueError('Expecting operator')
self.expr = Expression(value, endat='}')
elif c == '(':
self.name = None
self.op = value.get_name()
c = value.next()
if c != '(':
raise ValueError("Expecting '('")
self.expr = Expression(value, endat=')')
c = value.next()
if c != ')':
raise ValueError("Expecting ')'")
else:
value.back()
self.name = value.get_name()
def value(self, variables):
"""Expand the expression using the variables specified."""
# lookup the value
value = variables.get(self.name, '')
if value in (None, [], ()):
value = ''
elif isinstance(value, (list, tuple)):
value = value[0]
# TODO: try to return multiple values, one for each value of the list
if self.op == ':-':
return value if value else self.expr.value(variables)
elif self.op == ':+':
return self.expr.value(variables) if value else ''
elif self.op in ('#', '##', '%', '%%'):
match = fnmatch.translate(self.expr.value(variables))
if self.op == '#':
match = match.replace('*', '*?').replace(r'\Z', r'(?P.*)\Z')
elif self.op == '##':
match = match.replace(r'\Z', r'(?P.*?)\Z')
elif self.op == '%':
match = r'(?P.*)' + match.replace('*', '*?')
elif self.op == '%%':
match = r'(?P.*?)' + match
match = re.match(match, value)
return match.group('replace') if match else value
elif self.op == 'lower':
return self.expr.value(variables).lower()
elif self.op == 'upper':
return self.expr.value(variables).upper()
return value
def variables(self, results):
"""Add the variables used in the expression to results."""
if self.name:
results.add(self.name)
if self.expr:
self.expr.variables(results)
class Expression(object):
"""Class for parsing and expanding an expression."""
def __init__(self, value, endat=None):
"""Parse the expression as a string."""
if not isinstance(value, MyIter):
self.expression = value
value = MyIter(value)
expr = []
literal = ''
c = value.next()
while c != endat:
if c == '$':
if literal:
expr.append(literal)
expr.append(DollarExpression(value))
literal = ''
elif c == '\\':
literal += value.next()
else:
literal += c
c = value.next()
if literal:
expr.append(literal)
self.expr = expr
def value(self, variables):
"""Expand the expression using the variables specified."""
res = ''
for x in self.expr:
if hasattr(x, 'value'):
res += x.value(variables)
else:
res += x
return res
def variables(self, results=None):
"""Return the variables defined in the expression."""
if not results:
results = set()
for x in self.expr:
if hasattr(x, 'variables'):
x.variables(results)
return results
def __str__(self):
return self.expression
def __repr__(self):
return repr(str(self))
nss-pam-ldapd-0.9.6/pynslcd/alias.py 0000644 0001750 0000144 00000005653 12273004007 014226 0000000 0000000
# alias.py - lookup functions for email aliases
#
# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import cache
import common
import constants
import search
attmap = common.Attributes(cn='cn', rfc822MailMember='rfc822MailMember')
filter = '(objectClass=nisMailAlias)'
class Search(search.LDAPSearch):
case_insensitive = ('cn', )
limit_attributes = ('cn', )
required = ('cn', 'rfc822MailMember')
class Cache(cache.Cache):
tables = ('alias_cache', 'alias_member_cache')
create_sql = '''
CREATE TABLE IF NOT EXISTS `alias_cache`
( `cn` TEXT PRIMARY KEY COLLATE NOCASE,
`mtime` TIMESTAMP NOT NULL );
CREATE TABLE IF NOT EXISTS `alias_member_cache`
( `alias` TEXT NOT NULL COLLATE NOCASE,
`rfc822MailMember` TEXT NOT NULL,
FOREIGN KEY(`alias`) REFERENCES `alias_cache`(`cn`)
ON DELETE CASCADE ON UPDATE CASCADE );
CREATE INDEX IF NOT EXISTS `alias_member_idx` ON `alias_member_cache`(`alias`);
'''
retrieve_sql = '''
SELECT `alias_cache`.`cn` AS `cn`,
`alias_member_cache`.`rfc822MailMember` AS `rfc822MailMember`,
`alias_cache`.`mtime` AS `mtime`
FROM `alias_cache`
LEFT JOIN `alias_member_cache`
ON `alias_member_cache`.`alias` = `alias_cache`.`cn`
'''
retrieve_by = dict(
rfc822MailMember='''
`cn` IN (
SELECT `a`.`alias`
FROM `alias_member_cache` `a`
WHERE `a`.`rfc822MailMember` = ?)
''',
)
group_by = (0, ) # cn
group_columns = (1, ) # rfc822MailMember
class AliasRequest(common.Request):
def write(self, name, members):
self.fp.write_string(name)
self.fp.write_stringlist(members)
def convert(self, dn, attributes, parameters):
names = attributes['cn']
members = attributes['rfc822MailMember']
for name in names:
yield (name, members)
class AliasByNameRequest(AliasRequest):
action = constants.NSLCD_ACTION_ALIAS_BYNAME
def read_parameters(self, fp):
return dict(cn=fp.read_string())
class AliasAllRequest(AliasRequest):
action = constants.NSLCD_ACTION_ALIAS_ALL
nss-pam-ldapd-0.9.6/pynslcd/passwd.py 0000644 0001750 0000144 00000011536 12530340161 014433 0000000 0000000
# passwd.py - lookup functions for user account information
#
# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import logging
import cache
import cfg
import common
import constants
import search
attmap = common.Attributes(uid='uid',
userPassword='"*"',
uidNumber='uidNumber',
gidNumber='gidNumber',
gecos='"${gecos:-$cn}"',
homeDirectory='homeDirectory',
loginShell='loginShell',
objectClass='objectClass')
filter = '(objectClass=posixAccount)'
class Search(search.LDAPSearch):
case_sensitive = ('uid', 'uidNumber', )
limit_attributes = ('uid', 'uidNumber', )
required = ('uid', 'uidNumber', 'gidNumber', 'gecos', 'homeDirectory',
'loginShell')
class Cache(cache.Cache):
create_sql = '''
CREATE TABLE IF NOT EXISTS `passwd_cache`
( `uid` TEXT PRIMARY KEY,
`userPassword` TEXT,
`uidNumber` INTEGER NOT NULL UNIQUE,
`gidNumber` INTEGER NOT NULL,
`gecos` TEXT,
`homeDirectory` TEXT,
`loginShell` TEXT,
`mtime` TIMESTAMP NOT NULL );
'''
class PasswdRequest(common.Request):
def write(self, name, passwd, uid, gid, gecos, home, shell):
self.fp.write_string(name)
self.fp.write_string(passwd)
self.fp.write_int32(uid)
self.fp.write_int32(gid)
self.fp.write_string(gecos)
self.fp.write_string(home)
self.fp.write_string(shell)
def convert(self, dn, attributes, parameters):
names = attributes['uid']
if 'shadowAccount' in attributes['objectClass']:
passwd = 'x'
else:
try:
passwd = attributes['userPassword'][0]
except IndexError:
passwd = None
if not passwd or self.calleruid != 0:
passwd = '*'
uids = [int(x) for x in attributes['uidNumber']]
gid = int(attributes['gidNumber'][0])
gecos = attributes['gecos'][0]
home = attributes['homeDirectory'][0]
shell = attributes['loginShell'][0]
for name in names:
if not common.is_valid_name(name):
logging.warning('%s: %s: denied by validnames option', dn, attmap['uid'])
else:
for uid in uids:
if uid >= cfg.nss_min_uid:
yield (name, passwd, uid, gid, gecos, home, shell)
class PasswdByNameRequest(PasswdRequest):
action = constants.NSLCD_ACTION_PASSWD_BYNAME
def read_parameters(self, fp):
name = fp.read_string()
common.validate_name(name)
return dict(uid=name)
class PasswdByUidRequest(PasswdRequest):
action = constants.NSLCD_ACTION_PASSWD_BYUID
def read_parameters(self, fp):
return dict(uidNumber=fp.read_int32())
def handle_request(self, parameters):
# check requested numeric id
if parameters['uidNumber'] >= cfg.nss_min_uid:
return super(PasswdByUidRequest, self).handle_request(parameters)
# write the final result code to signify empty results
self.fp.write_int32(constants.NSLCD_RESULT_END)
class PasswdAllRequest(PasswdRequest):
action = constants.NSLCD_ACTION_PASSWD_ALL
def handle_request(self, parameters):
if not cfg.nss_disable_enumeration:
return super(PasswdAllRequest, self).handle_request(parameters)
def uid2entry(conn, uid):
"""Look up the user by uid and return the LDAP entry or None if the user
was not found."""
for dn, attributes in Search(conn, parameters=dict(uid=uid)):
if any(int(x) >= cfg.nss_min_uid for x in attributes['uidNumber']):
return dn, attributes
# FIXME: use cache of dn2uid and try to use DN to get uid attribute
def dn2uid(conn, dn):
"""Look up the user by dn and return a uid or None if the user was
not found."""
for dn, attributes in Search(conn, base=dn):
if any(int(x) >= cfg.nss_min_uid for x in attributes['uidNumber']):
return attributes['uid'][0]
nss-pam-ldapd-0.9.6/pynslcd/cfg.py 0000644 0001750 0000144 00000031236 12530340161 013670 0000000 0000000
# cfg.py - module for accessing configuration information
#
# Copyright (C) 2010-2015 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import logging
import re
import ldap
# the number of threads to start
threads = 5
# the user id nslcd should be run as
uid = None
# the group id nslcd should be run as
gid = None
# the configured loggers
logs = []
# the LDAP server to use
uri = None # FIXME: support multiple servers and have a fail-over mechanism
# LDAP protocol version to use (perhaps fix at 3?)
ldap_version = ldap.VERSION3
# the DN to use when binding
binddn = None # FIXME: add support
bindpw = None # FIXME: add support
# the DN to use to perform password modifications as root
rootpwmoddn = None
rootpwmodpw = None
# SASL configuration
sasl_mech = None # FIXME: add support
sasl_realm = None # FIXME: add support
sasl_authcid = None # FIXME: add support
sasl_authzid = None # FIXME: add support
sasl_secprops = None # FIXME: add support
sasl_canonicalize = None # FIXME: add support
# LDAP bases to search
bases = []
# default search scope for searches
scope = ldap.SCOPE_SUBTREE
deref = ldap.DEREF_NEVER
referrals = True
# timing configuration
bind_timelimit = 10 # FIXME: add support
timelimit = ldap.NO_LIMIT
idle_timelimit = 0 # FIXME: add support
reconnect_sleeptime = 1 # FIXME: add support
reconnect_retrytime = 10
# SSL/TLS options
ssl = None
tls_reqcert = None
tls_cacertdir = None
tls_cacertfile = None
tls_randfile = None
tls_ciphers = None
tls_cert = None
tls_key = None
# other options
pagesize = 0 # FIXME: add support
nss_initgroups_ignoreusers = set()
nss_min_uid = 0
nss_nested_groups = False
nss_getgrent_skipmembers = False
nss_disable_enumeration = False
validnames = re.compile(r'^[a-z0-9._@$][a-z0-9._@$ \\~-]{0,98}[a-z0-9._@$~-]$', re.IGNORECASE)
pam_authz_searches = []
pam_password_prohibit_message = None
reconnect_invalidate = set()
# allowed boolean values
_boolean_options = {'on': True, 'yes': True, 'true': True, '1': True,
'off': False, 'no': False, 'false': False, '0': False}
# allowed log levels (we log notice which is unsupported in Python to warning)
_log_levels = {'crit': logging.CRITICAL, 'error': logging.ERROR,
'err': logging.ERROR, 'warning': logging.WARNING,
'notice': logging.WARNING, 'info': logging.INFO,
'debug': logging.DEBUG, 'none': logging.INFO}
# allowed values for scope option
if not hasattr(ldap, 'SCOPE_CHILDREN') and ldap.VENDOR_VERSION >= 20400:
ldap.SCOPE_CHILDREN = 3 # OpenLDAP extension
_scope_options = dict(sub=ldap.SCOPE_SUBTREE, subtree=ldap.SCOPE_SUBTREE,
one=ldap.SCOPE_ONELEVEL, onelevel=ldap.SCOPE_ONELEVEL,
base=ldap.SCOPE_BASE)
if hasattr(ldap, 'SCOPE_CHILDREN'):
_scope_options['children'] = ldap.SCOPE_CHILDREN
# allowed values for the deref option
_deref_options = dict(never=ldap.DEREF_NEVER,
searching=ldap.DEREF_SEARCHING,
finding=ldap.DEREF_FINDING,
always=ldap.DEREF_ALWAYS)
# allowed values for the ssl option
_ssl_options = dict(start_tls='STARTTLS', starttls='STARTTLS',
on='LDAPS', off=None)
# allowed values for the tls_reqcert option
_tls_reqcert_options = {'never': ldap.OPT_X_TLS_NEVER,
'no': ldap.OPT_X_TLS_NEVER,
'allow': ldap.OPT_X_TLS_ALLOW,
'try': ldap.OPT_X_TLS_TRY,
'demand': ldap.OPT_X_TLS_DEMAND,
'yes': ldap.OPT_X_TLS_DEMAND,
'hard': ldap.OPT_X_TLS_HARD}
def _get_maps():
# separate function as not to pollute the namespace and avoid import loops
import alias, ether, group, host, netgroup, network, passwd
import protocol, rpc, service, shadow
import sys
return dict(
alias=alias, aliases=alias,
ether=ether, ethers=ether,
group=group,
host=host, hosts=host,
netgroup=netgroup,
network=network, networks=network,
passwd=passwd,
protocol=protocol, protocols=protocol,
rpc=rpc,
service=service, services=service,
shadow=shadow,
none=sys.modules[__name__]
)
class ParseError(Exception):
def __init__(self, filename, lineno, message):
self.message = '%s:%d: %s' % (filename, lineno, message)
def __repr__(self):
return self.message
__str__ = __repr__
def read(filename):
maps = _get_maps()
lineno = 0
for line in open(filename, 'r'):
lineno += 1
line = line.strip()
# skip comments and blank lines
if re.match('(#.*)?$', line, re.IGNORECASE):
continue
# parse options with a single integer argument
m = re.match('(?Pthreads|ldap_version|bind_timelimit|timelimit|idle_timelimit|reconnect_sleeptime|reconnect_retrytime|pagesize|nss_min_uid)\s+(?P\d+)',
line, re.IGNORECASE)
if m:
globals()[m.group('keyword').lower()] = int(m.group('value'))
continue
# parse options with a single boolean argument
m = re.match('(?Preferrals|nss_nested_groups|nss_getgrent_skipmembers|nss_disable_enumeration)\s+(?P%s)' %
'|'.join(_boolean_options.keys()),
line, re.IGNORECASE)
if m:
globals()[m.group('keyword').lower()] = _boolean_options[m.group('value').lower()]
continue
# parse options with a single no-space value
m = re.match('(?Puid|gid|bindpw|rootpwmodpw|sasl_mech)\s+(?P\S+)',
line, re.IGNORECASE)
if m:
globals()[m.group('keyword').lower()] = m.group('value')
continue
# parse options with a single value that can contain spaces
m = re.match('(?Pbinddn|rootpwmoddn|sasl_realm|sasl_authcid|sasl_authzid|sasl_secprops|krb5_ccname|tls_cacertdir|tls_cacertfile|tls_randfile|tls_ciphers|tls_cert|tls_key|pam_password_prohibit_message)\s+(?P\S.*)',
line, re.IGNORECASE)
if m:
globals()[m.group('keyword').lower()] = m.group('value')
continue
# log []
m = re.match('log\s+(?Psyslog|/\S*)(\s+(?P%s))?' %
'|'.join(_log_levels.keys()),
line, re.IGNORECASE)
if m:
logs.append((m.group('scheme'), _log_levels[str(m.group('level')).lower()]))
continue
# uri
m = re.match('uri\s+(?P\S+)', line, re.IGNORECASE)
if m:
# FIXME: support multiple URI values
# FIXME: support special DNS and DNS:domain values
global uri
uri = m.group('uri')
continue
# base