NetBSD でも YubiKey を使って二要素認証したい

これは NetBSD Advent Calendar 2015 の 24 日目の記事です。

はじめに

Github ユーザなら 20% off というキャンペーンを見かけて IYH した YubiKey 4 が届いたので NetBSD で使えるか試してみました。

今回はコンソールログイン時の認証を既存のパスワードに加え YubiKey の OTP を使った認証を使えるようにしてみようと思います。

前提条件

  • 使用しているシステムは 2015/12/20 あたりのソースがベースの独自パッチがあたっている NetBSD/amd64 7.99.24 です。
  • pam_yubico で使用される認証サーバーには Yubico の提供しているサーバー YubiCloud を使用します。
  • 上記条件より pam_yubico を使用するシステムはインターネットに接続されている必要があります。

YubiKey 設定確認

YubiKey 4 の初期設定では OTP が使えるようになっているはずなので、とりあえず NetBSD マシンに YubiKey 4 を接続してみます。

uhidev2 at uhub2 port 1 configuration 1 interface 0
uhidev2: Yubico Yubikey 4 OTP+U2F+CCID, rev 2.00/4.27, addr 6, iclass 3/1
ukbd1 at uhidev2: 8 modifier keys, 6 key codes
wskbd2 at ukbd1 mux 1
wskbd2: connecting to wsdisplay0
uhidev3 at uhub2 port 1 configuration 1 interface 1
uhidev3: Yubico Yubikey 4 OTP+U2F+CCID, rev 2.00/4.27, addr 6, iclass 3/0
uhid0 at uhidev3: input=64, output=64, feature=0

接続後の dmesg に上記の様に「Yubico Yubikey 4 OTP+U2F+CCID」と「OTP」が含まれている、かつ ukbd(4) が attach されていて YubiKey 4 の「y」マークをタッチして 44 文字入力されれば問題ないようです。

ここで ukbd(4) が attach されていないと動作モードの変更が必要になるのですが、素の NetBSD カーネルだと動作モードの変更が難しいので後述することにします、しないかもしれません。*1

NetBSD 設定

pam_yubico インストール

NetBSD では PAM を使ってログイン時の認証などを行っています。 調べてみたところ YubiKey 開発元の Yubicopam_yubico という PAM のモジュールを提供しているのでこれを使えば YubiKey を使った認証ができるようになりそうです。

幸いにして pkgsrc に security/pam-yubico が存在しているのでこれを使えば苦労することなく目的を達することができそうです。

というわけで pam_yubico を pkgsrc を使ってインストールします。

$ cd /usr/pkgsrc/security/pam-yubico
$ sudo make install
$ pkg_info | grep pam-yubico
pam-yubico-2.17     Pluggable Authentication Module for Yubikey validation

Client ID 取得

PAM 設定ファイルを編集する前に pam_yubico の Configuration を見ると Client ID というものが出てきますが、これは Yubico Get API Key で取得可能なようです。

「Your e-mail address」には適当に自分のメールアドレスを、「YubiKey one-time password」には右側の入力欄にフォーカスさせてから YubiKey を指でタッチして文字列を入力します。「Get API Key」ボタンをクリック後に Client ID と Secret Key が表示されるので忘れないようにメモしておきます。

PAM 設定

コンソールログイン時の login プロンプトは /usr/bin/login が表示しています。これに対応する PAM の設定ファイルはどうマッピングされているのかまでは調べていませんが /etc/pam.d/login になるようです。

2015/12/23 時点の HEAD の /etc/pam.d/login の内容はこんな感じです。

# $NetBSD: login,v 1.4 2005/02/27 03:40:14 thorpej Exp $
#
# PAM configuration for the "login" service
#

# auth
auth        sufficient  pam_self.so     no_warn
auth        required    pam_nologin.so      no_warn
auth        include     system

# account
account     requisite   pam_securetty.so
account     required    pam_login_access.so
account     include     system

# session
session     include     system

# password
password    include     system

今回注目するのは auth です。

auth の最後の行で system を include しているので、こっちも見てみます。

# $NetBSD: system,v 1.8 2008/03/26 11:31:17 lukem Exp $
#
# System-wide defaults
#

# auth
auth        sufficient  pam_skey.so     no_warn try_first_pass
auth        sufficient  pam_krb5.so     no_warn try_first_pass
auth        optional    pam_afslog.so       no_warn try_first_pass
auth        required    pam_unix.so     no_warn try_first_pass nullok

# account
account     required    pam_krb5.so
account     required    pam_unix.so

# session
session     required    pam_lastlog.so      no_fail no_nested

