Import Yubico's pam-u2f from https://github.com/Yubico/pam-u2f.git
This commit is contained in:
parent
95f430ca15
commit
46988a0ecd
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1000
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
|
@ -0,0 +1,253 @@
|
|||
language: c
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- name: Xenial gcc-7
|
||||
os: linux
|
||||
compiler: gcc-7
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- gcc-7
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-xenial-gcc7.sh
|
||||
- name: Xenial gcc-8
|
||||
os: linux
|
||||
compiler: gcc-8
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- gcc-8
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-xenial-gcc8.sh
|
||||
- name: Xenial gcc-9
|
||||
os: linux
|
||||
compiler: gcc-9
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- gcc-9
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-xenial-gcc9.sh
|
||||
- name: Xenial clang-7
|
||||
os: linux
|
||||
compiler: clang-7
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-7
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- clang-7
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-xenial-clang7.sh
|
||||
- name: Xenial clang-8
|
||||
os: linux
|
||||
compiler: clang-8
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-8
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- clang-8
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-xenial-clang8.sh
|
||||
- name: Bionic gcc-7 and clang-format
|
||||
os: linux
|
||||
compiler: gcc-7
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- clang-format-6.0
|
||||
- gcc-7
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-bionic-gcc7.sh
|
||||
- name: Bionic gcc-8
|
||||
os: linux
|
||||
compiler: gcc-8
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- gcc-8
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-bionic-gcc8.sh
|
||||
- name: Bionic gcc-9
|
||||
os: linux
|
||||
compiler: gcc-9
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- gcc-9
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-bionic-gcc9.sh
|
||||
- name: Bionic clang-7
|
||||
os: linux
|
||||
compiler: clang-7
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main'
|
||||
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- clang-7
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-bionic-clang7.sh
|
||||
- name: Bionic clang-8
|
||||
os: linux
|
||||
compiler: clang-8
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:yubico/stable'
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main'
|
||||
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
packages:
|
||||
- autoconf
|
||||
- check
|
||||
- clang-8
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libfido2-dev
|
||||
- libpam-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- pkg-config
|
||||
script: ./build-aux/ci/build-bionic-clang8.sh
|
||||
- name: macOS xcode9.4
|
||||
os: osx
|
||||
osx_image: xcode9.4
|
||||
compiler: clang
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- check
|
||||
- cmake
|
||||
- gengetopt
|
||||
- help2man
|
||||
- mandoc
|
||||
- openssl@1.1
|
||||
- pkg-config
|
||||
update: true
|
||||
script: ./build-aux/ci/build-osx9.4-clang.sh
|
||||
- name: macOS xcode11
|
||||
os: osx
|
||||
osx_image: xcode11
|
||||
compiler: clang
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- check
|
||||
- cmake
|
||||
- gengetopt
|
||||
- help2man
|
||||
- mandoc
|
||||
- openssl@1.1
|
||||
- pkg-config
|
||||
update: true
|
||||
script: ./build-aux/ci/build-osx11-clang.sh
|
|
@ -0,0 +1 @@
|
|||
Alessio Di Mauro <alessio@yubico.com>
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2014-2018 Yubico AB
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,76 @@
|
|||
# Copyright (C) 2014-2018 Yubico AB - See COPYING
|
||||
|
||||
SUBDIRS = . pamu2fcfg tests
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
AM_CFLAGS = $(CWFLAGS)
|
||||
AM_CPPFLAGS = $(LIBFIDO2_CFLAGS) $(LIBCRYPTO_CFLAGS)
|
||||
|
||||
libdir = $(PAMDIR)
|
||||
|
||||
lib_LTLIBRARIES = pam_u2f.la
|
||||
|
||||
pam_u2f_la_SOURCES = pam-u2f.c
|
||||
pam_u2f_la_SOURCES += util.c util.h
|
||||
pam_u2f_la_SOURCES += drop_privs.h drop_privs.c
|
||||
pam_u2f_la_SOURCES += b64.c b64.h
|
||||
pam_u2f_la_SOURCES += explicit_bzero.c
|
||||
|
||||
pam_u2f_la_LIBADD = -lpam
|
||||
pam_u2f_la_LIBADD += $(LIBFIDO2_LIBS) $(LIBCRYPTO_LIBS)
|
||||
pam_u2f_la_LDFLAGS = -module -avoid-version
|
||||
|
||||
DEFS = -DDEBUG_PAM -DPAM_DEBUG @DEFS@
|
||||
|
||||
if ENABLE_MAN
|
||||
dist_man8_MANS = $(top_builddir)/man/pam_u2f.8
|
||||
DISTCLEANFILES = $(dist_man8_MANS)
|
||||
|
||||
MANSOURCES = $(top_builddir)/man/pam_u2f.8.txt
|
||||
EXTRA_DIST = $(MANSOURCES)
|
||||
|
||||
SUFFIXES = .8.txt .8
|
||||
|
||||
.8.txt.8:
|
||||
$(A2X) --format=manpage -L -a revdate="Version $(VERSION)" $<
|
||||
endif
|
||||
|
||||
# Release
|
||||
|
||||
install-exec-hook:
|
||||
rm -f $(PAMDIR)/pam_u2f.la
|
||||
chmod -f 644 $(PAMDIR)/pam_u2f.so || true
|
||||
|
||||
indent:
|
||||
clang-format -i *.c *.h pamu2fcfg/*.c pamu2fcfg/*.h
|
||||
|
||||
ChangeLog:
|
||||
cd $(srcdir) && git2cl > ChangeLog
|
||||
|
||||
PROJECT = pam-u2f
|
||||
|
||||
release:
|
||||
@if test ! -d "$(YUBICO_WWW_REPO)"; then \
|
||||
echo "WWW repo not found!"; \
|
||||
echo "Make sure that YUBICO_WWW_REPO is set"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if test -z "$(KEYID)"; then \
|
||||
echo "Try this instead:"; \
|
||||
echo " make release KEYID=[PGPKEYID]"; \
|
||||
echo "For example:"; \
|
||||
echo " make release KEYID=2117364A"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@head -5 $(srcdir)/NEWS | \
|
||||
grep -q "Version $(VERSION) .released `date -I`" || \
|
||||
(echo 'error: Update date/version in $(srcdir)/NEWS.'; exit 1)
|
||||
rm -f $(srcdir)/ChangeLog
|
||||
sudo make ChangeLog distcheck
|
||||
gpg --detach-sign --default-key $(KEYID) $(PACKAGE)-$(VERSION).tar.gz
|
||||
gpg --verify $(PACKAGE)-$(VERSION).tar.gz.sig
|
||||
cd $(srcdir) && git push
|
||||
cd $(srcdir) && git tag -u $(KEYID) -m $(VERSION) $(PACKAGE)-$(VERSION)
|
||||
cd $(srcdir) && git push --tags
|
||||
$(YUBICO_WWW_REPO)/publish $(PROJECT) $(VERSION) $(PACKAGE)-$(VERSION).tar.gz*
|
|
@ -0,0 +1,48 @@
|
|||
Copyright (c) 2014-2018 Yubico AB - See COPYING
|
||||
|
||||
pam-u2f NEWS -- History of user-visible changes. -*- outline -*-
|
||||
|
||||
* Version 1.0.9 (unreleased)
|
||||
|
||||
* Version 1.0.8 (released 2019-06-04)
|
||||
** Fix debug file descriptor leak CVE-2019-12210.
|
||||
** Fix insecure debug file handling CVE-2019-12209.
|
||||
Both reported by Matthias Gerstner of the SUSE Security Team.
|
||||
** Fix a non-critical buffer oob access.
|
||||
|
||||
* Version 1.0.7 (released 2018-05-15)
|
||||
** Add authpending_file to signal authentication activity
|
||||
** Add nodetect to skip to avoid unnecessary cue messages
|
||||
|
||||
* Version 1.0.6 (released 2018-04-18)
|
||||
** Fix an issue when using syslog as a debug facility.
|
||||
** Do not honor cue if no sutable device is found.
|
||||
|
||||
* Version 1.0.5 (released 2018-04-16)
|
||||
** General bugfixes and quality-of-life improvements.
|
||||
|
||||
* Version 1.0.4 (released 2016-01-07)
|
||||
** Fixed possible permission escalation when using XDG_CONFIG_HOME.
|
||||
|
||||
* Version 1.0.3 (released 2015-11-02)
|
||||
** Bugfix in pamu2fcfg.
|
||||
** Minor improvements for verbose mode in pamu2fcfg.
|
||||
|
||||
* Version 1.0.2 (released 2015-10-06)
|
||||
** Changes to automake flags.
|
||||
** Improve build on OS X.
|
||||
|
||||
* Version 1.0.1 (released 2015-06-18)
|
||||
** Minor changes to man pages and install hooks.
|
||||
|
||||
* Version 1.0.0 (released 2015-06-17)
|
||||
** Use XDG_CONFIG_HOME as default for config files.
|
||||
** Added manual and interactive mode.
|
||||
** Added verbose mode.
|
||||
|
||||
* Version 0.0.1 (released 2015-01-16)
|
||||
** Changed failure mode after authentication error.
|
||||
** Added call to setcred.
|
||||
|
||||
* Version 0.0.0 (released 2014-12-16)
|
||||
** Initial release.
|
|
@ -0,0 +1,272 @@
|
|||
Pluggable Authentication Module (PAM) Universal 2nd Factor (U2F)
|
||||
================================================================
|
||||
|
||||
image:https://travis-ci.org/Yubico/pam-u2f.svg?branch=master["Build Status", link="https://travis-ci.org/Yubico/pam-u2f"]
|
||||
image:https://scan.coverity.com/projects/5711/badge.svg["Coverity Status", link=https://scan.coverity.com/projects/5711]
|
||||
|
||||
This module implements PAM over U2F, providing an easy way to integrate the
|
||||
YubiKey (or other U2F compliant authenticators) into your existing
|
||||
infrastructure.
|
||||
|
||||
[[building]]
|
||||
Building
|
||||
--------
|
||||
|
||||
This project uses 'autoconf', 'automake', 'pkg-config' and 'libtool'
|
||||
to achieve portability and ease of use.
|
||||
|
||||
In addition, both the Yubico U2F https://developers.yubico.com/libu2f-host['libu2f-host-dev'] and
|
||||
https://developers.yubico.com/libu2f-server['libu2f-server-dev'] libaries are needed.
|
||||
|
||||
Debian: apt-get install autoconf automake libtool pkg-config libu2f-host-dev libu2f-server-dev --no-install-recommends
|
||||
|
||||
If you downloaded a tarball, build it as follows.
|
||||
|
||||
-----------
|
||||
$ ./configure
|
||||
$ make
|
||||
-----------
|
||||
|
||||
Building from Git
|
||||
-----------------
|
||||
|
||||
You may check out the sources using Git with the following command:
|
||||
|
||||
-----------
|
||||
$ git clone git://github.com/Yubico/pam-u2f.git
|
||||
-----------
|
||||
|
||||
This will create a directory 'pam-u2f'. Enter the directory:
|
||||
|
||||
-----------
|
||||
$ cd pam-u2f
|
||||
-----------
|
||||
|
||||
'Autoconf', 'automake', 'libtool', and 'libpam' must be installed. 'AsciiDoc' and 'xsltproc' are used to
|
||||
generate the manpages.
|
||||
|
||||
Debian: apt-get install autoconf automake libtool libpam-dev libu2f-host-dev libu2f-server-dev asciidoc xsltproc libxml2-utils docbook-xml --no-install-recommends
|
||||
|
||||
Generate the build system using:
|
||||
|
||||
-----------
|
||||
$ autoreconf --install
|
||||
-----------
|
||||
|
||||
Then build as usual, see above under <<building,Building>>.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Once the module is built copy the file +pam_u2f.so+ to the correct
|
||||
directory for your system. Typically +/lib/security/+ or
|
||||
+/lib/x86_64-linux-gnu/security/+. This is automated by +make install+
|
||||
assuming that the pam directory chosen by +configure+ is correct.
|
||||
If that is not the case it can be specified with +./configure --with-pam-dir=+.
|
||||
|
||||
Create a file for a new service in +/etc/pam.d/+ or edit an already
|
||||
existing one by adding a line similar to this:
|
||||
|
||||
----
|
||||
auth sufficient pam_u2f.so debug
|
||||
----
|
||||
|
||||
Supported parameters for the module are:
|
||||
|
||||
[horizontal]
|
||||
debug::
|
||||
Enables debug output
|
||||
|
||||
debug_file::
|
||||
Filename to write debugging messages to. **If this file is missing, nothing will be logged**. This regular file **has to be created by the user**
|
||||
or **must exist and be a regular file** for anything getting logged to it. It is not created by pam-u2f on purpose (for security considerations).
|
||||
This filename may be alternatively set to "stderr" (default), "stdout", or "syslog".
|
||||
|
||||
origin=origin::
|
||||
Set the origin for the U2F authentication procedure.
|
||||
If no value is specified, the origin "pam://$HOSTNAME" is used.
|
||||
|
||||
appid=appid::
|
||||
Set the https://developers.yubico.com/U2F/App_ID.html[application ID] for the U2F authentication procedure.
|
||||
If no value is specified, the same value used for origin is taken
|
||||
("pam://$HOSTNAME" if also origin is not specified).
|
||||
|
||||
authfile=file::
|
||||
Set the location of the file that holds the mappings of user names
|
||||
to keyHandles and user keys. The format is
|
||||
+username:first_keyHandle,first_public_key:
|
||||
second_keyHandle,second_public_key:...+ the default location of the
|
||||
file is $XDG_CONFIG_HOME/Yubico/u2f_keys. If the environment variable
|
||||
is not set, $HOME/.config/Yubico/u2f_keys is used.
|
||||
(more on <<files,Authorization Mapping Files>>). An individual (per user) file
|
||||
may be configured, see <<individualAuth>>.
|
||||
|
||||
authpending_file=file::
|
||||
Set the location of the file that is used for touch request notifications.
|
||||
This file will be opened when pam-u2f starts waiting for a user to touch the device,
|
||||
and will be closed when it no longer waits for a touch.
|
||||
Use inotify to listen on these events, or a more high-level tool like https://github.com/maximbaz/yubikey-touch-detector[yubikey-touch-detector].
|
||||
Set an empty value in order to disable this functionality, like so: `authpending_file=`.
|
||||
Default value: /var/run/user/$UID/pam-u2f-authpending
|
||||
|
||||
nouserok::
|
||||
Set to enable authentication attempts to succeed even if the user trying to
|
||||
authenticate is not found inside authfile or if authfile is missing/malformed.
|
||||
|
||||
openasuser::
|
||||
Setuid to the authenticating user when opening the authfile. Useful when the
|
||||
user's home is stored on an NFS volume mounted with the root_squash option
|
||||
(which maps root to nobody which will not be able to read the file).
|
||||
Note that after release 1.0.8 this is done by default when no global
|
||||
authfile or XDG_CONFIG_HOME environment variable has been set.
|
||||
|
||||
alwaysok::
|
||||
Set to enable all authentication attempts to succeed (aka presentation mode).
|
||||
|
||||
max_devices=n_devices::
|
||||
Maximum number of devices allowed per user (default is 24). Devices specified
|
||||
in the authentication file that exceed this value will be ignored.
|
||||
|
||||
interactive::
|
||||
Set to prompt a message and wait before testing the presence of a U2F device.
|
||||
Recommended if your device doesn't have a tactile trigger.
|
||||
|
||||
[prompt=your prompt here]::
|
||||
Set individual prompt message for interactive mode. Watch the square brackets
|
||||
around this parameter to get spaces correctly recognized by PAM.
|
||||
|
||||
manual::
|
||||
Set to drop to a manual console where challenges are printed on screen
|
||||
and response read from standard input. Useful for debugging and SSH sessions
|
||||
without U2F-support from the SSH client/server.
|
||||
If enabled, interactive mode becomes redundant and has no effect.
|
||||
|
||||
cue::
|
||||
Set to prompt a message to remind to touch the device.
|
||||
|
||||
[cue_prompt=your prompt here]::
|
||||
Set individual prompt message for the cue option. Watch the square brackets
|
||||
around this parameter to get spaces correctly recognized by PAM.
|
||||
|
||||
nodetect::
|
||||
Set to skip detecting if a suitable U2F token is inserted before performing
|
||||
the full tactile authentication. This detection was created to avoid
|
||||
emitting the "cue" message if no suitable token exists, because doing so
|
||||
leaks information about the authentication stack if a token is inserted but
|
||||
not configured for the authenticating user. However, it was found that
|
||||
versions of libu2f-user 1.1.5 or less has buggy iteration/sleep behavior
|
||||
which causes a 1-second delay to occur for this initial detection. For this
|
||||
reason, as well as the possibility of hypothetical tokens that do not
|
||||
tolerate this double authentication, the "nodetect" option was added.
|
||||
|
||||
userpresence=int::
|
||||
If 1, request user presence during authentication. If 0, do not request user
|
||||
presence during authentication. Otherwise, fallback to the authenticator's
|
||||
default behaviour.
|
||||
|
||||
userverification=int::
|
||||
If 1, request user verification during authentication. If 0, do not request
|
||||
user verification during authentication. Otherwise, fallback to the
|
||||
authenticator's default behaviour.
|
||||
|
||||
pinverification=int::
|
||||
If 1, request PIN verification during authentication. If 0, do not request
|
||||
PIN verification during authentication. Otherwise, fallback to the
|
||||
authenticator's default behaviour.
|
||||
|
||||
[[files]]
|
||||
Authorization Mapping Files
|
||||
---------------------------
|
||||
A mapping must be made between the YubiKey token and the user name,
|
||||
see <<registration, here>> for details on how to perform the registration
|
||||
using the bundled tool.
|
||||
|
||||
There are two ways to do this, either centrally in one file, or
|
||||
individually, where users can create the mapping in their home directories.
|
||||
If the central authorization mapping file is being used, user home directory
|
||||
mappings will not be used and the opposite applies if user home directory
|
||||
mappings are being used, the central authorization mappings file will not
|
||||
be used.
|
||||
|
||||
By default the mapping file inside a home directory will be opened as
|
||||
the target user, whereas the central file will be opened as `root`. If
|
||||
the `XDG_CONFIG_HOME` variable is set, privileges will not be dropped
|
||||
unless the `openasuser` configuration setting is set.
|
||||
|
||||
IMPORTANT: Using pam-u2f to secure the login to a computer while
|
||||
storing the mapping file in an encrypted home directory, will result
|
||||
in the impossibility of logging into the system. The partition is
|
||||
decrypted after login and the mapping file can not be accessed.
|
||||
|
||||
== Central authorization mapping
|
||||
Create a file e.g. `/etc/u2f_mappings`., The file must contain
|
||||
a user name, the number of registered Yubikeys and the information
|
||||
obtained during the registration procedure.
|
||||
|
||||
The mappings should look like this, one per line:
|
||||
|
||||
<username1>:<KeyHandle1>,<UserKey1>:<KeyHandle2>,<UserKey2>:...
|
||||
<username2>:<KeyHandle1>,<UserKey1>:<KeyHandle2>,<UserKey2>:...
|
||||
|
||||
Now add `authfile=/etc/u2f_mappings` to your PAM configuration line, so it
|
||||
looks like:
|
||||
|
||||
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
|
||||
|
||||
If you do not set the `openasuser` setting, the authfile will be opened
|
||||
and parsed as `root` so make sure it has the correct owner and
|
||||
permissions set.
|
||||
|
||||
IMPORTANT: On dynamics networks (e.g. where hostnames are set by DHCP),
|
||||
users should not rely on the default origin and appid ("pam://$HOSTNAME")
|
||||
but set those parameters explicitly to the same value.
|
||||
|
||||
[[individualAuth]]
|
||||
== Individual authorization mapping by user
|
||||
Each user creates a `.config/Yubico/u2f_keys` (default) file inside their
|
||||
home directory and places the mapping in that file. You may want to specify
|
||||
a different per user file (relative to the users' home dir), i.e.
|
||||
`.ssh/u2f_keys`. Bear in mind, setting an absolute path here is possible although
|
||||
very likely a fragile setup, and probably not exhibiting the intended behaviour.
|
||||
|
||||
The file must have only one line:
|
||||
|
||||
<username>:<KeyHandle1>,<UserKey1>:<KeyHandle2>,<UserKey2>:...
|
||||
|
||||
This is much the same concept as the SSH authorized_keys file.
|
||||
|
||||
In this case, pam-u2f will drop privileges and read the mapping file
|
||||
as that user. This happens regardless of the `openasuser` option being
|
||||
set.
|
||||
|
||||
Note that if you set the XDG_CONFIG_HOME variable, privileges will not
|
||||
be dropped by default. Consider also setting `openasuser` in that case.
|
||||
|
||||
[[registration]]
|
||||
Obtaining key-handles and public keys
|
||||
-------------------------------------
|
||||
|
||||
In order to obtain the required information for the authentication procedure,
|
||||
a token should be first registered. This can be done by using the command line
|
||||
configuration tool provided with the module:
|
||||
|
||||
----
|
||||
$ pamu2fcfg -uusername -opam://myorigin -ipam://myappid
|
||||
----
|
||||
|
||||
the tool will register a connected token by using the specified origin and
|
||||
appid. If neither are specified they will default to +pam://$HOSTNAME+.
|
||||
During the U2F registration, the user is required to touch the token.
|
||||
On success the tool prints to standard output a configuration line that
|
||||
can be directly used with the module. For additional information on the
|
||||
tool read the relative manpage (+man pamu2fcfg+)
|
||||
|
||||
[[devices]]
|
||||
Multiple Devices
|
||||
----------------
|
||||
|
||||
Multiple devices are supported. If more than one device is specified,
|
||||
authentication against them is attempted sequentially as they are defined
|
||||
in the configuration file of the module. If during an authentication
|
||||
attempt a connected device is removed or a new device is plugged in,
|
||||
the authentication restarts from the top of the list.
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
main() {
|
||||
autoreconf --install
|
||||
}
|
||||
|
||||
pushd "$DIR" &>/dev/null
|
||||
main "$@"
|
||||
popd &>/dev/null
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2018 Yubico AB - See COPYING
|
||||
*/
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "b64.h"
|
||||
|
||||
int b64_encode(const void *ptr, size_t len, char **out) {
|
||||
BIO *bio_b64 = NULL;
|
||||
BIO *bio_mem = NULL;
|
||||
char *b64_ptr = NULL;
|
||||
long b64_len;
|
||||
int n;
|
||||
int ok = 0;
|
||||
|
||||
if (ptr == NULL || out == NULL || len > INT_MAX)
|
||||
return (0);
|
||||
|
||||
*out = NULL;
|
||||
|
||||
bio_b64 = BIO_new(BIO_f_base64());
|
||||
if (bio_b64 == NULL)
|
||||
goto fail;
|
||||
|
||||
bio_mem = BIO_new(BIO_s_mem());
|
||||
if (bio_mem == NULL)
|
||||
goto fail;
|
||||
|
||||
BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
BIO_push(bio_b64, bio_mem);
|
||||
|
||||
n = BIO_write(bio_b64, ptr, (int) len);
|
||||
if (n < 0 || (size_t) n != len)
|
||||
goto fail;
|
||||
|
||||
if (BIO_flush(bio_b64) < 0)
|
||||
goto fail;
|
||||
|
||||
b64_len = BIO_get_mem_data(bio_b64, &b64_ptr);
|
||||
if (b64_len < 0 || (size_t) b64_len == SIZE_MAX || b64_ptr == NULL)
|
||||
goto fail;
|
||||
|
||||
*out = calloc(1, (size_t) b64_len + 1);
|
||||
if (*out == NULL)
|
||||
goto fail;
|
||||
|
||||
memcpy(*out, b64_ptr, (size_t) b64_len);
|
||||
ok = 1;
|
||||
|
||||
fail:
|
||||
BIO_free(bio_b64);
|
||||
BIO_free(bio_mem);
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
int b64_decode(const char *in, void **ptr, size_t *len) {
|
||||
BIO *bio_mem = NULL;
|
||||
BIO *bio_b64 = NULL;
|
||||
size_t alloc_len;
|
||||
int n;
|
||||
int ok = 0;
|
||||
|
||||
if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX)
|
||||
return (0);
|
||||
|
||||
*ptr = NULL;
|
||||
*len = 0;
|
||||
|
||||
bio_b64 = BIO_new(BIO_f_base64());
|
||||
if (bio_b64 == NULL)
|
||||
goto fail;
|
||||
|
||||
bio_mem = BIO_new_mem_buf((void *) in, -1);
|
||||
if (bio_mem == NULL)
|
||||
goto fail;
|
||||
|
||||
BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
BIO_push(bio_b64, bio_mem);
|
||||
|
||||
alloc_len = strlen(in);
|
||||
*ptr = calloc(1, alloc_len);
|
||||
if (*ptr == NULL)
|
||||
goto fail;
|
||||
|
||||
n = BIO_read(bio_b64, *ptr, (int) alloc_len);
|
||||
if (n < 0 || BIO_eof(bio_b64) == 0)
|
||||
goto fail;
|
||||
|
||||
*len = (size_t) n;
|
||||
ok = 1;
|
||||
|
||||
fail:
|
||||
BIO_free(bio_b64);
|
||||
BIO_free(bio_mem);
|
||||
|
||||
if (!ok) {
|
||||
free(*ptr);
|
||||
*ptr = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
|
||||
return (ok);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright (C) 2018 Yubico AB - See COPYING
|
||||
*/
|
||||
|
||||
#ifndef B64_H
|
||||
#define B64_H
|
||||
|
||||
int b64_encode(const void *, size_t, char **);
|
||||
int b64_decode(const char *, void **, size_t *);
|
||||
|
||||
#endif /* B64_H */
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
set +x
|
||||
source $BUILDROOT/build-aux/ci/format-code.sh "$(git rev-parse HEAD~)"
|
||||
set -x
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
pushd "$BUILDROOT" &>/dev/null
|
||||
./autogen.sh
|
||||
./configure --disable-silent-rules --disable-man
|
||||
make check
|
||||
popd &>/dev/null
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
pushd "/tmp" &>/dev/null
|
||||
# Build and install libcbor
|
||||
git clone git://github.com/pjk/libcbor
|
||||
pushd "/tmp/libcbor" &>/dev/null
|
||||
git checkout v0.5.0
|
||||
cmake -Bbuild -H.
|
||||
cmake --build build -- --jobs=2 VERBOSE=1
|
||||
sudo make -C build install
|
||||
popd &>/dev/null
|
||||
|
||||
# Build and install libfido2
|
||||
export PKG_CONFIG_PATH=/usr/local/opt/openssl@1.1/lib/pkgconfig
|
||||
git clone git://github.com/Yubico/libfido2
|
||||
pushd "/tmp/libfido2" &>/dev/null
|
||||
cmake -Bbuild -H.
|
||||
cmake --build build -- --jobs=2 VERBOSE=1
|
||||
sudo make -C build install
|
||||
popd &>/dev/null
|
||||
popd &>/dev/null
|
||||
|
||||
pushd "$BUILDROOT" &>/dev/null
|
||||
./autogen.sh
|
||||
./configure --disable-silent-rules --disable-man
|
||||
make
|
||||
popd &>/dev/null
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-osx.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-osx.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
BUILDROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source $BUILDROOT/build-aux/ci/build-linux.sh
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Inspired by https://github.com/antiagainst/SPIRV-Tools/commit/c4f1bf8ddf7764b7c11fed1ce18ceb1d36b2eaf6
|
||||
#
|
||||
# Script to determine if source code in a diff is properly formatted.
|
||||
# On Travis it uses the commit range of the PR or push, otherwise it uses a provided range
|
||||
# Exits with non 0 exit code if formatting is needed.
|
||||
#
|
||||
# This script assumes to be invoked at the project root directory.
|
||||
|
||||
COMMIT_RANGE="${TRAVIS_COMMIT_RANGE:-$1}"
|
||||
|
||||
if [ -z "${COMMIT_RANGE}" ]; then
|
||||
>&2 echo "Empty commit range, missing parameter"
|
||||
return 0
|
||||
fi
|
||||
|
||||
>&2 echo "Commit range $COMMIT_RANGE"
|
||||
|
||||
FILES_TO_CHECK="$(git diff --name-only "$COMMIT_RANGE" | grep -e '\.c$' -e '\.h$' || true)"
|
||||
CFV="${CLANG_FORMAT_VERSION:--6.0}"
|
||||
|
||||
if [ -z "${FILES_TO_CHECK}" ]; then
|
||||
>&2 echo "No source code to check for formatting"
|
||||
return 0
|
||||
fi
|
||||
|
||||
FORMAT_DIFF=$(git diff -U0 ${COMMIT_RANGE} -- ${FILES_TO_CHECK} | clang-format-diff$CFV -p1)
|
||||
|
||||
if [ -z "${FORMAT_DIFF}" ]; then
|
||||
>&2 echo "All source code in the diff is properly formatted"
|
||||
return 0
|
||||
else
|
||||
>&2 echo -e "Found formatting errors\n"
|
||||
echo "${FORMAT_DIFF}"
|
||||
>&2 echo -e "\nYou can save the diff above and apply it with 'git apply -p0 my_diff'"
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,114 @@
|
|||
# Copyright (C) 2014-2019 Yubico AB
|
||||
AC_PREREQ([2.65])
|
||||
AC_INIT([pam_u2f], [1.0.9], [https://github.com/Yubico/pam-u2f/issues],
|
||||
[pam_u2f], [https://developers.yubico.com/pam-u2f/])
|
||||
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
AM_INIT_AUTOMAKE([1.11 foreign subdir-objects])
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AM_PROG_CC_C_O
|
||||
AM_PROG_AR
|
||||
AC_LIBTOOL_WIN32_DLL
|
||||
AC_DISABLE_STATIC
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_CC_STDC
|
||||
|
||||
AC_ARG_ENABLE([man],
|
||||
[AS_HELP_STRING([--disable-man], [Disable man page generation])],
|
||||
[:],
|
||||
[enable_man=yes]
|
||||
)
|
||||
AS_IF([test "$enable_man" = "yes"],
|
||||
[AM_MISSING_PROG([A2X], a2x, $missing_dir)]
|
||||
)
|
||||
AM_CONDITIONAL([ENABLE_MAN], [test "$enable_man" = "yes"])
|
||||
|
||||
|
||||
AC_CHECK_HEADERS([security/pam_appl.h], [],
|
||||
[AC_MSG_ERROR([[PAM header files not found, install libpam-dev.]])])
|
||||
AC_CHECK_HEADERS([security/pam_modules.h security/_pam_macros.h security/pam_modutil.h], [], [],
|
||||
[#include <sys/types.h>
|
||||
#include <security/pam_appl.h>])
|
||||
AC_CHECK_LIB([pam], [pam_start])
|
||||
|
||||
AC_SEARCH_LIBS([pam_modutil_drop_priv], ["pam"], [AC_DEFINE([HAVE_PAM_MODUTIL_DROP_PRIV], [1])])
|
||||
|
||||
case "$host" in
|
||||
*darwin*) PAMDIR="/usr/lib/pam";;
|
||||
*linux*) PAMDIR="/lib/x86_64-linux-gnu/security";;
|
||||
*) PAMDIR="/usr/lib"
|
||||
esac
|
||||
AC_ARG_WITH(pam-dir,
|
||||
AC_HELP_STRING([--with-pam-dir=DIR], [Where to install the PAM module]), [
|
||||
case "${withval}" in
|
||||
/*) PAMDIR="${withval}";;
|
||||
./*|../*) AC_MSG_ERROR(Bad value for --with-pam-dir);;
|
||||
*);;
|
||||
esac
|
||||
])
|
||||
AC_SUBST(PAMDIR, "$PAMDIR")
|
||||
|
||||
|
||||
PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto], [], [])
|
||||
PKG_CHECK_MODULES([LIBFIDO2], [libfido2 >= 1.2.0], [], [])
|
||||
|
||||
|
||||
# Check for secure_getenv, readpassphrase, explicit_bzero, and memset_s
|
||||
am_save_CFLAGS="$CFLAGS"
|
||||
am_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS"
|
||||
LIBS="$LIBS"
|
||||
AC_CHECK_FUNCS([secure_getenv readpassphrase explicit_bzero memset_s])
|
||||
CFLAGS=$am_save_CFLAGS
|
||||
LIBS=$am_save_LIBS
|
||||
|
||||
|
||||
AC_ARG_VAR([CWFLAGS], [Warning flags])
|
||||
AX_CHECK_COMPILE_FLAG([-Wall], [CWFLAGS="-Wall"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wextra], [CWFLAGS="$CWFLAGS -Wextra"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wconversion], [CWFLAGS="$CWFLAGS -Wconversion"])
|
||||
# Because pam headers are doing sign-conversion, see PAM_MODUTIL_DEF_PRIVS in pam_modutil.h
|
||||
AX_CHECK_COMPILE_FLAG([-Wconversion], [CWFLAGS="$CWFLAGS -Wno-sign-conversion"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wpedantic], [CWFLAGS="$CWFLAGS -Wpedantic"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wformat=2], [CWFLAGS="$CWFLAGS -Wformat=2"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wstrict-prototypes], [CWFLAGS="$CWFLAGS -Wstrict-prototypes"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wmissing-declarations], [CWFLAGS="$CWFLAGS -Wmissing-declarations"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wmissing-prototypes], [CWFLAGS="$CWFLAGS -Wmissing-prototypes"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CWFLAGS="$CWFLAGS -Wnull-dereference"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wshadow], [CWFLAGS="$CWFLAGS -Wshadow"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wpointer-arith], [CWFLAGS="$CWFLAGS -Wpointer-arith"])
|
||||
|
||||
AC_ARG_VAR([CSFLAGS], [Warning suppression flags])
|
||||
AX_CHECK_COMPILE_FLAG([-Wno-unused-but-set-variable], [CSFLAGS="-Wno-unused-but-set-variable"])
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
pamu2fcfg/Makefile
|
||||
tests/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
AC_MSG_NOTICE([Summary of build options:
|
||||
|
||||
Version: ${VERSION}
|
||||
Host type: ${host}
|
||||
Install prefix: ${prefix}
|
||||
Compiler: ${CC}
|
||||
CFLAGS: ${CFLAGS}
|
||||
CWFLAGS: ${CWFLAGS}
|
||||
CSFLAGS: ${CSFLAGS}
|
||||
Library types: Shared=${enable_shared}, Static=${enable_static}
|
||||
LIBFIDO2 CFLAGS: $LIBFIDO2_CFLAGS
|
||||
LIBFIDO2 LIBS: $LIBFIDO2_LIBS
|
||||
LIBCRYPTO CFLAGS: $LIBCRYPTO_CFLAGS
|
||||
LIBCRYPTO LIBS: $LIBCRYPTO_LIBS
|
||||
PAMDIR: $PAMDIR
|
||||
])
|
|
@ -0,0 +1,131 @@
|
|||
/* Written by Ricky Zhou <ricky@fedoraproject.org>
|
||||
* Fredrik Thulin <fredrik@yubico.com> implemented pam_modutil_drop_priv
|
||||
*
|
||||
* Copyright (c) 2011-2014 Yubico AB
|
||||
* Copyright (c) 2011 Ricky Zhou <ricky@fedoraproject.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_PAM_MODUTIL_DROP_PRIV
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "drop_privs.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_SECURITY_PAM_APPL_H
|
||||
#include <security/pam_appl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SECURITY_PAM_MODULES_H
|
||||
#include <security/pam_modules.h>
|
||||
#endif
|
||||
|
||||
int pam_modutil_drop_priv(pam_handle_t *pamh, struct _ykpam_privs *privs,
|
||||
struct passwd *pw) {
|
||||
privs->saved_euid = geteuid();
|
||||
privs->saved_egid = getegid();
|
||||
|
||||
if ((privs->saved_euid == pw->pw_uid) && (privs->saved_egid == pw->pw_gid)) {
|
||||
D(privs->debug_file, "Privilges already dropped, pretend it is all right");
|
||||
return 0;
|
||||
}
|
||||
|
||||
privs->saved_groups_length = getgroups(0, NULL);
|
||||
if (privs->saved_groups_length < 0) {
|
||||
D(privs->debug_file, "getgroups: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privs->saved_groups_length > SAVED_GROUPS_MAX_LEN) {
|
||||
D(privs->debug_file, "too many groups, limiting.");
|
||||
privs->saved_groups_length = SAVED_GROUPS_MAX_LEN;
|
||||
}
|
||||
|
||||
if (privs->saved_groups_length > 0) {
|
||||
if (getgroups(privs->saved_groups_length, privs->saved_groups) < 0) {
|
||||
D(privs->debug_file, "getgroups: %s", strerror(errno));
|
||||
goto free_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
|
||||
D(privs->debug_file, "initgroups: %s", strerror(errno));
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
if (setegid(pw->pw_gid) < 0) {
|
||||
D(privs->debug_file, "setegid: %s", strerror(errno));
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
if (seteuid(pw->pw_uid) < 0) {
|
||||
D(privs->debug_file, "seteuid: %s", strerror(errno));
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
free_out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pam_modutil_regain_priv(pam_handle_t *pamh, struct _ykpam_privs *privs) {
|
||||
if ((privs->saved_euid == geteuid()) && (privs->saved_egid == getegid())) {
|
||||
D(privs->debug_file,
|
||||
"Privilges already as requested, pretend it is all right");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seteuid(privs->saved_euid) < 0) {
|
||||
D(privs->debug_file, "seteuid: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setegid(privs->saved_egid) < 0) {
|
||||
D(privs->debug_file, "setegid: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setgroups(privs->saved_groups_length, privs->saved_groups) < 0) {
|
||||
D(privs->debug_file, "setgroups: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// drop_privs.c:124: warning: ISO C forbids an empty translation unit
|
||||
// [-Wpedantic]
|
||||
typedef int make_iso_compilers_happy;
|
||||
|
||||
#endif // HAVE_PAM_MODUTIL_DROP_PRIV
|
|
@ -0,0 +1,66 @@
|
|||
/* Copyright (c) 2011-2014 Yubico AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __PAM_U2F_DROP_PRIVS_H_INCLUDED__
|
||||
#define __PAM_U2F_DROP_PRIVS_H_INCLUDED__
|
||||
|
||||
#ifdef HAVE_PAM_MODUTIL_DROP_PRIV
|
||||
#include <security/pam_modutil.h>
|
||||
#else
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_SECURITY_PAM_APPL_H
|
||||
#include <security/pam_appl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SECURITY_PAM_MODULES_H
|
||||
#include <security/pam_modules.h>
|
||||
#endif
|
||||
|
||||
#define SAVED_GROUPS_MAX_LEN 64 /* as pam_modutil.. */
|
||||
|
||||
struct _ykpam_privs {
|
||||
uid_t saved_euid;
|
||||
gid_t saved_egid;
|
||||
gid_t *saved_groups;
|
||||
int saved_groups_length;
|
||||
FILE *debug_file;
|
||||
};
|
||||
|
||||
#define PAM_MODUTIL_DEF_PRIVS(n) \
|
||||
gid_t n##_saved_groups[SAVED_GROUPS_MAX_LEN]; \
|
||||
struct _ykpam_privs n = {-1, -1, n##_saved_groups, SAVED_GROUPS_MAX_LEN, \
|
||||
cfg->debug_file}
|
||||
|
||||
int pam_modutil_drop_priv(pam_handle_t *, struct _ykpam_privs *,
|
||||
struct passwd *);
|
||||
int pam_modutil_regain_priv(pam_handle_t *, struct _ykpam_privs *);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
/* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */
|
||||
/* $OpenBSD: explicit_bzero.c,v 1.1 2014/01/22 21:06:45 tedu Exp $ */
|
||||
/*
|
||||
* Public domain.
|
||||
* Written by Ted Unangst
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* explicit_bzero - don't let the compiler optimize away bzero
|
||||
*/
|
||||
|
||||
#ifndef HAVE_EXPLICIT_BZERO
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_MEMSET_S
|
||||
|
||||
void explicit_bzero(void *p, size_t n) {
|
||||
if (n == 0)
|
||||
return;
|
||||
(void) memset_s(p, n, 0, n);
|
||||
}
|
||||
|
||||
#else /* HAVE_MEMSET_S */
|
||||
|
||||
/*
|
||||
* Indirect bzero through a volatile pointer to hopefully avoid
|
||||
* dead-store optimisation eliminating the call.
|
||||
*/
|
||||
static void (*volatile ssh_bzero)(void *, size_t) = bzero;
|
||||
|
||||
void explicit_bzero(void *p, size_t n) {
|
||||
if (n == 0)
|
||||
return;
|
||||
/*
|
||||
* clang -fsanitize=memory needs to intercept memset-like functions
|
||||
* to correctly detect memory initialisation. Make sure one is called
|
||||
* directly since our indirection trick above successfully confuses it.
|
||||
*/
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(memory_sanitizer)
|
||||
memset(p, 0, n);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ssh_bzero(p, n);
|
||||
}
|
||||
|
||||
#endif /* HAVE_MEMSET_S */
|
||||
|
||||
#endif /* HAVE_EXPLICIT_BZERO */
|
|
@ -0,0 +1,73 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the given FLAG works with the current language's compiler
|
||||
# or gives an error. (Warnings, however, are ignored)
|
||||
#
|
||||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
|
||||
# success/failure.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the current language's default
|
||||
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
|
||||
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
|
||||
# force the compiler to issue an error when a bad flag is given.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
|
||||
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# This program 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 4
|
||||
|
||||
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
|
||||
AC_TRY_LINK([#include <stdio.h>],
|
||||
[char x[42U], fodder = 0;if (fodder > -1000 && fgets(x,1000,stdin)) puts(x)],
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
])dnl AX_CHECK_COMPILE_FLAGS
|
|
@ -0,0 +1,110 @@
|
|||
# lib-ld.m4 serial 4 (gettext-0.18)
|
||||
dnl Copyright (C) 1996-2003, 2009 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl Subroutines of libtool.m4,
|
||||
dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
|
||||
dnl with libtool.m4.
|
||||
|
||||
dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
|
||||
AC_DEFUN([AC_LIB_PROG_LD_GNU],
|
||||
[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld],
|
||||
[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
|
||||
case `$LD -v 2>&1 </dev/null` in
|
||||
*GNU* | *'with BFD'*)
|
||||
acl_cv_prog_gnu_ld=yes ;;
|
||||
*)
|
||||
acl_cv_prog_gnu_ld=no ;;
|
||||
esac])
|
||||
with_gnu_ld=$acl_cv_prog_gnu_ld
|
||||
])
|
||||
|
||||
dnl From libtool-1.4. Sets the variable LD.
|
||||
AC_DEFUN([AC_LIB_PROG_LD],
|
||||
[AC_ARG_WITH([gnu-ld],
|
||||
[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
|
||||
test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
|
||||
AC_REQUIRE([AC_PROG_CC])dnl
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
# Prepare PATH_SEPARATOR.
|
||||
# The user is always right.
|
||||
if test "${PATH_SEPARATOR+set}" != set; then
|
||||
echo "#! /bin/sh" >conf$$.sh
|
||||
echo "exit 0" >>conf$$.sh
|
||||
chmod +x conf$$.sh
|
||||
if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
|
||||
PATH_SEPARATOR=';'
|
||||
else
|
||||
PATH_SEPARATOR=:
|
||||
fi
|
||||
rm -f conf$$.sh
|
||||
fi
|
||||
ac_prog=ld
|
||||
if test "$GCC" = yes; then
|
||||
# Check if gcc -print-prog-name=ld gives a path.
|
||||
AC_MSG_CHECKING([for ld used by GCC])
|
||||
case $host in
|
||||
*-*-mingw*)
|
||||
# gcc leaves a trailing carriage return which upsets mingw
|
||||
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
|
||||
*)
|
||||
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
|
||||
esac
|
||||
case $ac_prog in
|
||||
# Accept absolute paths.
|
||||
[[\\/]* | [A-Za-z]:[\\/]*)]
|
||||
[re_direlt='/[^/][^/]*/\.\./']
|
||||
# Canonicalize the path of ld
|
||||
ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
|
||||
while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
|
||||
ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
|
||||
done
|
||||
test -z "$LD" && LD="$ac_prog"
|
||||
;;
|
||||
"")
|
||||
# If it fails, then pretend we aren't using GCC.
|
||||
ac_prog=ld
|
||||
;;
|
||||
*)
|
||||
# If it is relative, then search for the first ld in PATH.
|
||||
with_gnu_ld=unknown
|
||||
;;
|
||||
esac
|
||||
elif test "$with_gnu_ld" = yes; then
|
||||
AC_MSG_CHECKING([for GNU ld])
|
||||
else
|
||||
AC_MSG_CHECKING([for non-GNU ld])
|
||||
fi
|
||||
AC_CACHE_VAL([acl_cv_path_LD],
|
||||
[if test -z "$LD"; then
|
||||
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
|
||||
for ac_dir in $PATH; do
|
||||
test -z "$ac_dir" && ac_dir=.
|
||||
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
|
||||
acl_cv_path_LD="$ac_dir/$ac_prog"
|
||||
# Check to see if the program is GNU ld. I'd rather use --version,
|
||||
# but apparently some GNU ld's only accept -v.
|
||||
# Break only if it was the GNU/non-GNU ld that we prefer.
|
||||
case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
|
||||
*GNU* | *'with BFD'*)
|
||||
test "$with_gnu_ld" != no && break ;;
|
||||
*)
|
||||
test "$with_gnu_ld" != yes && break ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
IFS="$ac_save_ifs"
|
||||
else
|
||||
acl_cv_path_LD="$LD" # Let the user override the test with a path.
|
||||
fi])
|
||||
LD="$acl_cv_path_LD"
|
||||
if test -n "$LD"; then
|
||||
AC_MSG_RESULT([$LD])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
|
||||
AC_LIB_PROG_LD_GNU
|
||||
])
|
|
@ -0,0 +1,758 @@
|
|||
# lib-link.m4 serial 18 (gettext-0.18)
|
||||
dnl Copyright (C) 2001-2009 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl From Bruno Haible.
|
||||
|
||||
AC_PREREQ([2.54])
|
||||
|
||||
dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
|
||||
dnl the libraries corresponding to explicit and implicit dependencies.
|
||||
dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
|
||||
dnl augments the CPPFLAGS variable.
|
||||
dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
|
||||
dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
|
||||
AC_DEFUN([AC_LIB_LINKFLAGS],
|
||||
[
|
||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
|
||||
AC_REQUIRE([AC_LIB_RPATH])
|
||||
pushdef([Name],[translit([$1],[./-], [___])])
|
||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
|
||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
|
||||
AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
|
||||
AC_LIB_LINKFLAGS_BODY([$1], [$2])
|
||||
ac_cv_lib[]Name[]_libs="$LIB[]NAME"
|
||||
ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
|
||||
ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
|
||||
ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX"
|
||||
])
|
||||
LIB[]NAME="$ac_cv_lib[]Name[]_libs"
|
||||
LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
|
||||
INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
|
||||
LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix"
|
||||
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
|
||||
AC_SUBST([LIB]NAME)
|
||||
AC_SUBST([LTLIB]NAME)
|
||||
AC_SUBST([LIB]NAME[_PREFIX])
|
||||
dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
|
||||
dnl results of this search when this library appears as a dependency.
|
||||
HAVE_LIB[]NAME=yes
|
||||
popdef([NAME])
|
||||
popdef([Name])
|
||||
])
|
||||
|
||||
dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
|
||||
dnl searches for libname and the libraries corresponding to explicit and
|
||||
dnl implicit dependencies, together with the specified include files and
|
||||
dnl the ability to compile and link the specified testcode. If found, it
|
||||
dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
|
||||
dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
|
||||
dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
|
||||
dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
|
||||
dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
|
||||
dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
|
||||
AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
|
||||
[
|
||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
|
||||
AC_REQUIRE([AC_LIB_RPATH])
|
||||
pushdef([Name],[translit([$1],[./-], [___])])
|
||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
|
||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
|
||||
|
||||
dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
|
||||
dnl accordingly.
|
||||
AC_LIB_LINKFLAGS_BODY([$1], [$2])
|
||||
|
||||
dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
|
||||
dnl because if the user has installed lib[]Name and not disabled its use
|
||||
dnl via --without-lib[]Name-prefix, he wants to use it.
|
||||
ac_save_CPPFLAGS="$CPPFLAGS"
|
||||
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
|
||||
|
||||
AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $LIB[]NAME"
|
||||
AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
|
||||
LIBS="$ac_save_LIBS"
|
||||
])
|
||||
if test "$ac_cv_lib[]Name" = yes; then
|
||||
HAVE_LIB[]NAME=yes
|
||||
AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
|
||||
AC_MSG_CHECKING([how to link with lib[]$1])
|
||||
AC_MSG_RESULT([$LIB[]NAME])
|
||||
else
|
||||
HAVE_LIB[]NAME=no
|
||||
dnl If $LIB[]NAME didn't lead to a usable library, we don't need
|
||||
dnl $INC[]NAME either.
|
||||
CPPFLAGS="$ac_save_CPPFLAGS"
|
||||
LIB[]NAME=
|
||||
LTLIB[]NAME=
|
||||
LIB[]NAME[]_PREFIX=
|
||||
fi
|
||||
AC_SUBST([HAVE_LIB]NAME)
|
||||
AC_SUBST([LIB]NAME)
|
||||
AC_SUBST([LTLIB]NAME)
|
||||
AC_SUBST([LIB]NAME[_PREFIX])
|
||||
popdef([NAME])
|
||||
popdef([Name])
|
||||
])
|
||||
|
||||
dnl Determine the platform dependent parameters needed to use rpath:
|
||||
dnl acl_libext,
|
||||
dnl acl_shlibext,
|
||||
dnl acl_hardcode_libdir_flag_spec,
|
||||
dnl acl_hardcode_libdir_separator,
|
||||
dnl acl_hardcode_direct,
|
||||
dnl acl_hardcode_minus_L.
|
||||
AC_DEFUN([AC_LIB_RPATH],
|
||||
[
|
||||
dnl Tell automake >= 1.10 to complain if config.rpath is missing.
|
||||
m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
|
||||
AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
|
||||
AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
|
||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
|
||||
AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
|
||||
AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [
|
||||
CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
|
||||
${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
|
||||
. ./conftest.sh
|
||||
rm -f ./conftest.sh
|
||||
acl_cv_rpath=done
|
||||
])
|
||||
wl="$acl_cv_wl"
|
||||
acl_libext="$acl_cv_libext"
|
||||
acl_shlibext="$acl_cv_shlibext"
|
||||
acl_libname_spec="$acl_cv_libname_spec"
|
||||
acl_library_names_spec="$acl_cv_library_names_spec"
|
||||
acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
|
||||
acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
|
||||
acl_hardcode_direct="$acl_cv_hardcode_direct"
|
||||
acl_hardcode_minus_L="$acl_cv_hardcode_minus_L"
|
||||
dnl Determine whether the user wants rpath handling at all.
|
||||
AC_ARG_ENABLE([rpath],
|
||||
[ --disable-rpath do not hardcode runtime library paths],
|
||||
:, enable_rpath=yes)
|
||||
])
|
||||
|
||||
dnl AC_LIB_FROMPACKAGE(name, package)
|
||||
dnl declares that libname comes from the given package. The configure file
|
||||
dnl will then not have a --with-libname-prefix option but a
|
||||
dnl --with-package-prefix option. Several libraries can come from the same
|
||||
dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar
|
||||
dnl macro call that searches for libname.
|
||||
AC_DEFUN([AC_LIB_FROMPACKAGE],
|
||||
[
|
||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
|
||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
|
||||
define([acl_frompackage_]NAME, [$2])
|
||||
popdef([NAME])
|
||||
pushdef([PACK],[$2])
|
||||
pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-],
|
||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
|
||||
define([acl_libsinpackage_]PACKUP,
|
||||
m4_ifdef([acl_libsinpackage_]PACKUP, [acl_libsinpackage_]PACKUP[[, ]],)[lib$1])
|
||||
popdef([PACKUP])
|
||||
popdef([PACK])
|
||||
])
|
||||
|
||||
dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
|
||||
dnl the libraries corresponding to explicit and implicit dependencies.
|
||||
dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
|
||||
dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found
|
||||
dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
|
||||
AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
|
||||
[
|
||||
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
|
||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
|
||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
|
||||
pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])])
|
||||
pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-],
|
||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
|
||||
pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])])
|
||||
dnl Autoconf >= 2.61 supports dots in --with options.
|
||||
pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit(PACK,[.],[_])],PACK)])
|
||||
dnl By default, look in $includedir and $libdir.
|
||||
use_additional=yes
|
||||
AC_LIB_WITH_FINAL_PREFIX([
|
||||
eval additional_includedir=\"$includedir\"
|
||||
eval additional_libdir=\"$libdir\"
|
||||
])
|
||||
AC_ARG_WITH(P_A_C_K[-prefix],
|
||||
[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib
|
||||
--without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]],
|
||||
[
|
||||
if test "X$withval" = "Xno"; then
|
||||
use_additional=no
|
||||
else
|
||||
if test "X$withval" = "X"; then
|
||||
AC_LIB_WITH_FINAL_PREFIX([
|
||||
eval additional_includedir=\"$includedir\"
|
||||
eval additional_libdir=\"$libdir\"
|
||||
])
|
||||
else
|
||||
additional_includedir="$withval/include"
|
||||
additional_libdir="$withval/$acl_libdirstem"
|
||||
if test "$acl_libdirstem2" != "$acl_libdirstem" \
|
||||
&& ! test -d "$withval/$acl_libdirstem"; then
|
||||
additional_libdir="$withval/$acl_libdirstem2"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
])
|
||||
dnl Search the library and its dependencies in $additional_libdir and
|
||||
dnl $LDFLAGS. Using breadth-first-seach.
|
||||
LIB[]NAME=
|
||||
LTLIB[]NAME=
|
||||
INC[]NAME=
|
||||
LIB[]NAME[]_PREFIX=
|
||||
rpathdirs=
|
||||
ltrpathdirs=
|
||||
names_already_handled=
|
||||
names_next_round='$1 $2'
|
||||
while test -n "$names_next_round"; do
|
||||
names_this_round="$names_next_round"
|
||||
names_next_round=
|
||||
for name in $names_this_round; do
|
||||
already_handled=
|
||||
for n in $names_already_handled; do
|
||||
if test "$n" = "$name"; then
|
||||
already_handled=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$already_handled"; then
|
||||
names_already_handled="$names_already_handled $name"
|
||||
dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
|
||||
dnl or AC_LIB_HAVE_LINKFLAGS call.
|
||||
uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
|
||||
eval value=\"\$HAVE_LIB$uppername\"
|
||||
if test -n "$value"; then
|
||||
if test "$value" = yes; then
|
||||
eval value=\"\$LIB$uppername\"
|
||||
test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
|
||||
eval value=\"\$LTLIB$uppername\"
|
||||
test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
|
||||
else
|
||||
dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
|
||||
dnl that this library doesn't exist. So just drop it.
|
||||
:
|
||||
fi
|
||||
else
|
||||
dnl Search the library lib$name in $additional_libdir and $LDFLAGS
|
||||
dnl and the already constructed $LIBNAME/$LTLIBNAME.
|
||||
found_dir=
|
||||
found_la=
|
||||
found_so=
|
||||
found_a=
|
||||
eval libname=\"$acl_libname_spec\" # typically: libname=lib$name
|
||||
if test -n "$acl_shlibext"; then
|
||||
shrext=".$acl_shlibext" # typically: shrext=.so
|
||||
else
|
||||
shrext=
|
||||
fi
|
||||
if test $use_additional = yes; then
|
||||
dir="$additional_libdir"
|
||||
dnl The same code as in the loop below:
|
||||
dnl First look for a shared library.
|
||||
if test -n "$acl_shlibext"; then
|
||||
if test -f "$dir/$libname$shrext"; then
|
||||
found_dir="$dir"
|
||||
found_so="$dir/$libname$shrext"
|
||||
else
|
||||
if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
|
||||
ver=`(cd "$dir" && \
|
||||
for f in "$libname$shrext".*; do echo "$f"; done \
|
||||
| sed -e "s,^$libname$shrext\\\\.,," \
|
||||
| sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
|
||||
| sed 1q ) 2>/dev/null`
|
||||
if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
|
||||
found_dir="$dir"
|
||||
found_so="$dir/$libname$shrext.$ver"
|
||||
fi
|
||||
else
|
||||
eval library_names=\"$acl_library_names_spec\"
|
||||
for f in $library_names; do
|
||||
if test -f "$dir/$f"; then
|
||||
found_dir="$dir"
|
||||
found_so="$dir/$f"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
dnl Then look for a static library.
|
||||
if test "X$found_dir" = "X"; then
|
||||
if test -f "$dir/$libname.$acl_libext"; then
|
||||
found_dir="$dir"
|
||||
found_a="$dir/$libname.$acl_libext"
|
||||
fi
|
||||
fi
|
||||
if test "X$found_dir" != "X"; then
|
||||
if test -f "$dir/$libname.la"; then
|
||||
found_la="$dir/$libname.la"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test "X$found_dir" = "X"; then
|
||||
for x in $LDFLAGS $LTLIB[]NAME; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
case "$x" in
|
||||
-L*)
|
||||
dir=`echo "X$x" | sed -e 's/^X-L//'`
|
||||
dnl First look for a shared library.
|
||||
if test -n "$acl_shlibext"; then
|
||||
if test -f "$dir/$libname$shrext"; then
|
||||
found_dir="$dir"
|
||||
found_so="$dir/$libname$shrext"
|
||||
else
|
||||
if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
|
||||
ver=`(cd "$dir" && \
|
||||
for f in "$libname$shrext".*; do echo "$f"; done \
|
||||
| sed -e "s,^$libname$shrext\\\\.,," \
|
||||
| sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
|
||||
| sed 1q ) 2>/dev/null`
|
||||
if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
|
||||
found_dir="$dir"
|
||||
found_so="$dir/$libname$shrext.$ver"
|
||||
fi
|
||||
else
|
||||
eval library_names=\"$acl_library_names_spec\"
|
||||
for f in $library_names; do
|
||||
if test -f "$dir/$f"; then
|
||||
found_dir="$dir"
|
||||
found_so="$dir/$f"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
dnl Then look for a static library.
|
||||
if test "X$found_dir" = "X"; then
|
||||
if test -f "$dir/$libname.$acl_libext"; then
|
||||
found_dir="$dir"
|
||||
found_a="$dir/$libname.$acl_libext"
|
||||
fi
|
||||
fi
|
||||
if test "X$found_dir" != "X"; then
|
||||
if test -f "$dir/$libname.la"; then
|
||||
found_la="$dir/$libname.la"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if test "X$found_dir" != "X"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test "X$found_dir" != "X"; then
|
||||
dnl Found the library.
|
||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
|
||||
if test "X$found_so" != "X"; then
|
||||
dnl Linking with a shared library. We attempt to hardcode its
|
||||
dnl directory into the executable's runpath, unless it's the
|
||||
dnl standard /usr/lib.
|
||||
if test "$enable_rpath" = no \
|
||||
|| test "X$found_dir" = "X/usr/$acl_libdirstem" \
|
||||
|| test "X$found_dir" = "X/usr/$acl_libdirstem2"; then
|
||||
dnl No hardcoding is needed.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
|
||||
else
|
||||
dnl Use an explicit option to hardcode DIR into the resulting
|
||||
dnl binary.
|
||||
dnl Potentially add DIR to ltrpathdirs.
|
||||
dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
|
||||
haveit=
|
||||
for x in $ltrpathdirs; do
|
||||
if test "X$x" = "X$found_dir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
ltrpathdirs="$ltrpathdirs $found_dir"
|
||||
fi
|
||||
dnl The hardcoding into $LIBNAME is system dependent.
|
||||
if test "$acl_hardcode_direct" = yes; then
|
||||
dnl Using DIR/libNAME.so during linking hardcodes DIR into the
|
||||
dnl resulting binary.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
|
||||
else
|
||||
if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
|
||||
dnl Use an explicit option to hardcode DIR into the resulting
|
||||
dnl binary.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
|
||||
dnl Potentially add DIR to rpathdirs.
|
||||
dnl The rpathdirs will be appended to $LIBNAME at the end.
|
||||
haveit=
|
||||
for x in $rpathdirs; do
|
||||
if test "X$x" = "X$found_dir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
rpathdirs="$rpathdirs $found_dir"
|
||||
fi
|
||||
else
|
||||
dnl Rely on "-L$found_dir".
|
||||
dnl But don't add it if it's already contained in the LDFLAGS
|
||||
dnl or the already constructed $LIBNAME
|
||||
haveit=
|
||||
for x in $LDFLAGS $LIB[]NAME; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
if test "X$x" = "X-L$found_dir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
|
||||
fi
|
||||
if test "$acl_hardcode_minus_L" != no; then
|
||||
dnl FIXME: Not sure whether we should use
|
||||
dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
|
||||
dnl here.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
|
||||
else
|
||||
dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH
|
||||
dnl here, because this doesn't fit in flags passed to the
|
||||
dnl compiler. So give up. No hardcoding. This affects only
|
||||
dnl very old systems.
|
||||
dnl FIXME: Not sure whether we should use
|
||||
dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
|
||||
dnl here.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test "X$found_a" != "X"; then
|
||||
dnl Linking with a static library.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
|
||||
else
|
||||
dnl We shouldn't come here, but anyway it's good to have a
|
||||
dnl fallback.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
|
||||
fi
|
||||
fi
|
||||
dnl Assume the include files are nearby.
|
||||
additional_includedir=
|
||||
case "$found_dir" in
|
||||
*/$acl_libdirstem | */$acl_libdirstem/)
|
||||
basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
|
||||
if test "$name" = '$1'; then
|
||||
LIB[]NAME[]_PREFIX="$basedir"
|
||||
fi
|
||||
additional_includedir="$basedir/include"
|
||||
;;
|
||||
*/$acl_libdirstem2 | */$acl_libdirstem2/)
|
||||
basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'`
|
||||
if test "$name" = '$1'; then
|
||||
LIB[]NAME[]_PREFIX="$basedir"
|
||||
fi
|
||||
additional_includedir="$basedir/include"
|
||||
;;
|
||||
esac
|
||||
if test "X$additional_includedir" != "X"; then
|
||||
dnl Potentially add $additional_includedir to $INCNAME.
|
||||
dnl But don't add it
|
||||
dnl 1. if it's the standard /usr/include,
|
||||
dnl 2. if it's /usr/local/include and we are using GCC on Linux,
|
||||
dnl 3. if it's already present in $CPPFLAGS or the already
|
||||
dnl constructed $INCNAME,
|
||||
dnl 4. if it doesn't exist as a directory.
|
||||
if test "X$additional_includedir" != "X/usr/include"; then
|
||||
haveit=
|
||||
if test "X$additional_includedir" = "X/usr/local/include"; then
|
||||
if test -n "$GCC"; then
|
||||
case $host_os in
|
||||
linux* | gnu* | k*bsd*-gnu) haveit=yes;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if test -z "$haveit"; then
|
||||
for x in $CPPFLAGS $INC[]NAME; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
if test "X$x" = "X-I$additional_includedir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
if test -d "$additional_includedir"; then
|
||||
dnl Really add $additional_includedir to $INCNAME.
|
||||
INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
dnl Look for dependencies.
|
||||
if test -n "$found_la"; then
|
||||
dnl Read the .la file. It defines the variables
|
||||
dnl dlname, library_names, old_library, dependency_libs, current,
|
||||
dnl age, revision, installed, dlopen, dlpreopen, libdir.
|
||||
save_libdir="$libdir"
|
||||
case "$found_la" in
|
||||
*/* | *\\*) . "$found_la" ;;
|
||||
*) . "./$found_la" ;;
|
||||
esac
|
||||
libdir="$save_libdir"
|
||||
dnl We use only dependency_libs.
|
||||
for dep in $dependency_libs; do
|
||||
case "$dep" in
|
||||
-L*)
|
||||
additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
|
||||
dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
|
||||
dnl But don't add it
|
||||
dnl 1. if it's the standard /usr/lib,
|
||||
dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
|
||||
dnl 3. if it's already present in $LDFLAGS or the already
|
||||
dnl constructed $LIBNAME,
|
||||
dnl 4. if it doesn't exist as a directory.
|
||||
if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \
|
||||
&& test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then
|
||||
haveit=
|
||||
if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \
|
||||
|| test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then
|
||||
if test -n "$GCC"; then
|
||||
case $host_os in
|
||||
linux* | gnu* | k*bsd*-gnu) haveit=yes;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if test -z "$haveit"; then
|
||||
haveit=
|
||||
for x in $LDFLAGS $LIB[]NAME; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
if test "X$x" = "X-L$additional_libdir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
if test -d "$additional_libdir"; then
|
||||
dnl Really add $additional_libdir to $LIBNAME.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
|
||||
fi
|
||||
fi
|
||||
haveit=
|
||||
for x in $LDFLAGS $LTLIB[]NAME; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
if test "X$x" = "X-L$additional_libdir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
if test -d "$additional_libdir"; then
|
||||
dnl Really add $additional_libdir to $LTLIBNAME.
|
||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
-R*)
|
||||
dir=`echo "X$dep" | sed -e 's/^X-R//'`
|
||||
if test "$enable_rpath" != no; then
|
||||
dnl Potentially add DIR to rpathdirs.
|
||||
dnl The rpathdirs will be appended to $LIBNAME at the end.
|
||||
haveit=
|
||||
for x in $rpathdirs; do
|
||||
if test "X$x" = "X$dir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
rpathdirs="$rpathdirs $dir"
|
||||
fi
|
||||
dnl Potentially add DIR to ltrpathdirs.
|
||||
dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
|
||||
haveit=
|
||||
for x in $ltrpathdirs; do
|
||||
if test "X$x" = "X$dir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
ltrpathdirs="$ltrpathdirs $dir"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
-l*)
|
||||
dnl Handle this in the next round.
|
||||
names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
|
||||
;;
|
||||
*.la)
|
||||
dnl Handle this in the next round. Throw away the .la's
|
||||
dnl directory; it is already contained in a preceding -L
|
||||
dnl option.
|
||||
names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
|
||||
;;
|
||||
*)
|
||||
dnl Most likely an immediate library name.
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
|
||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
else
|
||||
dnl Didn't find the library; assume it is in the system directories
|
||||
dnl known to the linker and runtime loader. (All the system
|
||||
dnl directories known to the linker should also be known to the
|
||||
dnl runtime loader, otherwise the system is severely misconfigured.)
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
|
||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
if test "X$rpathdirs" != "X"; then
|
||||
if test -n "$acl_hardcode_libdir_separator"; then
|
||||
dnl Weird platform: only the last -rpath option counts, the user must
|
||||
dnl pass all path elements in one option. We can arrange that for a
|
||||
dnl single library, but not when more than one $LIBNAMEs are used.
|
||||
alldirs=
|
||||
for found_dir in $rpathdirs; do
|
||||
alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir"
|
||||
done
|
||||
dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl.
|
||||
acl_save_libdir="$libdir"
|
||||
libdir="$alldirs"
|
||||
eval flag=\"$acl_hardcode_libdir_flag_spec\"
|
||||
libdir="$acl_save_libdir"
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
|
||||
else
|
||||
dnl The -rpath options are cumulative.
|
||||
for found_dir in $rpathdirs; do
|
||||
acl_save_libdir="$libdir"
|
||||
libdir="$found_dir"
|
||||
eval flag=\"$acl_hardcode_libdir_flag_spec\"
|
||||
libdir="$acl_save_libdir"
|
||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
if test "X$ltrpathdirs" != "X"; then
|
||||
dnl When using libtool, the option that works for both libraries and
|
||||
dnl executables is -R. The -R options are cumulative.
|
||||
for found_dir in $ltrpathdirs; do
|
||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
|
||||
done
|
||||
fi
|
||||
popdef([P_A_C_K])
|
||||
popdef([PACKLIBS])
|
||||
popdef([PACKUP])
|
||||
popdef([PACK])
|
||||
popdef([NAME])
|
||||
])
|
||||
|
||||
dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
|
||||
dnl unless already present in VAR.
|
||||
dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
|
||||
dnl contains two or three consecutive elements that belong together.
|
||||
AC_DEFUN([AC_LIB_APPENDTOVAR],
|
||||
[
|
||||
for element in [$2]; do
|
||||
haveit=
|
||||
for x in $[$1]; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
if test "X$x" = "X$element"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
[$1]="${[$1]}${[$1]:+ }$element"
|
||||
fi
|
||||
done
|
||||
])
|
||||
|
||||
dnl For those cases where a variable contains several -L and -l options
|
||||
dnl referring to unknown libraries and directories, this macro determines the
|
||||
dnl necessary additional linker options for the runtime path.
|
||||
dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL])
|
||||
dnl sets LDADDVAR to linker options needed together with LIBSVALUE.
|
||||
dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed,
|
||||
dnl otherwise linking without libtool is assumed.
|
||||
AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
|
||||
[
|
||||
AC_REQUIRE([AC_LIB_RPATH])
|
||||
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
|
||||
$1=
|
||||
if test "$enable_rpath" != no; then
|
||||
if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
|
||||
dnl Use an explicit option to hardcode directories into the resulting
|
||||
dnl binary.
|
||||
rpathdirs=
|
||||
next=
|
||||
for opt in $2; do
|
||||
if test -n "$next"; then
|
||||
dir="$next"
|
||||
dnl No need to hardcode the standard /usr/lib.
|
||||
if test "X$dir" != "X/usr/$acl_libdirstem" \
|
||||
&& test "X$dir" != "X/usr/$acl_libdirstem2"; then
|
||||
rpathdirs="$rpathdirs $dir"
|
||||
fi
|
||||
next=
|
||||
else
|
||||
case $opt in
|
||||
-L) next=yes ;;
|
||||
-L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
|
||||
dnl No need to hardcode the standard /usr/lib.
|
||||
if test "X$dir" != "X/usr/$acl_libdirstem" \
|
||||
&& test "X$dir" != "X/usr/$acl_libdirstem2"; then
|
||||
rpathdirs="$rpathdirs $dir"
|
||||
fi
|
||||
next= ;;
|
||||
*) next= ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
if test "X$rpathdirs" != "X"; then
|
||||
if test -n ""$3""; then
|
||||
dnl libtool is used for linking. Use -R options.
|
||||
for dir in $rpathdirs; do
|
||||
$1="${$1}${$1:+ }-R$dir"
|
||||
done
|
||||
else
|
||||
dnl The linker is used for linking directly.
|
||||
if test -n "$acl_hardcode_libdir_separator"; then
|
||||
dnl Weird platform: only the last -rpath option counts, the user
|
||||
dnl must pass all path elements in one option.
|
||||
alldirs=
|
||||
for dir in $rpathdirs; do
|
||||
alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir"
|
||||
done
|
||||
acl_save_libdir="$libdir"
|
||||
libdir="$alldirs"
|
||||
eval flag=\"$acl_hardcode_libdir_flag_spec\"
|
||||
libdir="$acl_save_libdir"
|
||||
$1="$flag"
|
||||
else
|
||||
dnl The -rpath options are cumulative.
|
||||
for dir in $rpathdirs; do
|
||||
acl_save_libdir="$libdir"
|
||||
libdir="$dir"
|
||||
eval flag=\"$acl_hardcode_libdir_flag_spec\"
|
||||
libdir="$acl_save_libdir"
|
||||
$1="${$1}${$1:+ }$flag"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([$1])
|
||||
])
|
|
@ -0,0 +1,221 @@
|
|||
# lib-prefix.m4 serial 6 (gettext-0.18)
|
||||
dnl Copyright (C) 2001-2005, 2008 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl From Bruno Haible.
|
||||
|
||||
dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
|
||||
dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
|
||||
dnl require excessive bracketing.
|
||||
ifdef([AC_HELP_STRING],
|
||||
[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
|
||||
[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
|
||||
|
||||
dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
|
||||
dnl to access previously installed libraries. The basic assumption is that
|
||||
dnl a user will want packages to use other packages he previously installed
|
||||
dnl with the same --prefix option.
|
||||
dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
|
||||
dnl libraries, but is otherwise very convenient.
|
||||
AC_DEFUN([AC_LIB_PREFIX],
|
||||
[
|
||||
AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
|
||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
|
||||
dnl By default, look in $includedir and $libdir.
|
||||
use_additional=yes
|
||||
AC_LIB_WITH_FINAL_PREFIX([
|
||||
eval additional_includedir=\"$includedir\"
|
||||
eval additional_libdir=\"$libdir\"
|
||||
])
|
||||
AC_LIB_ARG_WITH([lib-prefix],
|
||||
[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
|
||||
--without-lib-prefix don't search for libraries in includedir and libdir],
|
||||
[
|
||||
if test "X$withval" = "Xno"; then
|
||||
use_additional=no
|
||||
else
|
||||
if test "X$withval" = "X"; then
|
||||
AC_LIB_WITH_FINAL_PREFIX([
|
||||
eval additional_includedir=\"$includedir\"
|
||||
eval additional_libdir=\"$libdir\"
|
||||
])
|
||||
else
|
||||
additional_includedir="$withval/include"
|
||||
additional_libdir="$withval/$acl_libdirstem"
|
||||
fi
|
||||
fi
|
||||
])
|
||||
if test $use_additional = yes; then
|
||||
dnl Potentially add $additional_includedir to $CPPFLAGS.
|
||||
dnl But don't add it
|
||||
dnl 1. if it's the standard /usr/include,
|
||||
dnl 2. if it's already present in $CPPFLAGS,
|
||||
dnl 3. if it's /usr/local/include and we are using GCC on Linux,
|
||||
dnl 4. if it doesn't exist as a directory.
|
||||
if test "X$additional_includedir" != "X/usr/include"; then
|
||||
haveit=
|
||||
for x in $CPPFLAGS; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
if test "X$x" = "X-I$additional_includedir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
if test "X$additional_includedir" = "X/usr/local/include"; then
|
||||
if test -n "$GCC"; then
|
||||
case $host_os in
|
||||
linux* | gnu* | k*bsd*-gnu) haveit=yes;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if test -z "$haveit"; then
|
||||
if test -d "$additional_includedir"; then
|
||||
dnl Really add $additional_includedir to $CPPFLAGS.
|
||||
CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
dnl Potentially add $additional_libdir to $LDFLAGS.
|
||||
dnl But don't add it
|
||||
dnl 1. if it's the standard /usr/lib,
|
||||
dnl 2. if it's already present in $LDFLAGS,
|
||||
dnl 3. if it's /usr/local/lib and we are using GCC on Linux,
|
||||
dnl 4. if it doesn't exist as a directory.
|
||||
if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
|
||||
haveit=
|
||||
for x in $LDFLAGS; do
|
||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
|
||||
if test "X$x" = "X-L$additional_libdir"; then
|
||||
haveit=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$haveit"; then
|
||||
if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
|
||||
if test -n "$GCC"; then
|
||||
case $host_os in
|
||||
linux*) haveit=yes;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if test -z "$haveit"; then
|
||||
if test -d "$additional_libdir"; then
|
||||
dnl Really add $additional_libdir to $LDFLAGS.
|
||||
LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
|
||||
dnl acl_final_exec_prefix, containing the values to which $prefix and
|
||||
dnl $exec_prefix will expand at the end of the configure script.
|
||||
AC_DEFUN([AC_LIB_PREPARE_PREFIX],
|
||||
[
|
||||
dnl Unfortunately, prefix and exec_prefix get only finally determined
|
||||
dnl at the end of configure.
|
||||
if test "X$prefix" = "XNONE"; then
|
||||
acl_final_prefix="$ac_default_prefix"
|
||||
else
|
||||
acl_final_prefix="$prefix"
|
||||
fi
|
||||
if test "X$exec_prefix" = "XNONE"; then
|
||||
acl_final_exec_prefix='${prefix}'
|
||||
else
|
||||
acl_final_exec_prefix="$exec_prefix"
|
||||
fi
|
||||
acl_save_prefix="$prefix"
|
||||
prefix="$acl_final_prefix"
|
||||
eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
|
||||
prefix="$acl_save_prefix"
|
||||
])
|
||||
|
||||
dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
|
||||
dnl variables prefix and exec_prefix bound to the values they will have
|
||||
dnl at the end of the configure script.
|
||||
AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
|
||||
[
|
||||
acl_save_prefix="$prefix"
|
||||
prefix="$acl_final_prefix"
|
||||
acl_save_exec_prefix="$exec_prefix"
|
||||
exec_prefix="$acl_final_exec_prefix"
|
||||
$1
|
||||
exec_prefix="$acl_save_exec_prefix"
|
||||
prefix="$acl_save_prefix"
|
||||
])
|
||||
|
||||
dnl AC_LIB_PREPARE_MULTILIB creates
|
||||
dnl - a variable acl_libdirstem, containing the basename of the libdir, either
|
||||
dnl "lib" or "lib64" or "lib/64",
|
||||
dnl - a variable acl_libdirstem2, as a secondary possible value for
|
||||
dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or
|
||||
dnl "lib/amd64".
|
||||
AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
|
||||
[
|
||||
dnl There is no formal standard regarding lib and lib64.
|
||||
dnl On glibc systems, the current practice is that on a system supporting
|
||||
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
|
||||
dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine
|
||||
dnl the compiler's default mode by looking at the compiler's library search
|
||||
dnl path. If at least one of its elements ends in /lib64 or points to a
|
||||
dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI.
|
||||
dnl Otherwise we use the default, namely "lib".
|
||||
dnl On Solaris systems, the current practice is that on a system supporting
|
||||
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
|
||||
dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or
|
||||
dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib.
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
acl_libdirstem=lib
|
||||
acl_libdirstem2=
|
||||
case "$host_os" in
|
||||
solaris*)
|
||||
dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
|
||||
dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>.
|
||||
dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
|
||||
dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
|
||||
dnl symlink is missing, so we set acl_libdirstem2 too.
|
||||
AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit],
|
||||
[AC_EGREP_CPP([sixtyfour bits], [
|
||||
#ifdef _LP64
|
||||
sixtyfour bits
|
||||
#endif
|
||||
], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no])
|
||||
])
|
||||
if test $gl_cv_solaris_64bit = yes; then
|
||||
acl_libdirstem=lib/64
|
||||
case "$host_cpu" in
|
||||
sparc*) acl_libdirstem2=lib/sparcv9 ;;
|
||||
i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
|
||||
if test -n "$searchpath"; then
|
||||
acl_save_IFS="${IFS= }"; IFS=":"
|
||||
for searchdir in $searchpath; do
|
||||
if test -d "$searchdir"; then
|
||||
case "$searchdir" in
|
||||
*/lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
|
||||
*) searchdir=`cd "$searchdir" && pwd`
|
||||
case "$searchdir" in
|
||||
*/lib64 ) acl_libdirstem=lib64 ;;
|
||||
esac ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
IFS="$acl_save_IFS"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
|
||||
])
|
|
@ -0,0 +1,142 @@
|
|||
PAM_U2F(8)
|
||||
==========
|
||||
:doctype: manpage
|
||||
:man source: pam-u2f
|
||||
:man manual: PAM U2F Module Manual
|
||||
|
||||
== NAME
|
||||
pam_u2f - Module for U2F authentication
|
||||
|
||||
== SYNOPSIS
|
||||
*pam_u2f* [...]
|
||||
|
||||
== DESCRIPTION
|
||||
The module provides U2F authentication against Yubikeys and other compliant authenticators.
|
||||
|
||||
== OPTIONS
|
||||
*debug*::
|
||||
Enables debug output
|
||||
|
||||
*debug_file*::
|
||||
Filename to write debugging messages to. *If this file is missing, nothing will be logged*. This regular file *has to be created by the user*
|
||||
or *must exist and be a regular file* for anything getting logged to it. It is not created by pam-u2f on purpose (for security considerations).
|
||||
This filename may be alternatively set to "stderr" (default), "stdout", or "syslog".
|
||||
|
||||
*origin*=_origin_::
|
||||
Set the origin for the U2F authentication procedure. If no value is specified, the origin "pam://$HOSTNAME" is used.
|
||||
|
||||
*appid*=_appid_::
|
||||
Set the application ID for the U2F authentication procedure. If no value is specified, the same value used for origin is taken ("pam://$HOSTNAME" if also origin is not specified).
|
||||
|
||||
*authfile*=_file_::
|
||||
Set the location of the file that holds the mappings of user names to keyHandles and user keys. The format is username:keyHandle1,public_key1:keyHandle2,public_key2:... the default location of the file is $XDG_CONFIG_HOME/Yubico/u2f_keys. If the environment variable is not set, $HOME/.config/Yubico/u2f_keys is used.
|
||||
An individual (per user) file may be configured relative to the users' home dirs, i.e. ".ssh/u2f_keys".
|
||||
|
||||
*authpending_file*=_file_::
|
||||
Set the location of the file that is used for touch request notifications. This file will be opened when pam-u2f starts waiting for a user to touch the device, and will be closed when it no longer waits for a touch. Use inotify to listen on these events, or a more high-level tool like yubikey-touch-detector. Default value: /var/run/user/$UID/pam-u2f-authpending. Set an empty value in order to disable this functionality, like so: "authpending_file=".
|
||||
|
||||
*nouserok*::
|
||||
Set to enable authentication attempts to succeed even if the user trying to authenticate is not found inside authfile or if authfile is missing/malformed.
|
||||
|
||||
*openasuser*::
|
||||
Setuid to the authenticating user when opening the authfile. Useful when the user's home is stored on an NFS volume mounted with the root_squash option (which maps root to nobody which will not be able to read the file).
|
||||
Note that after release 1.0.8 this is done by default when no global authfile or XDG_CONFIG_HOME environment variable has been set.
|
||||
|
||||
*alwaysok*::
|
||||
Set to enable all authentication attempts to succeed (aka presentation mode).
|
||||
|
||||
*max_devices*=_n_devices_::
|
||||
Maximum number of devices allowed per user (default is 24). Devices specified
|
||||
in the authentication file that exceed this value will be ignored.
|
||||
|
||||
*interactive*::
|
||||
Set to prompt a message and wait before testing the presence of a U2F device. Recommended if your device doesn't have tactile trigger.
|
||||
|
||||
*[prompt=your prompt here]*::
|
||||
Set individual prompt message for interactive mode. Watch the square brackets
|
||||
around this parameter to get spaces correctly recognized by PAM.
|
||||
|
||||
*manual*::
|
||||
Set to drop to a manual console where challenges are printed on screen and response read from standard input. Useful for debugging and SSH sessions without U2F-support from the SSH client/server. If enabled, interactive mode becomes redundant and has no effect.
|
||||
|
||||
*cue*::
|
||||
Set to prompt a message to remind to touch the device.
|
||||
|
||||
*[cue_prompt=your prompt here]*::
|
||||
Set individual prompt message for the cue option. Watch the square brackets
|
||||
around this parameter to get spaces correctly recognized by PAM.
|
||||
|
||||
*nodetect*::
|
||||
Skip detecting if a suitable key is inserted before performing a full authentication. See *NOTES* below.
|
||||
|
||||
*userpresence*=_int_::
|
||||
If 1, require user presence during authentication. If 0, do not request user
|
||||
presence during authentication. Otherwise, fallback to the authenticator's
|
||||
default behaviour.
|
||||
|
||||
*userverification*=_int_::
|
||||
If 1, require user verification during authentication. If 0, do not request
|
||||
user verification during authentication. Otherwise, fallback to the
|
||||
authenticator's default behaviour.
|
||||
|
||||
*pinverification*=_int_::
|
||||
If 1, require PIN verification during authentication. If 0, do not request
|
||||
PIN verification during authentication. Otherwise, fallback to the
|
||||
authenticator's default behaviour.
|
||||
|
||||
== EXAMPLES
|
||||
|
||||
auth sufficient pam_u2f.so debug origin=pam://$HOSTNAME appid=pam://$HOSTNAME
|
||||
|
||||
auth required pam_u2f.so origin=http://example.com appid=http://example.com authfile=/etc/yubikey_mappings
|
||||
|
||||
== CAVEATS
|
||||
By default the mapping file inside a home directory will be opened as
|
||||
the target user, whereas the central file will be opened as "root". If
|
||||
the "XDG_CONFIG_HOME" variable is set, privileges will not be dropped
|
||||
unless the "openasuser" configuration setting is set.
|
||||
|
||||
Using pam-u2f to secure the login to a computer while
|
||||
storing the mapping file in an encrypted home directory, will result
|
||||
in the impossibility of logging into the system. The partition is
|
||||
decrypted after login and the mapping file can not be accessed.
|
||||
|
||||
== NOTES
|
||||
The "nodetect" option should be used with caution. pam_u2f checks that a
|
||||
key configured for the user is inserted before performing the full tactile
|
||||
authentication. This detection is done by sending a "check-only"
|
||||
authentication request to all inserted tokens to so see if at least one of
|
||||
them responds affirmatively to one or more of the keyhandles configured for
|
||||
the user. By doing this, pam_u2f can avoid emitting the "cue" prompt (if
|
||||
configured), which can cause some confusing UI issues if the cue is emitted
|
||||
followed by the underlying library immediately failing the tactile
|
||||
authentication. This option is also useful to avoid an unintended 1-second
|
||||
delay prior to the tactile authentication caused by versions of libu2f-host
|
||||
\<= 1.1.5.
|
||||
|
||||
If pam_u2f is configured to "cue" and "nodetect", an attacker can determine
|
||||
that pam_u2f is part of the authentication stack by inserting any random
|
||||
U2F token and performing an authentication attempt. In this scenario, the
|
||||
attacker would see the cue message followed by an immediate failure,
|
||||
whereas with detection enabled, the U2F authentication will fail silently.
|
||||
Understand that an attacker could choose a U2F token that alerts him or
|
||||
her in some way to the "check-only" authentication attempt, so this
|
||||
precaution only pushes the issue back a step.
|
||||
|
||||
In summary, the detection feature was added to avoid confusing UI issues
|
||||
and to prevent leaking information about the authentication stack in very
|
||||
specific scenario when "cue" is configured. The "nodetect" option was added
|
||||
to avoid buggy sleep behavior in older versions of libu2f-host and for
|
||||
hypothetical tokens that do not tolerate the double authentication.
|
||||
Detection is performed, and likewise "nodetect" honored, regardless of
|
||||
whether "cue" is also specified.
|
||||
|
||||
== BUGS
|
||||
Report pam-u2f bugs in the issue tracker: https://github.com/Yubico/pam-u2f/issues
|
||||
|
||||
== SEE ALSO
|
||||
*pam*(7)
|
||||
|
||||
The pam-u2f home page: https://developers.yubico.com/pam-u2f/
|
||||
|
||||
YubiKeys can be obtained from Yubico: http://www.yubico.com/
|
|
@ -0,0 +1,60 @@
|
|||
PAMU2FCFG(1)
|
||||
============
|
||||
:doctype: manpage
|
||||
:man source: pamu2fcfg
|
||||
:man manual: PAM U2F Configuration Tool
|
||||
|
||||
== NAME
|
||||
pamu2fcfg - Configuration tool for the U2F PAM module.
|
||||
|
||||
== SYNOPSIS
|
||||
*pamu2fcfg* [_OPTION_]...
|
||||
|
||||
== DESCRIPTION
|
||||
Perform a U2F registration procedure using a connected U2F token and output a configuration line that can be used with the U2F PAM module.
|
||||
|
||||
== OPTIONS
|
||||
*-d*, *--debug*::
|
||||
Print debug information (highly verbose)
|
||||
|
||||
*-h*, *--help*::
|
||||
Print help and exit
|
||||
|
||||
*-o*, *--origin*=_STRING_::
|
||||
Origin URL to use during registration. Defaults to pam://hostname
|
||||
|
||||
*-i*, *--appid*=_STRING_::
|
||||
Application ID to use during registration. Defaults to *origin*
|
||||
|
||||
*-r*, *--resident*::
|
||||
Generate a resident credential. Defaults to off.
|
||||
|
||||
*-t*, *--type*=_STRING_::
|
||||
COSE type to use during registration (ES256 or RS256). Defaults to ES256.
|
||||
|
||||
*-N*, *--pin-verification*::
|
||||
Require PIN verification during authentication. Defaults to off.
|
||||
|
||||
*-V*, *--user-verification*::
|
||||
Require user verification during authentication. Defaults to off.
|
||||
|
||||
*--version*:
|
||||
*Print version and exit*
|
||||
|
||||
Group: user (mutually exclusive)
|
||||
|
||||
*-u*, *--username*=_STRING_::
|
||||
The name of the user registering the device. Defaults to the current user name
|
||||
|
||||
*-n*, *--nouser*::
|
||||
Print only registration information (keyHandle and public key). Useful for appending
|
||||
|
||||
== BUGS
|
||||
Report pamu2fcfg bugs in the issue tracker: https://github.com/Yubico/pam-u2f/issues
|
||||
|
||||
== SEE ALSO
|
||||
*pam_u2f*(8), *pam*(7)
|
||||
|
||||
The pam-u2f home page: https://developers.yubico.com/pam-u2f/
|
||||
|
||||
YubiKeys can be obtained from Yubico: https://www.yubico.com/
|
|
@ -0,0 +1,472 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2019 Yubico AB - See COPYING
|
||||
*/
|
||||
|
||||
/* Define which PAM interfaces we provide */
|
||||
#define PAM_SM_AUTH
|
||||
|
||||
/* Include PAM headers */
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_modules.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "drop_privs.h"
|
||||
|
||||
/* If secure_getenv is not defined, define it here */
|
||||
#ifndef HAVE_SECURE_GETENV
|
||||
char *secure_getenv(const char *);
|
||||
char *secure_getenv(const char *name) {
|
||||
(void) name;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void parse_cfg(int flags, int argc, const char **argv, cfg_t *cfg) {
|
||||
struct stat st;
|
||||
FILE *file = NULL;
|
||||
int fd = -1;
|
||||
int i;
|
||||
|
||||
memset(cfg, 0, sizeof(cfg_t));
|
||||
cfg->debug_file = stderr;
|
||||
cfg->userpresence = -1;
|
||||
cfg->userverification = -1;
|
||||
cfg->pinverification = -1;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (strncmp(argv[i], "max_devices=", 12) == 0)
|
||||
sscanf(argv[i], "max_devices=%u", &cfg->max_devs);
|
||||
if (strcmp(argv[i], "manual") == 0)
|
||||
cfg->manual = 1;
|
||||
if (strcmp(argv[i], "debug") == 0)
|
||||
cfg->debug = 1;
|
||||
if (strcmp(argv[i], "nouserok") == 0)
|
||||
cfg->nouserok = 1;
|
||||
if (strcmp(argv[i], "openasuser") == 0)
|
||||
cfg->openasuser = 1;
|
||||
if (strcmp(argv[i], "alwaysok") == 0)
|
||||
cfg->alwaysok = 1;
|
||||
if (strcmp(argv[i], "interactive") == 0)
|
||||
cfg->interactive = 1;
|
||||
if (strcmp(argv[i], "cue") == 0)
|
||||
cfg->cue = 1;
|
||||
if (strcmp(argv[i], "nodetect") == 0)
|
||||
cfg->nodetect = 1;
|
||||
if (strncmp(argv[i], "userpresence=", 13) == 0)
|
||||
sscanf(argv[i], "userpresence=%d", &cfg->userpresence);
|
||||
if (strncmp(argv[i], "userverification=", 17) == 0)
|
||||
sscanf(argv[i], "userverification=%d", &cfg->userverification);
|
||||
if (strncmp(argv[i], "pinverification=", 16) == 0)
|
||||
sscanf(argv[i], "pinverification=%d", &cfg->pinverification);
|
||||
if (strncmp(argv[i], "authfile=", 9) == 0)
|
||||
cfg->auth_file = argv[i] + 9;
|
||||
if (strncmp(argv[i], "authpending_file=", 17) == 0)
|
||||
cfg->authpending_file = argv[i] + 17;
|
||||
if (strncmp(argv[i], "origin=", 7) == 0)
|
||||
cfg->origin = argv[i] + 7;
|
||||
if (strncmp(argv[i], "appid=", 6) == 0)
|
||||
cfg->appid = argv[i] + 6;
|
||||
if (strncmp(argv[i], "prompt=", 7) == 0)
|
||||
cfg->prompt = argv[i] + 7;
|
||||
if (strncmp(argv[i], "cue_prompt=", 11) == 0)
|
||||
cfg->cue_prompt = argv[i] + 11;
|
||||
if (strncmp(argv[i], "debug_file=", 11) == 0) {
|
||||
const char *filename = argv[i] + 11;
|
||||
if (strncmp(filename, "stdout", 6) == 0) {
|
||||
cfg->debug_file = stdout;
|
||||
} else if (strncmp(filename, "stderr", 6) == 0) {
|
||||
cfg->debug_file = stderr;
|
||||
} else if (strncmp(filename, "syslog", 6) == 0) {
|
||||
cfg->debug_file = (FILE *) -1;
|
||||
} else {
|
||||
fd = open(filename,
|
||||
O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_NOCTTY);
|
||||
if (fd >= 0 && (fstat(fd, &st) == 0) && S_ISREG(st.st_mode)) {
|
||||
file = fdopen(fd, "a");
|
||||
if (file != NULL) {
|
||||
cfg->debug_file = file;
|
||||
cfg->is_custom_debug_file = 1;
|
||||
file = NULL;
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->debug) {
|
||||
D(cfg->debug_file, "called.");
|
||||
D(cfg->debug_file, "flags %d argc %d", flags, argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
D(cfg->debug_file, "argv[%d]=%s", i, argv[i]);
|
||||
}
|
||||
D(cfg->debug_file, "max_devices=%d", cfg->max_devs);
|
||||
D(cfg->debug_file, "debug=%d", cfg->debug);
|
||||
D(cfg->debug_file, "interactive=%d", cfg->interactive);
|
||||
D(cfg->debug_file, "cue=%d", cfg->cue);
|
||||
D(cfg->debug_file, "nodetect=%d", cfg->nodetect);
|
||||
D(cfg->debug_file, "userpresence=%d", cfg->userpresence);
|
||||
D(cfg->debug_file, "userverification=%d", cfg->userverification);
|
||||
D(cfg->debug_file, "pinverification=%d", cfg->pinverification);
|
||||
D(cfg->debug_file, "manual=%d", cfg->manual);
|
||||
D(cfg->debug_file, "nouserok=%d", cfg->nouserok);
|
||||
D(cfg->debug_file, "openasuser=%d", cfg->openasuser);
|
||||
D(cfg->debug_file, "alwaysok=%d", cfg->alwaysok);
|
||||
D(cfg->debug_file, "authfile=%s",
|
||||
cfg->auth_file ? cfg->auth_file : "(null)");
|
||||
D(cfg->debug_file, "authpending_file=%s",
|
||||
cfg->authpending_file ? cfg->authpending_file : "(null)");
|
||||
D(cfg->debug_file, "origin=%s", cfg->origin ? cfg->origin : "(null)");
|
||||
D(cfg->debug_file, "appid=%s", cfg->appid ? cfg->appid : "(null)");
|
||||
D(cfg->debug_file, "prompt=%s", cfg->prompt ? cfg->prompt : "(null)");
|
||||
}
|
||||
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
||||
if (file != NULL)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
#ifdef DBG
|
||||
#undef DBG
|
||||
#endif
|
||||
#define DBG(...) \
|
||||
if (cfg->debug) { \
|
||||
D(cfg->debug_file, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
/* PAM entry point for authentication verification */
|
||||
int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
|
||||
const char **argv) {
|
||||
|
||||
struct passwd *pw = NULL, pw_s;
|
||||
const char *user = NULL;
|
||||
|
||||
cfg_t cfg_st;
|
||||
cfg_t *cfg = &cfg_st;
|
||||
char buffer[BUFSIZE];
|
||||
char *buf = NULL;
|
||||
char *authfile_dir;
|
||||
size_t authfile_dir_len;
|
||||
int pgu_ret, gpn_ret;
|
||||
int retval = PAM_IGNORE;
|
||||
device_t *devices = NULL;
|
||||
unsigned n_devices = 0;
|
||||
int openasuser = 0;
|
||||
int should_free_origin = 0;
|
||||
int should_free_appid = 0;
|
||||
int should_free_auth_file = 0;
|
||||
int should_free_authpending_file = 0;
|
||||
PAM_MODUTIL_DEF_PRIVS(privs);
|
||||
|
||||
parse_cfg(flags, argc, argv, cfg);
|
||||
|
||||
if (!cfg->origin) {
|
||||
strcpy(buffer, DEFAULT_ORIGIN_PREFIX);
|
||||
|
||||
if (gethostname(buffer + strlen(DEFAULT_ORIGIN_PREFIX),
|
||||
BUFSIZE - strlen(DEFAULT_ORIGIN_PREFIX)) == -1) {
|
||||
DBG("Unable to get host name");
|
||||
goto done;
|
||||
}
|
||||
DBG("Origin not specified, using \"%s\"", buffer);
|
||||
cfg->origin = strdup(buffer);
|
||||
if (!cfg->origin) {
|
||||
DBG("Unable to allocate memory");
|
||||
goto done;
|
||||
} else {
|
||||
should_free_origin = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfg->appid) {
|
||||
DBG("Appid not specified, using the same value of origin (%s)",
|
||||
cfg->origin);
|
||||
cfg->appid = strdup(cfg->origin);
|
||||
if (!cfg->appid) {
|
||||
DBG("Unable to allocate memory")
|
||||
goto done;
|
||||
} else {
|
||||
should_free_appid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->max_devs == 0) {
|
||||
DBG("Maximum devices number not set. Using default (%d)", MAX_DEVS);
|
||||
cfg->max_devs = MAX_DEVS;
|
||||
}
|
||||
|
||||
devices = calloc(cfg->max_devs, sizeof(device_t));
|
||||
if (!devices) {
|
||||
DBG("Unable to allocate memory");
|
||||
retval = PAM_IGNORE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pgu_ret = pam_get_user(pamh, &user, NULL);
|
||||
if (pgu_ret != PAM_SUCCESS || user == NULL) {
|
||||
DBG("Unable to access user %s", user);
|
||||
retval = PAM_CONV_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
DBG("Requesting authentication for user %s", user);
|
||||
|
||||
gpn_ret = getpwnam_r(user, &pw_s, buffer, sizeof(buffer), &pw);
|
||||
if (gpn_ret != 0 || pw == NULL || pw->pw_dir == NULL ||
|
||||
pw->pw_dir[0] != '/') {
|
||||
DBG("Unable to retrieve credentials for user %s, (%s)", user,
|
||||
strerror(errno));
|
||||
retval = PAM_USER_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
DBG("Found user %s", user);
|
||||
DBG("Home directory for %s is %s", user, pw->pw_dir);
|
||||
|
||||
if (!cfg->auth_file) {
|
||||
buf = NULL;
|
||||
authfile_dir = secure_getenv(DEFAULT_AUTHFILE_DIR_VAR);
|
||||
if (!authfile_dir) {
|
||||
DBG("Variable %s is not set. Using default value ($HOME/.config/)",
|
||||
DEFAULT_AUTHFILE_DIR_VAR);
|
||||
authfile_dir_len =
|
||||
strlen(pw->pw_dir) + strlen("/.config") + strlen(DEFAULT_AUTHFILE) + 1;
|
||||
buf = malloc(sizeof(char) * (authfile_dir_len));
|
||||
|
||||
if (!buf) {
|
||||
DBG("Unable to allocate memory");
|
||||
retval = PAM_IGNORE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Opening a file in a users $HOME, need to drop privs for security */
|
||||
openasuser = geteuid() == 0 ? 1 : 0;
|
||||
|
||||
snprintf(buf, authfile_dir_len, "%s/.config%s", pw->pw_dir,
|
||||
DEFAULT_AUTHFILE);
|
||||
} else {
|
||||
DBG("Variable %s set to %s", DEFAULT_AUTHFILE_DIR_VAR, authfile_dir);
|
||||
authfile_dir_len = strlen(authfile_dir) + strlen(DEFAULT_AUTHFILE) + 1;
|
||||
buf = malloc(sizeof(char) * (authfile_dir_len));
|
||||
|
||||
if (!buf) {
|
||||
DBG("Unable to allocate memory");
|
||||
retval = PAM_IGNORE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
snprintf(buf, authfile_dir_len, "%s%s", authfile_dir, DEFAULT_AUTHFILE);
|
||||
|
||||
if (!cfg->openasuser) {
|
||||
DBG("WARNING: not dropping privileges when reading %s, please "
|
||||
"consider setting openasuser=1 in the module configuration",
|
||||
buf);
|
||||
}
|
||||
}
|
||||
|
||||
DBG("Using authentication file %s", buf);
|
||||
|
||||
cfg->auth_file = buf; /* cfg takes ownership */
|
||||
should_free_auth_file = 1;
|
||||
buf = NULL;
|
||||
} else {
|
||||
if (cfg->auth_file[0] != '/') {
|
||||
/* Individual authorization mapping by user: auth_file is not
|
||||
absolute path, so prepend user home dir. */
|
||||
openasuser = geteuid() == 0 ? 1 : 0;
|
||||
|
||||
authfile_dir_len =
|
||||
strlen(pw->pw_dir) + strlen("/") + strlen(cfg->auth_file) + 1;
|
||||
buf = malloc(sizeof(char) * (authfile_dir_len));
|
||||
|
||||
if (!buf) {
|
||||
DBG("Unable to allocate memory");
|
||||
retval = PAM_IGNORE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
snprintf(buf, authfile_dir_len, "%s/%s", pw->pw_dir, cfg->auth_file);
|
||||
|
||||
cfg->auth_file = buf; /* update cfg */
|
||||
should_free_auth_file = 1;
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
DBG("Using authentication file %s", cfg->auth_file);
|
||||
}
|
||||
|
||||
if (!openasuser) {
|
||||
openasuser = geteuid() == 0 && cfg->openasuser;
|
||||
}
|
||||
if (openasuser) {
|
||||
DBG("Dropping privileges");
|
||||
if (pam_modutil_drop_priv(pamh, &privs, pw)) {
|
||||
DBG("Unable to switch user to uid %i", pw->pw_uid);
|
||||
retval = PAM_IGNORE;
|
||||
goto done;
|
||||
}
|
||||
DBG("Switched to uid %i", pw->pw_uid);
|
||||
}
|
||||
retval =
|
||||
get_devices_from_authfile(cfg->auth_file, user, cfg->max_devs, cfg->debug,
|
||||
cfg->debug_file, devices, &n_devices);
|
||||
if (openasuser) {
|
||||
if (pam_modutil_regain_priv(pamh, &privs)) {
|
||||
DBG("could not restore privileges");
|
||||
retval = PAM_IGNORE;
|
||||
goto done;
|
||||
}
|
||||
DBG("Restored privileges");
|
||||
}
|
||||
|
||||
if (retval != 1) {
|
||||
// for nouserok; make sure errors in get_devices_from_authfile don't
|
||||
// result in valid devices
|
||||
n_devices = 0;
|
||||
}
|
||||
|
||||
if (n_devices == 0) {
|
||||
if (cfg->nouserok) {
|
||||
DBG("Found no devices but nouserok specified. Skipping authentication");
|
||||
retval = PAM_SUCCESS;
|
||||
goto done;
|
||||
} else if (retval != 1) {
|
||||
DBG("Unable to get devices from file %s", cfg->auth_file);
|
||||
retval = PAM_AUTHINFO_UNAVAIL;
|
||||
goto done;
|
||||
} else {
|
||||
DBG("Found no devices. Aborting.");
|
||||
retval = PAM_AUTHINFO_UNAVAIL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the full path for authpending_file in order to emit touch request
|
||||
// notifications
|
||||
if (!cfg->authpending_file) {
|
||||
int actual_size =
|
||||
snprintf(buffer, BUFSIZE, DEFAULT_AUTHPENDING_FILE_PATH, getuid());
|
||||
if (actual_size >= 0 && actual_size < BUFSIZE) {
|
||||
cfg->authpending_file = strdup(buffer);
|
||||
}
|
||||
if (!cfg->authpending_file) {
|
||||
DBG("Unable to allocate memory for the authpending_file, touch request "
|
||||
"notifications will not be emitted");
|
||||
} else {
|
||||
should_free_authpending_file = 1;
|
||||
}
|
||||
} else {
|
||||
if (strlen(cfg->authpending_file) == 0) {
|
||||
DBG("authpending_file is set to an empty value, touch request "
|
||||
"notifications will be disabled");
|
||||
cfg->authpending_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int authpending_file_descriptor = -1;
|
||||
if (cfg->authpending_file) {
|
||||
DBG("Using file '%s' for emitting touch request notifications",
|
||||
cfg->authpending_file);
|
||||
|
||||
// Open (or create) the authpending_file to indicate that we start waiting
|
||||
// for a touch
|
||||
authpending_file_descriptor =
|
||||
open(cfg->authpending_file,
|
||||
O_RDONLY | O_CREAT | O_CLOEXEC | O_NOFOLLOW | O_NOCTTY, 0664);
|
||||
if (authpending_file_descriptor < 0) {
|
||||
DBG("Unable to emit 'authentication started' notification by opening the "
|
||||
"file '%s', (%s)",
|
||||
cfg->authpending_file, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->manual == 0) {
|
||||
if (cfg->interactive) {
|
||||
converse(pamh, PAM_PROMPT_ECHO_ON,
|
||||
cfg->prompt != NULL ? cfg->prompt : DEFAULT_PROMPT);
|
||||
}
|
||||
|
||||
retval = do_authentication(cfg, devices, n_devices, pamh);
|
||||
} else {
|
||||
retval = do_manual_authentication(cfg, devices, n_devices, pamh);
|
||||
}
|
||||
|
||||
// Close the authpending_file to indicate that we stop waiting for a touch
|
||||
if (authpending_file_descriptor >= 0) {
|
||||
if (close(authpending_file_descriptor) < 0) {
|
||||
DBG("Unable to emit 'authentication stopped' notification by closing the "
|
||||
"file '%s', (%s)",
|
||||
cfg->authpending_file, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (retval != 1) {
|
||||
DBG("do_authentication returned %d", retval);
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
retval = PAM_SUCCESS;
|
||||
|
||||
done:
|
||||
free_devices(devices, n_devices);
|
||||
|
||||
if (buf) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
if (should_free_origin) {
|
||||
free((char *) cfg->origin);
|
||||
cfg->origin = NULL;
|
||||
}
|
||||
|
||||
if (should_free_appid) {
|
||||
free((char *) cfg->appid);
|
||||
cfg->appid = NULL;
|
||||
}
|
||||
|
||||
if (should_free_auth_file) {
|
||||
free((char *) cfg->auth_file);
|
||||
cfg->auth_file = NULL;
|
||||
}
|
||||
|
||||
if (should_free_authpending_file) {
|
||||
free((char *) cfg->authpending_file);
|
||||
cfg->authpending_file = NULL;
|
||||
}
|
||||
|
||||
if (cfg->alwaysok && retval != PAM_SUCCESS) {
|
||||
DBG("alwaysok needed (otherwise return with %d)", retval);
|
||||
retval = PAM_SUCCESS;
|
||||
}
|
||||
DBG("done. [%s]", pam_strerror(pamh, retval));
|
||||
|
||||
if (cfg->is_custom_debug_file) {
|
||||
fclose(cfg->debug_file);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
|
||||
const char **argv) {
|
||||
(void) pamh;
|
||||
(void) flags;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
return PAM_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright (C) 2014-2018 Yubico AB - See COPYING
|
||||
|
||||
AM_CFLAGS = $(WARN_CFLAGS)
|
||||
AM_CPPFLAGS=-I$(srcdir)/.. -I$(builddir)/.. $(LIBFIDO2_CFLAGS)
|
||||
|
||||
bin_PROGRAMS = pamu2fcfg
|
||||
|
||||
pamu2fcfg_SOURCES = pamu2fcfg.c
|
||||
pamu2fcfg_SOURCES += cmdline.ggo cmdline.c cmdline.h
|
||||
pamu2fcfg_SOURCES += readpassphrase.c readpassphrase.h
|
||||
pamu2fcfg_SOURCES += ../util.c ../b64.c ../explicit_bzero.c
|
||||
pamu2fcfg_LDADD = $(LIBFIDO2_LIBS) $(LIBCRYPTO_LIBS)
|
||||
|
||||
cmdline.c cmdline.h: cmdline.ggo Makefile.am
|
||||
gengetopt --no-handle-help --input $^
|
||||
|
||||
BUILT_SOURCES = cmdline.c cmdline.h
|
||||
MAINTAINERCLEANFILES = $(BUILT_SOURCES)
|
||||
|
||||
if ENABLE_MAN
|
||||
dist_man1_MANS = $(top_builddir)/man/pamu2fcfg.1
|
||||
DISTCLEANFILES = $(dist_man1_MANS)
|
||||
|
||||
MANSOURCES = $(top_builddir)/man/pamu2fcfg.1.txt
|
||||
EXTRA_DIST = $(MANSOURCES)
|
||||
|
||||
SUFFIXES = .1.txt .1
|
||||
|
||||
.1.txt.1:
|
||||
$(A2X) --format=manpage -L -a revdate="Version $(VERSION)" $<
|
||||
endif
|
|
@ -0,0 +1,42 @@
|
|||
/* $OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
/* OPENBSD ORIGINAL: include/readpassphrase.h */
|
||||
|
||||
#ifndef _READPASSPHRASE_H_
|
||||
#define _READPASSPHRASE_H_
|
||||
|
||||
#ifndef HAVE_READPASSPHRASE
|
||||
|
||||
#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */
|
||||
#define RPP_ECHO_ON 0x01 /* Leave echo on. */
|
||||
#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */
|
||||
#define RPP_FORCELOWER 0x04 /* Force input to lower case. */
|
||||
#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */
|
||||
#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */
|
||||
#define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */
|
||||
|
||||
char * readpassphrase(const char *, char *, size_t, int);
|
||||
|
||||
#endif /* HAVE_READPASSPHRASE */
|
||||
|
||||
#endif /* !_READPASSPHRASE_H_ */
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright (C) 2014-2018 Yubico AB - See COPYING
|
||||
#
|
||||
|
||||
purpose "Perform a U2F registration operation and print a configuration line that can be used with the pam_u2f module."
|
||||
|
||||
defgroup "user"
|
||||
|
||||
option "origin" o "Origin URL to use during registration. Defaults to pam://hostname" string optional
|
||||
option "appid" i "Application ID to use during registration. Defaults to pam://hostname" string optional
|
||||
option "type" t "COSE type to use during registration (ES256 or RS256). Defaults to ES256." string optional
|
||||
option "resident" r "Generate a resident credential" flag off
|
||||
option "no-user-presence" P "Allow the credential to be used without ensuring the user's presence" flag off
|
||||
option "pin-verification" N "Require PIN verification during authentication" flag off
|
||||
option "user-verification" V "Require user verification during authentication" flag off
|
||||
option "debug" d "Print debug information (highly verbose)" flag off
|
||||
option "verbose" v "Print information about chosen origin and appid" flag off
|
||||
groupoption "username" u "The name of the user registering the device. Defaults to the current user name" string group="user"
|
||||
groupoption "nouser" n "Print only registration information (keyHandle and public key). Useful for appending" group="user"
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2018 Yubico AB - See COPYING
|
||||
*/
|
||||
|
||||
#define BUFSIZE 1024
|
||||
#define PAM_PREFIX "pam://"
|
||||
#define TIMEOUT 15
|
||||
#define FREQUENCY 1
|
||||
|
||||
#include <fido.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "b64.h"
|
||||
#include "cmdline.h"
|
||||
#include "util.h"
|
||||
#ifndef HAVE_READPASSPHRASE
|
||||
#include "_readpassphrase.h"
|
||||
#else
|
||||
#include <readpassphrase.h>
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int exit_code = EXIT_FAILURE;
|
||||
struct gengetopt_args_info args_info;
|
||||
char buf[BUFSIZE];
|
||||
char prompt[BUFSIZE];
|
||||
char pin[BUFSIZE];
|
||||
char *p;
|
||||
char *response;
|
||||
fido_cred_t *cred = NULL;
|
||||
fido_dev_info_t *devlist = NULL;
|
||||
fido_dev_t *dev = NULL;
|
||||
const fido_dev_info_t *di = NULL;
|
||||
size_t ndevs;
|
||||
int cose_type;
|
||||
int resident_key;
|
||||
int user_presence;
|
||||
int user_verification;
|
||||
int pin_verification;
|
||||
int r;
|
||||
int n;
|
||||
char *origin = NULL;
|
||||
char *appid = NULL;
|
||||
char *user = NULL;
|
||||
char *b64_kh;
|
||||
char *b64_pk;
|
||||
struct passwd *passwd;
|
||||
const unsigned char *kh = NULL;
|
||||
size_t kh_len;
|
||||
const unsigned char *pk = NULL;
|
||||
size_t pk_len;
|
||||
unsigned char userid[32];
|
||||
unsigned char challenge[32];
|
||||
unsigned i;
|
||||
unsigned max_index = 0;
|
||||
|
||||
if (cmdline_parser(argc, argv, &args_info) != 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (args_info.help_given) {
|
||||
cmdline_parser_print_help();
|
||||
printf("\nReport bugs at <https://github.com/Yubico/pam-u2f>.\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
fido_init(args_info.debug_flag ? FIDO_DEBUG : 0);
|
||||
|
||||
cred = fido_cred_new();
|
||||
if (!cred) {
|
||||
fprintf(stderr, "fido_cred_new failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!random_bytes(challenge, sizeof(challenge))) {
|
||||
fprintf(stderr, "random_bytes failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (args_info.type_given) {
|
||||
if (!strcasecmp(args_info.type_arg, "es256"))
|
||||
cose_type = COSE_ES256;
|
||||
else if (!strcasecmp(args_info.type_arg, "rs256"))
|
||||
cose_type = COSE_RS256;
|
||||
else {
|
||||
fprintf(stderr, "Unknown COSE type '%s'.\n", args_info.type_arg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else
|
||||
cose_type = COSE_ES256;
|
||||
|
||||
r = fido_cred_set_type(cred, cose_type);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_cred_set_type (%d): %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = fido_cred_set_clientdata_hash(cred, challenge, sizeof(challenge));
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_cred_set_clientdata_hash (%d): %s\n", r,
|
||||
fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (args_info.origin_given)
|
||||
origin = args_info.origin_arg;
|
||||
else {
|
||||
if (!strcpy(buf, PAM_PREFIX)) {
|
||||
fprintf(stderr, "strcpy failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (gethostname(buf + strlen(PAM_PREFIX), BUFSIZE - strlen(PAM_PREFIX)) ==
|
||||
-1) {
|
||||
perror("gethostname");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
origin = buf;
|
||||
}
|
||||
|
||||
if (args_info.verbose_given)
|
||||
fprintf(stderr, "Setting origin to %s\n", origin);
|
||||
|
||||
if (args_info.appid_given)
|
||||
appid = args_info.appid_arg;
|
||||
else {
|
||||
appid = origin;
|
||||
}
|
||||
|
||||
if (args_info.verbose_given)
|
||||
fprintf(stderr, "Setting appid to %s\n", appid);
|
||||
|
||||
r = fido_cred_set_rp(cred, origin, appid);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_cred_set_rp (%d) %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (args_info.username_given)
|
||||
user = args_info.username_arg;
|
||||
else {
|
||||
passwd = getpwuid(getuid());
|
||||
if (passwd == NULL) {
|
||||
perror("getpwuid");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
user = passwd->pw_name;
|
||||
}
|
||||
|
||||
if (!random_bytes(userid, sizeof(userid))) {
|
||||
fprintf(stderr, "random_bytes failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (args_info.verbose_given) {
|
||||
fprintf(stderr, "Setting user to %s\n", user);
|
||||
fprintf(stderr, "Setting user id to ");
|
||||
for (size_t i = 0; i < sizeof(userid); i++)
|
||||
fprintf(stderr, "%02x", userid[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
r = fido_cred_set_user(cred, userid, sizeof(userid), user, NULL, NULL);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_cred_set_user (%d) %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (args_info.resident_given)
|
||||
resident_key = 1;
|
||||
else
|
||||
resident_key = 0;
|
||||
|
||||
if (args_info.no_user_presence_given)
|
||||
user_presence = 0;
|
||||
else
|
||||
user_presence = 1;
|
||||
|
||||
if (args_info.user_verification_given)
|
||||
user_verification = 1;
|
||||
else
|
||||
user_verification = 0;
|
||||
|
||||
if (args_info.pin_verification_given)
|
||||
pin_verification = 1;
|
||||
else
|
||||
pin_verification = 0;
|
||||
|
||||
r = fido_cred_set_rk(cred, resident_key);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_cred_set_rk (%d) %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = fido_cred_set_uv(cred, false);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_cred_set_uv (%d) %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
devlist = fido_dev_info_new(64);
|
||||
if (!devlist) {
|
||||
fprintf(stderr, "error: fido_dev_info_new failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = fido_dev_info_manifest(devlist, 64, &ndevs);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "Unable to discover device(s), %s (%d)\n", fido_strerr(r),
|
||||
r);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (ndevs == 0) {
|
||||
for (i = 0; i < TIMEOUT; i += FREQUENCY) {
|
||||
fprintf(stderr,
|
||||
"\rNo U2F device available, please insert one now, you "
|
||||
"have %2d seconds",
|
||||
TIMEOUT - i);
|
||||
fflush(stderr);
|
||||
sleep(FREQUENCY);
|
||||
|
||||
r = fido_dev_info_manifest(devlist, 64, &ndevs);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "\nUnable to discover device(s), %s (%d)",
|
||||
fido_strerr(r), r);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (ndevs != 0) {
|
||||
fprintf(stderr, "\nDevice found!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ndevs == 0) {
|
||||
fprintf(stderr, "\rNo device found. Aborting. "
|
||||
" \n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* XXX loop over every device? */
|
||||
dev = fido_dev_new();
|
||||
if (!dev) {
|
||||
fprintf(stderr, "fido_dev_new failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
di = fido_dev_info_ptr(devlist, 0);
|
||||
if (!di) {
|
||||
fprintf(stderr, "error: fido_dev_info_ptr returned NULL\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = fido_dev_open(dev, fido_dev_info_path(di));
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_dev_open (%d) %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = fido_dev_make_cred(dev, cred, NULL);
|
||||
if (r == FIDO_ERR_PIN_REQUIRED) {
|
||||
n = snprintf(prompt, sizeof(prompt),
|
||||
"Enter PIN for %s: ", fido_dev_info_path(di));
|
||||
if (n < 0 || (size_t) n >= sizeof(prompt)) {
|
||||
fprintf(stderr, "error: snprintf prompt");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) {
|
||||
fprintf(stderr, "error: failed to read pin");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
r = fido_dev_make_cred(dev, cred, pin);
|
||||
}
|
||||
explicit_bzero(pin, sizeof(pin));
|
||||
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_dev_make_cred (%d) %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = fido_cred_verify(cred);
|
||||
if (r != FIDO_OK) {
|
||||
fprintf(stderr, "error: fido_cred_verify (%d) %s\n", r, fido_strerr(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
kh = fido_cred_id_ptr(cred);
|
||||
if (!kh) {
|
||||
fprintf(stderr, "error: fido_cred_id_ptr returned NULL\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
kh_len = fido_cred_id_len(cred);
|
||||
if (kh_len == 0) {
|
||||
fprintf(stderr, "error: fido_cred_id_len returned 0\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pk = (const unsigned char *) fido_cred_pubkey_ptr(cred);
|
||||
if (!pk) {
|
||||
fprintf(stderr, "error: fido_cred_pubkey_ptr returned NULL\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pk_len = fido_cred_pubkey_len(cred);
|
||||
if (pk_len == 0) {
|
||||
fprintf(stderr, "error: fido_cred_pubkey_len returned 0\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!b64_encode(kh, kh_len, &b64_kh)) {
|
||||
fprintf(stderr, "error: failed to encode key handle\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!b64_encode(pk, pk_len, &b64_pk)) {
|
||||
fprintf(stderr, "error: failed to encode public key\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!args_info.nouser_given)
|
||||
printf("%s", user);
|
||||
|
||||
printf(":%s,%s,%s,%s%s%s", resident_key ? "*" : b64_kh, b64_pk,
|
||||
cose_type == COSE_ES256 ? "es256" : "rs256",
|
||||
user_presence ? "+presence" : "",
|
||||
user_verification ? "+verification" : "",
|
||||
pin_verification ? "+pin" : "");
|
||||
|
||||
exit_code = EXIT_SUCCESS;
|
||||
|
||||
fido_dev_info_free(&devlist, ndevs);
|
||||
fido_cred_free(&cred);
|
||||
fido_dev_free(&dev);
|
||||
|
||||
free(b64_kh);
|
||||
free(b64_pk);
|
||||
|
||||
exit(exit_code);
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/* $OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000-2002, 2007, 2010
|
||||
* Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
/* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
|
||||
|
||||
#ifndef HAVE_READPASSPHRASE
|
||||
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <paths.h>
|
||||
|
||||
#include "_readpassphrase.h"
|
||||
|
||||
#ifndef _PATH_TTY
|
||||
# define _PATH_TTY "/dev/tty"
|
||||
#endif
|
||||
|
||||
#ifndef TCSASOFT
|
||||
/* If we don't have TCSASOFT define it so that ORing it it below is a no-op. */
|
||||
# define TCSASOFT 0
|
||||
#endif
|
||||
|
||||
/* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
|
||||
#if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
|
||||
# define _POSIX_VDISABLE VDISABLE
|
||||
#endif
|
||||
|
||||
static volatile sig_atomic_t signo[_NSIG];
|
||||
|
||||
static void handler(int);
|
||||
|
||||
char *
|
||||
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
|
||||
{
|
||||
ssize_t nr;
|
||||
int input, output, save_errno, i, need_restart;
|
||||
char ch, *p, *end;
|
||||
struct termios term, oterm;
|
||||
struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
|
||||
struct sigaction savetstp, savettin, savettou, savepipe;
|
||||
|
||||
/* I suppose we could alloc on demand in this case (XXX). */
|
||||
if (bufsiz == 0) {
|
||||
errno = EINVAL;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
restart:
|
||||
for (i = 0; i < _NSIG; i++)
|
||||
signo[i] = 0;
|
||||
need_restart = 0;
|
||||
/*
|
||||
* Read and write to /dev/tty if available. If not, read from
|
||||
* stdin and write to stderr unless a tty is required.
|
||||
*/
|
||||
if ((flags & RPP_STDIN) ||
|
||||
(input = output = open(_PATH_TTY, O_RDWR)) == -1) {
|
||||
if (flags & RPP_REQUIRE_TTY) {
|
||||
errno = ENOTTY;
|
||||
return(NULL);
|
||||
}
|
||||
input = STDIN_FILENO;
|
||||
output = STDERR_FILENO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn off echo if possible.
|
||||
* If we are using a tty but are not the foreground pgrp this will
|
||||
* generate SIGTTOU, so do it *before* installing the signal handlers.
|
||||
*/
|
||||
if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
|
||||
memcpy(&term, &oterm, sizeof(term));
|
||||
if (!(flags & RPP_ECHO_ON))
|
||||
term.c_lflag &= ~(ECHO | ECHONL);
|
||||
#ifdef VSTATUS
|
||||
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
|
||||
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
|
||||
#endif
|
||||
(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
|
||||
} else {
|
||||
memset(&term, 0, sizeof(term));
|
||||
term.c_lflag |= ECHO;
|
||||
memset(&oterm, 0, sizeof(oterm));
|
||||
oterm.c_lflag |= ECHO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch signals that would otherwise cause the user to end
|
||||
* up with echo turned off in the shell. Don't worry about
|
||||
* things like SIGXCPU and SIGVTALRM for now.
|
||||
*/
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0; /* don't restart system calls */
|
||||
sa.sa_handler = handler;
|
||||
(void)sigaction(SIGALRM, &sa, &savealrm);
|
||||
(void)sigaction(SIGHUP, &sa, &savehup);
|
||||
(void)sigaction(SIGINT, &sa, &saveint);
|
||||
(void)sigaction(SIGPIPE, &sa, &savepipe);
|
||||
(void)sigaction(SIGQUIT, &sa, &savequit);
|
||||
(void)sigaction(SIGTERM, &sa, &saveterm);
|
||||
(void)sigaction(SIGTSTP, &sa, &savetstp);
|
||||
(void)sigaction(SIGTTIN, &sa, &savettin);
|
||||
(void)sigaction(SIGTTOU, &sa, &savettou);
|
||||
|
||||
if (!(flags & RPP_STDIN))
|
||||
(void)write(output, prompt, strlen(prompt));
|
||||
end = buf + bufsiz - 1;
|
||||
p = buf;
|
||||
while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
|
||||
if (p < end) {
|
||||
if ((flags & RPP_SEVENBIT))
|
||||
ch &= 0x7f;
|
||||
if (isalpha((unsigned char)ch)) {
|
||||
if ((flags & RPP_FORCELOWER))
|
||||
ch = (char)tolower((unsigned char)ch);
|
||||
if ((flags & RPP_FORCEUPPER))
|
||||
ch = (char)toupper((unsigned char)ch);
|
||||
}
|
||||
*p++ = ch;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
save_errno = errno;
|
||||
if (!(term.c_lflag & ECHO))
|
||||
(void)write(output, "\n", 1);
|
||||
|
||||
/* Restore old terminal settings and signals. */
|
||||
if (memcmp(&term, &oterm, sizeof(term)) != 0) {
|
||||
const int sigttou = signo[SIGTTOU];
|
||||
|
||||
/* Ignore SIGTTOU generated when we are not the fg pgrp. */
|
||||
while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
|
||||
errno == EINTR && !signo[SIGTTOU])
|
||||
continue;
|
||||
signo[SIGTTOU] = sigttou;
|
||||
}
|
||||
(void)sigaction(SIGALRM, &savealrm, NULL);
|
||||
(void)sigaction(SIGHUP, &savehup, NULL);
|
||||
(void)sigaction(SIGINT, &saveint, NULL);
|
||||
(void)sigaction(SIGQUIT, &savequit, NULL);
|
||||
(void)sigaction(SIGPIPE, &savepipe, NULL);
|
||||
(void)sigaction(SIGTERM, &saveterm, NULL);
|
||||
(void)sigaction(SIGTSTP, &savetstp, NULL);
|
||||
(void)sigaction(SIGTTIN, &savettin, NULL);
|
||||
(void)sigaction(SIGTTOU, &savettou, NULL);
|
||||
if (input != STDIN_FILENO)
|
||||
(void)close(input);
|
||||
|
||||
/*
|
||||
* If we were interrupted by a signal, resend it to ourselves
|
||||
* now that we have restored the signal handlers.
|
||||
*/
|
||||
for (i = 0; i < _NSIG; i++) {
|
||||
if (signo[i]) {
|
||||
kill(getpid(), i);
|
||||
switch (i) {
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
need_restart = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (need_restart)
|
||||
goto restart;
|
||||
|
||||
if (save_errno)
|
||||
errno = save_errno;
|
||||
return(nr == -1 ? NULL : buf);
|
||||
}
|
||||
|
||||
#if 0
|
||||
char *
|
||||
getpass(const char *prompt)
|
||||
{
|
||||
static char buf[_PASSWORD_LEN + 1];
|
||||
|
||||
return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void handler(int s)
|
||||
{
|
||||
|
||||
signo[s] = 1;
|
||||
}
|
||||
#endif /* HAVE_READPASSPHRASE */
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright (C) 2014-2018 Yubico AB - See COPYING
|
||||
#
|
||||
|
||||
AM_CFLAGS = $(WARN_CFLAGS)
|
||||
AM_CPPFLAGS=-I$(srcdir)/.. -I$(builddir)/..
|
||||
|
||||
AM_LDFLAGS = -no-install
|
||||
|
||||
LDADD = $(top_builddir)/pam_u2f.la
|
||||
|
||||
check_PROGRAMS = basic
|
||||
TESTS = $(check_PROGRAMS)
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2018 Yubico AB - See COPYING
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* These #defines must be present according to PAM documentation. */
|
||||
#define PAM_SM_AUTH
|
||||
|
||||
#ifdef HAVE_SECURITY_PAM_APPL_H
|
||||
#include <security/pam_appl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SECURITY_PAM_MODULES_H
|
||||
#include <security/pam_modules.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, const char **argv)
|
||||
{
|
||||
pam_handle_t *pamh = NULL;
|
||||
int rc;
|
||||
|
||||
rc = pam_sm_authenticate (pamh, 0, 1, argv);
|
||||
|
||||
printf ("rc %d\n", rc);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
FROM ubuntu:bionic
|
||||
COPY . /pam-u2f
|
||||
WORKDIR /pam-u2f
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN apt-get -qq update
|
||||
RUN apt-get -qq upgrade
|
||||
RUN apt-get install -qq software-properties-common
|
||||
RUN add-apt-repository ppa:yubico/stable
|
||||
RUN apt-get -qq update
|
||||
RUN apt-get install -qq libudev-dev libssl-dev libfido2-dev
|
||||
RUN apt-get install -qq build-essential autoconf automake libtool pkg-config
|
||||
RUN apt-get install -qq gengetopt libpam-dev pamtester
|
||||
RUN autoreconf -i .
|
||||
RUN ./configure --disable-man
|
||||
RUN make clean all install
|
|
@ -0,0 +1,18 @@
|
|||
pam-u2f can be tested as follows:
|
||||
|
||||
1. Build a Docker image containing everything needed to run pam-u2f.
|
||||
This can be achieved through the command:
|
||||
|
||||
$ docker build -t pam-u2f-test -f tests/bionic/Dockerfile .
|
||||
|
||||
2. Connect a YubiKey to the host OS and take note of the path of the
|
||||
device's U2F endpoint (e.g. /dev/hidraw6).
|
||||
3. Execute tests/bionic/run.sh in a container, exposing the YubiKey
|
||||
to the guest OS. This can be done through the command:
|
||||
|
||||
$ docker run -it --rm=true --device=/dev/hidraw6 \
|
||||
pam-u2f-test /pam-u2f/tests/bionic/run.sh
|
||||
|
||||
To test U2F devices, pass -e U2F_TOKEN=1 to docker-run. To test
|
||||
FIDO2 devices configured with a PIN, pass -e FIDO2_PIN=1 to
|
||||
docker-run.
|
|
@ -0,0 +1,63 @@
|
|||
#!/bin/sh -ex
|
||||
mkdir -p ~/.config/Yubico
|
||||
|
||||
create_keys() {
|
||||
pamu2fcfg -t es256 -N > /tmp/es256
|
||||
[ "${U2F_TOKEN}" != "" ] && return
|
||||
pamu2fcfg -t es256 -N -r -o originA > /tmp/es256.r
|
||||
pamu2fcfg -t rs256 -N -r -o originB > /tmp/rs256.r
|
||||
}
|
||||
|
||||
run_tests() {
|
||||
[ "${U2F_TOKEN}" != "" ] && return
|
||||
|
||||
echo "auth sufficient pam_u2f.so" > /etc/pam.d/dummy
|
||||
cp /tmp/es256 ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
|
||||
echo "auth sufficient pam_u2f.so origin=originA" > /etc/pam.d/dummy
|
||||
cp /tmp/es256.r ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
|
||||
echo "auth sufficient pam_u2f.so origin=originB" > /etc/pam.d/dummy
|
||||
cp /tmp/rs256.r ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
}
|
||||
|
||||
run_user_presence_tests() {
|
||||
echo "auth sufficient pam_u2f.so" > /etc/pam.d/dummy
|
||||
cat /tmp/es256 | sed 's/-$/p/' > ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
|
||||
[ "${U2F_TOKEN}" != "" ] && return
|
||||
|
||||
echo "auth sufficient pam_u2f.so origin=originA" > /etc/pam.d/dummy
|
||||
cat /tmp/es256.r | sed 's/-$/p/' > ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
|
||||
echo "auth sufficient pam_u2f.so origin=originB" > /etc/pam.d/dummy
|
||||
cat /tmp/rs256.r | sed 's/-$/p/' > ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
}
|
||||
|
||||
run_user_verification_tests() {
|
||||
[ "${U2F_TOKEN}" != "" ] && return
|
||||
[ "${FIDO2_PIN}" = "" ] && return
|
||||
|
||||
echo "auth sufficient pam_u2f.so" > /etc/pam.d/dummy
|
||||
cat /tmp/es256 | sed 's/-$/v/' > ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
|
||||
echo "auth sufficient pam_u2f.so origin=originA" > /etc/pam.d/dummy
|
||||
cat /tmp/es256.r | sed 's/-$/v/' > ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
|
||||
echo "auth sufficient pam_u2f.so origin=originB" > /etc/pam.d/dummy
|
||||
cat /tmp/rs256.r | sed 's/-$/v/' > ~/.config/Yubico/u2f_keys
|
||||
pamtester dummy root authenticate
|
||||
}
|
||||
|
||||
create_keys
|
||||
run_tests
|
||||
run_user_presence_tests
|
||||
run_user_verification_tests
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2019 Yubico AB - See COPYING
|
||||
*/
|
||||
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
#define BUFSIZE 1024
|
||||
#define MAX_DEVS 24
|
||||
#define PK_LEN 130 // Public key
|
||||
#define KH_LEN 86 // Key handle
|
||||
#define RD_LEN 40 // Rounding
|
||||
#define DEVSIZE (((PK_LEN) + (KH_LEN) + (RD_LEN)))
|
||||
#define DEFAULT_AUTHFILE_DIR_VAR "XDG_CONFIG_HOME"
|
||||
#define DEFAULT_AUTHFILE "/Yubico/u2f_keys"
|
||||
#define DEFAULT_AUTHPENDING_FILE_PATH "/var/run/user/%d/pam-u2f-authpending"
|
||||
#define DEFAULT_PROMPT "Insert your U2F device, then press ENTER."
|
||||
#define DEFAULT_CUE "Please touch the device."
|
||||
#define DEFAULT_ORIGIN_PREFIX "pam://"
|
||||
#define DEBUG_STR "debug(pam_u2f): %s:%d (%s): "
|
||||
|
||||
#if defined(DEBUG_PAM)
|
||||
#define D(file, ...) _debug(file, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
#else
|
||||
#define D(file, ...)
|
||||
#endif /* DEBUG_PAM */
|
||||
|
||||
typedef struct {
|
||||
unsigned max_devs;
|
||||
const char *client_key;
|
||||
int manual;
|
||||
int debug;
|
||||
int nouserok;
|
||||
int openasuser;
|
||||
int alwaysok;
|
||||
int interactive;
|
||||
int cue;
|
||||
int nodetect;
|
||||
int userpresence;
|
||||
int userverification;
|
||||
int pinverification;
|
||||
const char *auth_file;
|
||||
const char *authpending_file;
|
||||
const char *origin;
|
||||
const char *appid;
|
||||
const char *prompt;
|
||||
const char *cue_prompt;
|
||||
FILE *debug_file;
|
||||
int is_custom_debug_file;
|
||||
} cfg_t;
|
||||
|
||||
typedef struct {
|
||||
char *publicKey;
|
||||
char *keyHandle;
|
||||
char *coseType;
|
||||
char *attributes;
|
||||
int old_format;
|
||||
} device_t;
|
||||
|
||||
int get_devices_from_authfile(const char *authfile, const char *username,
|
||||
unsigned max_devs, int verbose, FILE *debug_file,
|
||||
device_t *devices, unsigned *n_devs);
|
||||
void free_devices(device_t *devices, const unsigned n_devs);
|
||||
|
||||
int do_authentication(const cfg_t *cfg, const device_t *devices,
|
||||
const unsigned n_devs, pam_handle_t *pamh);
|
||||
int do_manual_authentication(const cfg_t *cfg, const device_t *devices,
|
||||
const unsigned n_devs, pam_handle_t *pamh);
|
||||
char *converse(pam_handle_t *pamh, int echocode, const char *prompt);
|
||||
void _debug(FILE *, const char *, int, const char *, const char *, ...);
|
||||
int random_bytes(void *, size_t);
|
||||
|
||||
#if !defined(HAVE_EXPLICIT_BZERO)
|
||||
void explicit_bzero(void *, size_t);
|
||||
#endif
|
||||
|
||||
#endif /* UTIL_H */
|
Loading…
Reference in New Issue