# password
password    sufficient  pam_krb5.so     no_warn try_first_pass
password    required    pam_unix.so     no_warn try_first_pass

/etc/pam.d/system にはシステムデフォルトが記述されているようです。このファイルを編集すると別のプログラムでも影響があるので、/etc/pam.d/login の方を編集することにします。

※PAM 設定ファイル中の auth 以外の箇所は変更しないので、これ以降は auth 部分のみを例示します。

pam_yubico の Configuration を参考に /etc/pam.d/login に pam_yubico の設定を追加します。

auth     sufficient  pam_self.so     no_warn
auth        required    pam_nologin.so      no_warn
auth        sufficient  /usr/pkg/lib/security/pam_yubico.so id=XXX debug
auth        include     system

NetBSD では特定のディレクトリに PAM モジュールを配置する必要は無く、モジュールのフルパスを指定すれば良いようです。

id には取得した Client ID を設定します。

また、この時点では設定ミスなどがあった場合にわかりやすくなるので debug を指定しておきます。

認可用マッピングファイル作成

pam_yubico の Authorization Mapping Files に記載されているように、ユーザと YubiKey の対応付けを行うファイルを作成します。 今回はユーザのホームディレクトリに認可用マッピングファイルを作成します。

$ cd
$ pwd
/home/nonaka
$ mkdir .yubico
$ chmod 700 .yubico
$ ls -ld .yubico
drwx------  2 nonaka  nonaka  512 Dec 23 09:22 .yubico
$ cd .yubico
$ pwd
/home/nonaka/.yubico
$ echo "nonaka:OTPfirst12char" > authorized_yubikeys
$ chmod 600 authorized_yubikeys
$ ls -l authorized_yubikeys
-rw-------  1 nonaka  nonaka  20 Dec 23 09:22 authorized_yubikeys

$HOME/.yubico/authorized_yubikeysOTPfirst12char には YubiKey をタッチして入力される文字列の先頭 12 文字を設定します。

最初は Modhex を指定する必要があるのかと思ったのですがそういう訳では無いようです。

さあ試してみよう

ここまで設定すると YubiKey を使ったログインができるようになっている筈なので実際にログインしてみます。

system の前に pam_yubico を追加したのでパスワードの前に YubiKey の入力が求められる筈です。

NetBSD/amd64 (koharu.myhome.nonakap.org) (ttyE1)

login: nonaka
Password:
Last login: Wed Dec 23 14:24:22 2015 on ttyE1
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 7.99.24 (KOHARU) #3367: Sun Dec 20 14:07:44 JST 2015
nonaka@koaru$ 

おいィ?

YubiKey のゆの字すら出てきません。

慌てず騒がず /var/log 配下のログファイルを見てみます。認証認可関連なので /var/log/authlog でしょう。

Dec 23 14:34:19 koharu login: in openpam_dispatch(): /usr/pkg/lib/security/pam_yubico.so: no pam_sm_authenticate()
Dec 23 14:34:21 koharu login: nonaka on tty ttyE1
Dec 23 14:34:21 koharu login: in openpam_dispatch(): /usr/pkg/lib/security/pam_yubico.so: no pam_sm_setcred()

おいィ?(二回目

慌てず騒がず /usr/pkg/lib/security/pam_yubico.so のシンボル一覧を見ます。

$ nm /usr/pkg/lib/security/pam_yubico.so
0000000000203028 d _DYNAMIC
0000000000203388 d _GLOBAL_OFFSET_TABLE_
                 w _Jv_RegisterClasses
0000000000203008 d __CTOR_LIST_END__
0000000000002870 r __FUNCTION__.4014
0000000000002850 r __FUNCTION__.4029
0000000000002990 r __FUNCTION__.4254
0000000000002970 r __FUNCTION__.4260
000000000020355c D __bss_start
                 w __cxa_finalize
                 w __deregister_frame_info@@GCC_3.0
0000000000203510 d __dso_handle
                 U __errno
                 U __getpwnam50
                 w __register_frame_info@@GCC_3.0
                 U __sF
000000000020355c D _edata
0000000000203560 D _end
0000000000002580 T _fini
00000000000013b0 T _init
00000000000019f3 T challenge_response
00000000000018b9 T check_firmware_version
                 U fclose
                 U fflush
                 U fileno
                 U fopen
                 U fprintf
                 U fread
                 U free
                 U fscanf
                 U fsync
                 U ftruncate
                 U fwrite
0000000000001863 T generate_random
0000000000001770 T get_user_cfgfile_path
0000000000001b19 T get_user_challenge_file
                 U getegid
                 U geteuid
                 U getgroups
00000000000019ce T init_yubikey
                 U initgroups
0000000000001c6d T load_chalresp_state
                 U malloc
                 U memset
00000000000021f0 T pam_modutil_drop_priv
0000000000002422 T pam_modutil_regain_priv
                 U printf
                 U putchar
                 U rewind
                 U setegid
                 U seteuid
                 U setgroups
                 U snprintf
                 U strerror
0000000000001ffe T write_chalresp_state
                 U yk_challenge_response@@LIBYKPERS_1.8
                 U yk_get_serial@@LIBYKPERS_1.5
                 U yk_get_status@@LIBYKPERS_1.0
                 U yk_hmac_sha1@@LIBYKPERS_1.9
                 U yk_init@@LIBYKPERS_1.0
                 U yk_open_first_key@@LIBYKPERS_1.0
                 U yk_pbkdf2@@LIBYKPERS_1.0
                 U ykds_alloc@@LIBYKPERS_1.0
                 U ykds_version_build@@LIBYKPERS_1.0
                 U ykds_version_major@@LIBYKPERS_1.0
                 U ykds_version_minor@@LIBYKPERS_1.0
                 U yubikey_hex_decode@@YUBIKEY_1.0
                 U yubikey_hex_encode@@YUBIKEY_1.0
                 U yubikey_hex_p@@YUBIKEY_1.5

確かに pam_sm_* なんてシンボルは存在していません。

pam_yubico 訪問

pam_yubico のソースを確認してみましょう。

$ cd /usr/pkgsrc/security/pam-yubico
$ make patch
$ cd /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17
$ grep -n pam_sm_authenticate *.[ch]
pam_yubico.c:792:pam_sm_authenticate (pam_handle_t * pamh,
pam_yubico.c:1107:  pam_sm_authenticate,
test.c:50:  rc = pam_sm_authenticate (pamh, 0, 1, (const char **) argv);

ありました。pam_yubico.c の 792 行目付近を見てます。

PAM_EXTERN int
pam_sm_authenticate (pam_handle_t * pamh,
                     int flags, int argc, const char **argv)

PAM_EXTERN というのが怪しそうです。

$ grep -n PAM_EXTERN *.[ch] | grep define
pam_yubico.c:81:#ifndef PAM_EXTERN
pam_yubico.c:83:#define PAM_EXTERN static
pam_yubico.c:85:#define PAM_EXTERN extern
pam_yubico.c:791:PAM_EXTERN int
pam_yubico.c:1097:PAM_EXTERN int

pam_yubico.c の 81 行目付近を見てます。

#ifndef PAM_EXTERN
#ifdef PAM_STATIC
#define PAM_EXTERN static
#else
#define PAM_EXTERN extern
#endif
#endif

PAM_STATIC というのはどこで define されるのでしょうか。

$ grep -n PAM_STATIC *.[ch]
pam_yubico.c:56:#define PAM_STATIC
pam_yubico.c:82:#ifdef PAM_STATIC
pam_yubico.c:1103:#ifdef PAM_STATIC

pam_yubico.c の 56 行目ですね。

/* Libtool defines PIC for shared objects */
#ifndef PIC
#define PAM_STATIC
#endif

この PIC は共有ライブラリを作成する際に指定されるやつですかね?

では実際に pkgsrc/security/pam-yubico をビルドしてみましょう。

$ cd /usr/pkgsrc/security/pam-yubico
$ make V=1 2>&1 | tee make.log
$ grep pam_yubico.c make.log
/bin/sh ./libtool  --tag=CC   --mode=compile gcc -DDEBUG_PAM -DPAM_DEBUG -DPACKAGE_NAME=\"pam_yubico\" -DPACKAGE_TARNAME=\"pam_yubico\" -DPACKAGE_VERSION=\"2.17\" -DPACKAGE_STRING=\"pam_yubico\ 2.17\" -DPACKAGE_BUGREPORT=\"yubico-devel@googlegroups.com\" -DPACKAGE_URL=\"\" -DPACKAGE=\"pam_yubico\" -DVERSION=\"2.17\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHAVE_SECURITY_PAM_APPL_H=1 -DHAVE_SECURITY_PAM_MODULES_H=1 -DHAVE_LIBPAM=1 -DHAVE_LIBLDAP=1 -DHAVE_LIBYKCLIENT=1 -DHAVE_LIBYUBIKEY=1 -DHAVE_CR=1 -I.  -pthread -I/usr/pkg/include/ykpers-1 -I/usr/pkg/include -I/usr/include/krb5 -I/usr/include  -O2 -I/usr/pkg/include -I/usr/include/krb5 -I/usr/include -MT pam_yubico_la-pam_yubico.lo -MD -MP -MF .deps/pam_yubico_la-pam_yubico.Tpo -c -o pam_yubico_la-pam_yubico.lo `test -f 'pam_yubico.c' || echo './'`pam_yubico.c
libtool: compile:  gcc -DDEBUG_PAM -DPAM_DEBUG -DPACKAGE_NAME=\"pam_yubico\" -DPACKAGE_TARNAME=\"pam_yubico\" -DPACKAGE_VERSION=\"2.17\" "-DPACKAGE_STRING=\"pam_yubico 2.17\"" -DPACKAGE_BUGREPORT=\"yubico-devel@googlegroups.com\" -DPACKAGE_URL=\"\" -DPACKAGE=\"pam_yubico\" -DVERSION=\"2.17\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHAVE_SECURITY_PAM_APPL_H=1 -DHAVE_SECURITY_PAM_MODULES_H=1 -DHAVE_LIBPAM=1 -DHAVE_LIBLDAP=1 -DHAVE_LIBYKCLIENT=1 -DHAVE_LIBYUBIKEY=1 -DHAVE_CR=1 -I. -pthread -I/usr/obj.pkgsrc/security/pam-yubico/work.koharu/.buildlink/include/ykpers-1 -I/usr/obj.pkgsrc/security/pam-yubico/work.koharu/.buildlink/include -I/usr/include/krb5 -O2 -MT pam_yubico_la-pam_yubico.lo -MD -MP -MF .deps/pam_yubico_la-pam_yubico.Tpo -c pam_yubico.c  -fPIC -DPIC -o .libs/pam_yubico_la-pam_yubico.o
pam_yubico.c: In function 'display_error':
pam_yubico.c:452:14: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]
libtool: compile:  gcc -DDEBUG_PAM -DPAM_DEBUG -DPACKAGE_NAME=\"pam_yubico\" -DPACKAGE_TARNAME=\"pam_yubico\" -DPACKAGE_VERSION=\"2.17\" "-DPACKAGE_STRING=\"pam_yubico 2.17\"" -DPACKAGE_BUGREPORT=\"yubico-devel@googlegroups.com\" -DPACKAGE_URL=\"\" -DPACKAGE=\"pam_yubico\" -DVERSION=\"2.17\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHAVE_SECURITY_PAM_APPL_H=1 -DHAVE_SECURITY_PAM_MODULES_H=1 -DHAVE_LIBPAM=1 -DHAVE_LIBLDAP=1 -DHAVE_LIBYKCLIENT=1 -DHAVE_LIBYUBIKEY=1 -DHAVE_CR=1 -I. -pthread -I/usr/obj.pkgsrc/security/pam-yubico/work.koharu/.buildlink/include/ykpers-1 -I/usr/obj.pkgsrc/security/pam-yubico/work.koharu/.buildlink/include -I/usr/include/krb5 -O2 -MT pam_yubico_la-pam_yubico.lo -MD -MP -MF .deps/pam_yubico_la-pam_yubico.Tpo -c pam_yubico.c -o pam_yubico_la-pam_yubico.o >/dev/null 2>&1

ちなみに make に V=1 を指定しないとコンパイル時に実行されるコマンドが表示されません。

少なくとも共有ライブラリ向けにコンパイルしている .libs/pam_yubico_la-pam_yubico.o では -fPIC -DPIC が指定されているので問題なさそうです。

一応 .libs/pam_yubico_la-pam_yubico.o のシンボルも見てみましょう。

$ nm /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17/.libs/pam_yubico_la-pam_yubico.o

おいィ?(三回目

何も表示されませんでした。

何かの間違いかもしれないので別のファイル .libs/pam_yubico_la-util.o のシンボルも見てみましょう。

$ nm /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17/.libs/pam_yubico_la-util.o
0000000000000000 r .LC0
0000000000000006 r .LC1
0000000000000054 r .LC10
000000000000005b r .LC11
0000000000000068 r .LC12
000000000000006f r .LC13
00000000000000a8 r .LC14
0000000000000075 r .LC15
00000000000000d8 r .LC16
0000000000000120 r .LC17
0000000000000140 r .LC18
0000000000000178 r .LC19
0000000000000014 r .LC2
00000000000001a8 r .LC20
00000000000001d0 r .LC21
0000000000000091 r .LC22
00000000000000a9 r .LC23
0000000000000016 r .LC3
0000000000000023 r .LC4
0000000000000000 r .LC5
000000000000003e r .LC6
0000000000000043 r .LC7
0000000000000038 r .LC8
000000000000004a r .LC9
                 U _GLOBAL_OFFSET_TABLE_
0000000000000020 r __FUNCTION__.4014
0000000000000000 r __FUNCTION__.4029
                 U __getpwnam50
                 U __sF
0000000000000283 T challenge_response
0000000000000149 T check_firmware_version
                 U fclose
                 U fflush
                 U fileno
                 U fopen
                 U fprintf
                 U fread
                 U free
                 U fscanf
                 U fsync
                 U ftruncate
                 U fwrite
00000000000000f3 T generate_random
0000000000000000 T get_user_cfgfile_path
00000000000003a9 T get_user_challenge_file
000000000000025e T init_yubikey
00000000000004fd T load_chalresp_state
                 U malloc
                 U memset
                 U printf
                 U putchar
                 U rewind
                 U snprintf
000000000000088e T write_chalresp_state
                 U yk_challenge_response
                 U yk_get_serial
                 U yk_get_status
                 U yk_hmac_sha1
                 U yk_init
                 U yk_open_first_key
                 U yk_pbkdf2
                 U ykds_alloc
                 U ykds_version_build
                 U ykds_version_major
                 U ykds_version_minor
                 U yubikey_hex_decode
                 U yubikey_hex_encode
                 U yubikey_hex_p

おいィ?(四回目

そんなバカな…

$ ls -l /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17/.libs/pam_yubico_la-*
-rw-r--r--  1 nonaka  wsrc   5704 Dec 23 15:09 /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17/.libs/pam_yubico_la-drop_privs.o
-rw-r--r--  1 nonaka  wsrc    814 Dec 23 15:09 /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17/.libs/pam_yubico_la-pam_yubico.o
-rw-r--r--  1 nonaka  wsrc  11048 Dec 23 15:09 /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17/.libs/pam_yubico_la-util.o

おいィ?(五回目

オブジェクトファイルのサイズが妙に小さい上にシンボルが一つも表示されないのってあれですかね、ファイル内に public なシンボルが無かったから全部消されたとかいう事なんでしょうか。

それって PAM_EXTERN として static が指定されているって事じゃないすか!やだー

という事で PIC 定義の有無に関係無く PAM_EXTERN に static が指定されているという事に。

$ cd /usr/obj.pkgsrc/security/pam-yubico/work.koharu/pam_yubico-2.17
$ find . -type f | xargs grep -n PAM_EXTERN /dev/null
./pam_yubico.c:81:#ifndef PAM_EXTERN
./pam_yubico.c:83:#define PAM_EXTERN static
./pam_yubico.c:85:#define PAM_EXTERN extern
./pam_yubico.c:791:PAM_EXTERN int
./pam_yubico.c:1097:PAM_EXTERN int

という事で pam_yubico は無罪

OpenPAM 訪問

NetBSD では PAM 関連のヘッダファイルは /usr/include/security にあるようです。

$ cd /usr/include/security/
$ grep -n PAM_EXTERN *
openpam.h:281:PAM_EXTERN int                                \
openpam.h:372:# define PAM_EXTERN static
openpam.h:389:# define PAM_EXTERN
pam_modules.h:56:PAM_EXTERN int
pam_modules.h:64:PAM_EXTERN int
pam_modules.h:72:PAM_EXTERN int
pam_modules.h:80:PAM_EXTERN int
pam_modules.h:88:PAM_EXTERN int
pam_modules.h:96:PAM_EXTERN int
pam_modules.h:107:PAM_EXTERN int
pam_modules.h:118:PAM_EXTERN int
pam_modules.h:128:PAM_EXTERN int
pam_modules.h:139:PAM_EXTERN int
pam_modules.h:149:PAM_EXTERN int

おいィ?(六回目

PAM_EXTERN は openpam.h で定義されているようです。

#if (defined(__GNUC__) || defined(__PCC__)) && !defined(NO_STATIC_MODULES)
# include <sys/cdefs.h>
# ifdef __FreeBSD__
#  include <linker_set.h>
# endif
# ifdef __NetBSD__
#  define DATA_SET(a, b) __link_set_add_data(a, b)
#  define SET_DECLARE(a, b) __link_set_decl(a, b)
#  define SET_FOREACH(a, b) __link_set_foreach(a, b)
# endif
# define OPENPAM_STATIC_MODULES
# define PAM_EXTERN static
# define PAM_MODULE_ENTRY(name)                        \
   static char _pam_name[] = name PAM_SOEXT;         \
   static struct pam_module _pam_module = {          \
       .path = _pam_name,                  \
       .func = {                       \
           [PAM_SM_AUTHENTICATE] = _PAM_SM_AUTHENTICATE,   \
           [PAM_SM_SETCRED] = _PAM_SM_SETCRED,     \
           [PAM_SM_ACCT_MGMT] = _PAM_SM_ACCT_MGMT,     \
           [PAM_SM_OPEN_SESSION] = _PAM_SM_OPEN_SESSION,   \
           [PAM_SM_CLOSE_SESSION] = _PAM_SM_CLOSE_SESSION, \
           [PAM_SM_CHAUTHTOK] = _PAM_SM_CHAUTHTOK      \
       },                          \
   };                              \
   DATA_SET(openpam_static_modules, _pam_module)
#else
/* normal case */
# define PAM_EXTERN
# define PAM_MODULE_ENTRY(name)
#endif

あー

どうやら NO_STATIC_MODULES が定義されていないと PAM_EXTERN に static が自動定義されるスバラシイ(褒めてない)コードになっていますね。

どうしてやろうか…

システム側のヘッダファイルがおかしいのであれば他の PAM 関連 pkgsrc でも問題が発生するような気がするんだけど、実は何か対処しているのだろうか

$ cd /usr/pkgsrc/security
$ grep -n NO_STATIC_MODULES */Makefile
gnome-keyring/Makefile:26:CFLAGS.NetBSD+=       -DNO_STATIC_MODULES
google-authenticator/Makefile:17:CFLAGS+=   -DNO_STATIC_MODULES
pam-dbm/Makefile:27:CFLAGS+=        -DNO_STATIC_MODULES
pam-fprint/Makefile:24:CFLAGS+=     -DNO_STATIC_MODULES
pam-krb5/Makefile:17:CPPFLAGS.NetBSD+=       -DNO_STATIC_MODULES
pam-ldap/Makefile:31:CFLAGS+=       -DNO_STATIC_MODULES
pam-mkhomedir/Makefile:38:CFLAGS+=      -DNO_STATIC_MODULES
pam-passwdqc/Makefile:16:CFLAGS+=   -DNO_STATIC_MODULES
pam-pwauth_suid/Makefile:13:PAMDEF+= -DNO_STATIC_MODULES
pam-yubico.new/Makefile:21:CFLAGS.NetBSD+=      -DNO_STATIC_MODULES
pam-yubico/Makefile:24:CFLAGS+=     -DNO_STATIC_MODULES

あー(二回目

とりあえず一番上の gnome-keyring/Makefile を見てましょう。

# $NetBSD: Makefile,v 1.83 2015/04/25 14:24:48 tnn Exp $

DISTNAME=   gnome-keyring-2.32.1
PKGREVISION=    19
CATEGORIES= security gnome
MASTER_SITES=   ${MASTER_SITE_GNOME:=sources/gnome-keyring/2.32/}
EXTRACT_SUFX=   .tar.bz2

MAINTAINER= pkgsrc-users@NetBSD.org
HOMEPAGE=   http://www.gnome.org/
COMMENT=    GNOME password and secret manager

USE_TOOLS+=     gmake intltool msgfmt pkg-config
GNU_CONFIGURE=      YES
USE_LIBTOOL=        YES
USE_PKGLOCALEDIR=   YES

PKGCONFIG_OVERRIDE+=    gcr/gcr.pc.in
PKGCONFIG_OVERRIDE+=    gp11/gp11.pc.in

CFLAGS.HPUX+=       -DMAP_ANON=MAP_ANONYMOUS

# Workaround a bug with NetBSD's openpam
# The bug is described in PR security/39313
#
CFLAGS.NetBSD+=     -DNO_STATIC_MODULES

.include "../../mk/bsd.prefs.mk"
.if ${OPSYS} == "SunOS"
CONFIGURE_ENV+= ac_cv_header_security_pam_modules_h=yes
.endif

.include "../../mk/dlopen.buildlink3.mk"

BUILDLINK_TRANSFORM+=   opt:-ldl:${BUILDLINK_LDADD.dl:M*}

BUILDLINK_API_DEPENDS.glib2+=   glib2>=2.26.0
.include "../../devel/glib2/schemas.mk"
.include "../../devel/gettext-lib/buildlink3.mk"
.include "../../devel/glib2/buildlink3.mk"
.include "../../security/libgcrypt/buildlink3.mk"
.include "../../security/libtasn1/buildlink3.mk"
.include "../../sysutils/dbus/buildlink3.mk"
.include "../../x11/gtk2/buildlink3.mk"
.include "../../mk/pam.buildlink3.mk"
.include "../../mk/bsd.pkg.mk"

あー(三回目

lib/39313、そういう事のようです

workaround をパチってきました。

Index: security/pam-yubico/Makefile
===================================================================
RCS file: /cvsroot/pkgsrc/security/pam-yubico/Makefile,v
retrieving revision 1.10
diff -u -p -r1.10 Makefile
--- security/pam-yubico/Makefile  10 Nov 2014 21:55:31 -0000  1.10
+++ security/pam-yubico/Makefile  23 Dec 2015 06:59:08 -0000
@@ -15,6 +15,11 @@ GNU_CONFIGURE=        yes
 USE_TOOLS+=        pkg-config
 USE_LIBTOOL=       yes
 
+# Workaround a bug with NetBSD's openpam
+# The bug is described in PR security/39313
+#
+CFLAGS.NetBSD+=        -DNO_STATIC_MODULES
+
 .include "../../security/libyubikey/buildlink3.mk"
 .include "../../security/ykclient/buildlink3.mk"
 .include "../../security/ykpers/buildlink3.mk"

Makefile にパッチをあてて pam_yubico パッケージを再作成します。

$ cd /usr/pkgsrc/security/pam-yubico
$ make clean
$ make update

新しい pam_yubico モジュールのシンボルを確認しておきます。

$ nm /usr/pkg/lib/security/pam_yubico.so
0000000000208620 d _DYNAMIC
0000000000208980 d _GLOBAL_OFFSET_TABLE_
                 w _Jv_RegisterClasses
0000000000208600 d __CTOR_LIST_END__
0000000000008050 r __FUNCTION__.4014
0000000000008030 r __FUNCTION__.4029
0000000000008170 r __FUNCTION__.4254
0000000000008150 r __FUNCTION__.4260
0000000000007ce0 r __FUNCTION__.6198
0000000000007d00 r __FUNCTION__.6211
0000000000007d20 r __FUNCTION__.6235
0000000000007d3a r __FUNCTION__.6252
0000000000007d50 r __FUNCTION__.6275
0000000000007d66 r __FUNCTION__.6289
0000000000007d70 r __FUNCTION__.6319
0000000000208d34 D __bss_start
                 w __cxa_finalize
                 w __deregister_frame_info@@GCC_3.0
0000000000208ce8 d __dso_handle
                 U __errno
                 U __fstat50
                 U __getpwnam50
                 w __register_frame_info@@GCC_3.0
                 U __sF
0000000000208d34 D _edata
0000000000208d38 D _end
0000000000006f60 T _fini
00000000000023b0 T _init
                 U _yk_errno_location@@LIBYKPERS_1.0
                 U ber_free
0000000000006033 T challenge_response
0000000000005ef9 T check_firmware_version
0000000000006bc0 t check_user_token.isra.1
                 U close
                 U fclose
                 U fdopen
                 U fflush
                 U fgets
                 U fileno
                 U fopen
                 U fprintf
                 U fread
                 U free
                 U fscanf
                 U fsync
                 U ftruncate
                 U fwrite
0000000000005ea3 T generate_random
0000000000005db0 T get_user_cfgfile_path
0000000000006159 T get_user_challenge_file
                 U getegid
                 U geteuid
                 U getgroups
000000000000600e T init_yubikey
                 U initgroups
                 U ldap_count_values_len
                 U ldap_err2string
                 U ldap_first_attribute
                 U ldap_first_entry
                 U ldap_get_values_len
                 U ldap_init
                 U ldap_initialize
                 U ldap_memfree
                 U ldap_msgfree
                 U ldap_next_attribute
                 U ldap_search_ext_s
                 U ldap_set_option
                 U ldap_simple_bind_s
                 U ldap_unbind
                 U ldap_value_free_len
00000000000062ad T load_chalresp_state
                 U malloc
                 U memcmp
                 U memcpy
                 U memset
                 U open
                 U pam_get_item
                 U pam_get_user
0000000000006830 T pam_modutil_drop_priv
0000000000006a62 T pam_modutil_regain_priv
                 U pam_set_data
                 U pam_set_item
0000000000002b30 T pam_sm_authenticate
0000000000005dac T pam_sm_setcred
                 U pam_strerror
                 U printf
                 U putchar
                 U rename
                 U rewind
                 U setegid
                 U seteuid
                 U setgroups
                 U snprintf
                 U sprintf
                 U sscanf
                 U strcmp
                 U strdup
                 U strerror
                 U strncmp
                 U strncpy
                 U strtok
                 U strtok_r
                 U syslog
000000000000663e T write_chalresp_state
                 U yk_challenge_response@@LIBYKPERS_1.8
                 U yk_close_key@@LIBYKPERS_1.0
                 U yk_get_serial@@LIBYKPERS_1.5
                 U yk_get_status@@LIBYKPERS_1.0
                 U yk_hmac_sha1@@LIBYKPERS_1.9
                 U yk_init@@LIBYKPERS_1.0
                 U yk_open_first_key@@LIBYKPERS_1.0
                 U yk_pbkdf2@@LIBYKPERS_1.0
                 U yk_release@@LIBYKPERS_1.0
                 U yk_strerror@@LIBYKPERS_1.0
                 U yk_usb_strerror@@LIBYKPERS_1.0
                 U ykclient_done@@Base
                 U ykclient_init@@Base
                 U ykclient_request@@Base
                 U ykclient_set_ca_path@@Base
                 U ykclient_set_client_b64@@Base
                 U ykclient_set_url_bases@@YKCLIENT_2.12
                 U ykclient_set_url_template@@Base
                 U ykclient_set_verify_signature@@Base
                 U ykclient_strerror@@Base
                 U ykds_alloc@@LIBYKPERS_1.0
                 U ykds_version_build@@LIBYKPERS_1.0
                 U ykds_version_major@@LIBYKPERS_1.0
                 U ykds_version_minor@@LIBYKPERS_1.0
                 U yubikey_hex_decode@@YUBIKEY_1.0
                 U yubikey_hex_encode@@YUBIKEY_1.0
                 U yubikey_hex_p@@YUBIKEY_1.5

ヤッター

再度試してみよう

気を取り直して再度ログインしてみましょう。

NetBSD/amd64 (koharu.myhome.nonakap.org) (ttyE1)

login: nonaka
debug: pam_yubico.c:764 (parse_cfg): called.
(snip...)
YubiKey for `nonaka': (ここで YubiKey にタッチする)
debug: pam_yubico.c:972 (pam_sm_authenticate): conv returned 44 bytes
(snip...)
Last login: Wed Dec 23 14:59:11 2015 on 192.168.0.103
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 7.99.24 (KOHARU) #3367: Sun Dec 20 14:07:44 JST 2015
nonaka@koaru$ 

ヤッター(二回目

pam_yubico モジュールのフラグに debug を指定しているのでデバッグログがちょっとうるさいですが、YubiKey 認証が実行されました。

ってあれ? そういえばパスワード入力無しでログインできてしまいました。

これはこれで大変便利なのですが今回は二要素認証したいという事なのでちょっと困ります。

再度 PAM 設定

これは YubiKey 関係無しに PAM の設定の話になります。

int128.hatenablog.com

/etc/pam.d/login に設定で二要素認証するようになっていなかったという事です。

auth     sufficient  pam_self.so     no_warn
auth        required    pam_nologin.so      no_warn
auth        sufficient  /usr/pkg/lib/security/pam_yubico.so id=XXX debug
auth        include     system

認証のバリエーションとしては以下の三つですかね

YubiKey→パスワード、YubiKey が成功したらログイン成功
auth     sufficient  pam_self.so     no_warn
auth        required    pam_nologin.so      no_warn
auth        sufficient  /usr/pkg/lib/security/pam_yubico.so id=XXX
auth        include     system
YubiKey→パスワード、両方成功したらログイン成功
auth     sufficient  pam_self.so     no_warn
auth        required    pam_nologin.so      no_warn
auth        required    /usr/pkg/lib/security/pam_yubico.so id=XXX
auth        include     system
パスワード→YubiKey、両方成功したらログイン成功
auth     sufficient  pam_self.so     no_warn
auth        required    pam_nologin.so      no_warn
auth        include     system
auth        required    /usr/pkg/lib/security/pam_yubico.so id=XXX

再々度試してみよう

「パスワード→YubiKey、両方成功したらログイン成功」の設定を使ってログインしてみます。

NetBSD/amd64 (koharu.myhome.nonakap.org) (ttyE1)

login: nonaka
Password:
YubiKey for `nonaka': (ここで YubiKey にタッチする)
Last login: Wed Dec 23 16:22:58 2015 on ttyE1
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 7.99.24 (KOHARU) #3367: Sun Dec 20 14:07:44 JST 2015
nonaka@koaru$ 

ヤッター(三回目

やっと当初の目的をとりあえず達成できました。

まとめ

コンソールログインだと二要素認証はそんなに便利でもないというか、その前にやる事が沢山あるだろうという気持ちでいっぱいです。

pam-u2f を使った U2F も試そうと思ったのですが、pkgsrc にパッケージが無かったので早々に諦めました。

pam_yubico を使った ssh 接続時の認証は多分 NetBSD 固有の設定は無いと思うのでググれ。

Authentication Using Challenge-ResponseNetBSD 固有の設定は無いと思うのでググれ。

しかし pkgsrc にもちゃんと使えないパッケージがあるんですね(棒

*1:書きました。nonakap.hatenablog.com