History log of /src/lib/libpam/modules/pam_ssh/
Revision (<<< Hide revision tags) (Show revision tags >>>) Date Author Comments
1.15 17-Dec-2025 riastradh

openssh: Do build and install compat libssh after all.

Even though it's not exposed for applications to _link_ against, it
is used by the dynamically _loadable_ pam_ssh module, which exists as
a compat module and therefore needs libssh as a compat library to be
installed somewhere. That somewhere will be
/usr/lib/${COMPAT_ARCH}/private.

Should fix problems like:

dependall ===> compat/sparc64/sparc/../../../lib/libpam/modules/pam_ssh
nbmake[11]: don't know how to make /home/source/ab/HEAD/src/crypto/external/bsd/openssh/lib/libssh.a. Stop

Verified in an amd64 build that the compat i386 pam_ssh.so is linked
correctly:

(chroot HEAD)# ldd /usr/lib/i386/security/pam_ssh.so.4
/usr/lib/i386/security/pam_ssh.so.4:
-lssh.50 => /usr/lib/i386/private/libssh.so.50
-lcrypto.16 => /usr/lib/i386/libcrypto.so.16
-lcrypt.1 => /usr/lib/i386/libcrypt.so.1
-lgcc_s.1 => /usr/lib/i386/libgcc_s.so.1
-lc.12 => /usr/lib/i386/libc.so.12
-lz.1 => /usr/lib/i386/libz.so.1

PR lib/58648: private shared libraries should go in /usr/lib/private,
not /usr/lib


Revision tags: perseant-exfatfs-base-20250801 netbsd-11-base
1.14 13-Jul-2025 christos

Get ready to handle the openssl move from bsd -> apache2


Revision tags: netbsd-10-1-RELEASE perseant-exfatfs-base-20240630 perseant-exfatfs-base netbsd-10-0-RELEASE netbsd-10-0-RC6 netbsd-10-0-RC5 netbsd-10-0-RC4 netbsd-10-0-RC3 netbsd-10-0-RC2 netbsd-10-0-RC1 netbsd-10-base cjep_sun2x-base1 cjep_sun2x-base cjep_staticlib_x-base1 cjep_staticlib_x-base phil-wifi-20200421 phil-wifi-20200411 is-mlppp-base phil-wifi-20200406
1.13 01-Mar-2020 christos

branches: 1.13.10;
Redo the sshsk_sign() stuff properly, but putting the helper in libssh.so


1.12 01-Mar-2020 christos

Add the sign client part.


Revision tags: netbsd-9-3-RELEASE netbsd-9-2-RELEASE netbsd-9-1-RELEASE netbsd-9-0-RELEASE netbsd-9-0-RC2 netbsd-9-0-RC1 phil-wifi-20191119 netbsd-9-base phil-wifi-20190609 pgoyette-compat-merge-20190127 pgoyette-compat-20190127 pgoyette-compat-20190118 pgoyette-compat-1226 pgoyette-compat-1126 pgoyette-compat-1020 pgoyette-compat-0930 pgoyette-compat-0906 pgoyette-compat-0728 phil-wifi-base pgoyette-compat-0625 pgoyette-compat-0521 pgoyette-compat-0502 pgoyette-compat-0422 pgoyette-compat-0415 pgoyette-compat-0407 pgoyette-compat-0330 pgoyette-compat-0322 pgoyette-compat-0315 pgoyette-compat-base
1.11 04-Feb-2018 christos

branches: 1.11.4; 1.11.6;
switch everyone to openssl.old


Revision tags: netbsd-8-3-RELEASE netbsd-8-2-RELEASE netbsd-8-1-RELEASE netbsd-8-1-RC1 netbsd-7-2-RELEASE netbsd-8-0-RELEASE netbsd-8-0-RC2 netbsd-8-0-RC1 netbsd-7-1-2-RELEASE netbsd-7-1-1-RELEASE matt-nb8-mediatek-base perseant-stdc-iso10646-base netbsd-8-base prg-localcount2-base3 prg-localcount2-base2 prg-localcount2-base1 prg-localcount2-base pgoyette-localcount-20170426 bouyer-socketcan-base1 pgoyette-localcount-20170320 netbsd-7-1-RELEASE netbsd-7-1-RC2 netbsd-7-nhusb-base-20170116 bouyer-socketcan-base pgoyette-localcount-20170107 netbsd-7-1-RC1 pgoyette-localcount-20161104 netbsd-7-0-2-RELEASE localcount-20160914 netbsd-7-nhusb-base pgoyette-localcount-20160806 pgoyette-localcount-20160726 pgoyette-localcount-base netbsd-7-0-1-RELEASE netbsd-7-0-RELEASE netbsd-7-0-RC3 netbsd-7-0-RC2 netbsd-7-0-RC1 netbsd-6-0-6-RELEASE netbsd-6-1-5-RELEASE netbsd-7-base yamt-pagecache-base9 yamt-pagecache-tag8 netbsd-6-1-4-RELEASE netbsd-6-0-5-RELEASE tls-earlyentropy-base riastradh-xf86-video-intel-2-7-1-pre-2-21-15 riastradh-drm2-base3 netbsd-6-1-3-RELEASE netbsd-6-0-4-RELEASE netbsd-6-1-2-RELEASE netbsd-6-0-3-RELEASE netbsd-6-1-1-RELEASE riastradh-drm2-base2 riastradh-drm2-base1 riastradh-drm2-base netbsd-6-0-2-RELEASE netbsd-6-1-RELEASE netbsd-6-1-RC4 netbsd-6-1-RC3 agc-symver-base netbsd-6-1-RC2 netbsd-6-1-RC1 yamt-pagecache-base8 netbsd-6-0-1-RELEASE yamt-pagecache-base7 matt-nb6-plus-nbase yamt-pagecache-base6 netbsd-6-0-RELEASE netbsd-6-0-RC2 tls-maxphys-base matt-nb6-plus-base netbsd-6-0-RC1 yamt-pagecache-base5 yamt-pagecache-base4 netbsd-6-base yamt-pagecache-base3 yamt-pagecache-base2 yamt-pagecache-base cherry-xenmp-base bouyer-quota2-nbase bouyer-quota2-base matt-mips64-premerge-20101231 matt-premerge-20091211
1.10 20-Jul-2009 christos

branches: 1.10.8; 1.10.14; 1.10.20;
use new openssh tree


1.9 20-Jul-2009 christos

use the proper libcrypto


1.8 09-Jun-2009 mrg

build libnetpgp and libssh earlier.
look for libssh in the right place.


Revision tags: netbsd-5-2-3-RELEASE netbsd-5-1-5-RELEASE netbsd-5-2-2-RELEASE netbsd-5-1-4-RELEASE netbsd-5-2-1-RELEASE netbsd-5-1-3-RELEASE netbsd-5-2-RELEASE netbsd-5-2-RC1 netbsd-5-1-2-RELEASE netbsd-5-1-1-RELEASE matt-nb5-mips64-premerge-20101231 matt-nb5-pq3-base netbsd-5-1-RELEASE netbsd-5-1-RC4 matt-nb5-mips64-k15 netbsd-5-1-RC3 netbsd-5-1-RC2 netbsd-5-1-RC1 netbsd-5-0-2-RELEASE matt-nb5-mips64-premerge-20091211 matt-nb5-mips64-u2-k2-k4-k7-k8-k9 matt-nb4-mips64-k7-u2a-k9b matt-nb5-mips64-u1-k1-k5 netbsd-5-0-1-RELEASE jym-xensuspend-nbase netbsd-5-0-RELEASE netbsd-5-0-RC4 netbsd-5-0-RC3 netbsd-5-0-RC2 jym-xensuspend-base netbsd-5-0-RC1 netbsd-5-base
1.7 27-Oct-2008 mrg

use LIBDPLIBS+= not =.


1.6 27-Oct-2008 mrg

don't set LIBDPLIBS in libpam/modules/Makefile - it is not necessary
and it interferes with the compat lib build. don't use LIB_ROOT_DIR.


Revision tags: matt-mips64-base2 mjf-devfs2-base netbsd-4-0-1-RELEASE wrstuden-revivesa-base-3 wrstuden-revivesa-base-2 wrstuden-fixsa-newbase wrstuden-revivesa-base-1 yamt-pf42-base4 yamt-pf42-base3 hpcarm-cleanup-nbase yamt-pf42-baseX yamt-pf42-base2 wrstuden-revivesa-base yamt-pf42-base keiichi-mipv6-base matt-armv6-nbase matt-armv6-prevmlocking wrstuden-fixsa-base-1 netbsd-4-0-RELEASE cube-autoconf-base netbsd-4-0-RC5 netbsd-4-0-RC4 netbsd-4-0-RC3 netbsd-4-0-RC2 netbsd-4-0-RC1 matt-armv6-base matt-mips64-base hpcarm-cleanup-base netbsd-3-1-1-RELEASE netbsd-3-0-3-RELEASE wrstuden-fixsa-base abandoned-netbsd-4-base netbsd-3-1-RELEASE netbsd-3-0-2-RELEASE netbsd-3-1-RC4 netbsd-3-1-RC3 netbsd-3-1-RC2 netbsd-3-1-RC1 netbsd-4-base netbsd-3-0-1-RELEASE netbsd-3-0-RELEASE netbsd-3-0-RC6 netbsd-3-0-RC5 netbsd-3-0-RC4 netbsd-3-0-RC3 netbsd-3-0-RC2 netbsd-3-0-RC1 netbsd-3-base
1.5 03-Jan-2005 lukem

Build & install pam_ssh.so.0 now that libssh is available for use.


1.4 29-Dec-2004 lukem

Use LIBDPLIBS to provide the list of libraries for the modules to depend
upon, because:
* it's MUCH quicker; no need to calculate the OBJDIRS of every library
we might require in every subdir.
(make obj drops from 21s to 3s on my system.)
* it's more robust when building to a fresh DESTDIR.


1.3 29-Dec-2004 christos

Link with libraries from the source build directory.


1.2 12-Dec-2004 christos

- NetBSD build glue
- Warning fixes
- RCSID's


1.1 12-Dec-2004 christos

branches: 1.1.1;
Initial revision


Revision tags: perseant-exfatfs-base-20250801 netbsd-11-base netbsd-10-1-RELEASE perseant-exfatfs-base-20240630 perseant-exfatfs-base netbsd-8-3-RELEASE netbsd-9-4-RELEASE netbsd-10-0-RELEASE netbsd-10-0-RC6 netbsd-10-0-RC5 netbsd-10-0-RC4 netbsd-10-0-RC3 netbsd-10-0-RC2 netbsd-10-0-RC1 netbsd-10-base netbsd-9-3-RELEASE cjep_sun2x-base1 cjep_sun2x-base cjep_staticlib_x-base1 netbsd-9-2-RELEASE cjep_staticlib_x-base netbsd-9-1-RELEASE phil-wifi-20200421 phil-wifi-20200411 is-mlppp-base phil-wifi-20200406 netbsd-8-2-RELEASE netbsd-9-0-RELEASE netbsd-9-0-RC2 netbsd-9-0-RC1 phil-wifi-20191119 netbsd-9-base phil-wifi-20190609 netbsd-8-1-RELEASE netbsd-8-1-RC1 pgoyette-compat-merge-20190127 pgoyette-compat-20190127 pgoyette-compat-20190118 pgoyette-compat-1226 pgoyette-compat-1126 pgoyette-compat-1020 pgoyette-compat-0930 pgoyette-compat-0906 netbsd-7-2-RELEASE pgoyette-compat-0728 netbsd-8-0-RELEASE phil-wifi-base pgoyette-compat-0625 netbsd-8-0-RC2 pgoyette-compat-0521 pgoyette-compat-0502 pgoyette-compat-0422 netbsd-8-0-RC1 pgoyette-compat-0415 pgoyette-compat-0407 pgoyette-compat-0330 pgoyette-compat-0322 pgoyette-compat-0315 netbsd-7-1-2-RELEASE pgoyette-compat-base netbsd-7-1-1-RELEASE matt-nb8-mediatek-base perseant-stdc-iso10646-base netbsd-8-base prg-localcount2-base3 prg-localcount2-base2 prg-localcount2-base1 prg-localcount2-base pgoyette-localcount-20170426 bouyer-socketcan-base1 pgoyette-localcount-20170320 netbsd-7-1-RELEASE netbsd-7-1-RC2 netbsd-7-nhusb-base-20170116 bouyer-socketcan-base pgoyette-localcount-20170107 netbsd-7-1-RC1 pgoyette-localcount-20161104 netbsd-7-0-2-RELEASE localcount-20160914 netbsd-7-nhusb-base pgoyette-localcount-20160806 pgoyette-localcount-20160726 pgoyette-localcount-base netbsd-7-0-1-RELEASE netbsd-7-0-RELEASE netbsd-7-0-RC3 netbsd-7-0-RC2 netbsd-7-0-RC1 netbsd-7-base yamt-pagecache-base9 tls-earlyentropy-base riastradh-xf86-video-intel-2-7-1-pre-2-21-15 tls-maxphys-base
1.8 18-Mar-2014 riastradh

Merge riastradh-drm2 to HEAD.


Revision tags: riastradh-drm2-base3 riastradh-drm2-base2 riastradh-drm2-base1
1.7 20-Jul-2013 wiz

Use Mt for email addresses.


Revision tags: netbsd-6-0-6-RELEASE netbsd-6-1-5-RELEASE netbsd-6-1-4-RELEASE netbsd-6-0-5-RELEASE netbsd-6-1-3-RELEASE netbsd-6-0-4-RELEASE netbsd-6-1-2-RELEASE netbsd-6-0-3-RELEASE netbsd-6-1-1-RELEASE riastradh-drm2-base netbsd-6-0-2-RELEASE netbsd-6-1-RELEASE netbsd-6-1-RC4 netbsd-6-1-RC3 agc-symver-base netbsd-6-1-RC2 netbsd-6-1-RC1 yamt-pagecache-base8 netbsd-6-0-1-RELEASE yamt-pagecache-base7 matt-nb6-plus-nbase yamt-pagecache-base6 netbsd-6-0-RELEASE netbsd-6-0-RC2 matt-nb6-plus-base netbsd-6-0-RC1 yamt-pagecache-base5 yamt-pagecache-base4 netbsd-6-base
1.6 16-Dec-2011 drochner

branches: 1.6.6; 1.6.10;
support ECDSA keys used by recent ssh


Revision tags: netbsd-5-2-3-RELEASE netbsd-5-1-5-RELEASE netbsd-5-2-2-RELEASE netbsd-5-1-4-RELEASE netbsd-5-2-1-RELEASE netbsd-5-1-3-RELEASE netbsd-5-2-RELEASE netbsd-5-2-RC1 netbsd-5-1-2-RELEASE netbsd-5-1-1-RELEASE yamt-pagecache-base3 yamt-pagecache-base2 yamt-pagecache-base cherry-xenmp-base bouyer-quota2-nbase bouyer-quota2-base matt-mips64-premerge-20101231 matt-nb5-mips64-premerge-20101231 matt-nb5-pq3-base netbsd-5-1-RELEASE netbsd-5-1-RC4 matt-nb5-mips64-k15 netbsd-5-1-RC3 netbsd-5-1-RC2 netbsd-5-1-RC1 netbsd-5-0-2-RELEASE matt-nb5-mips64-premerge-20091211 matt-premerge-20091211 matt-nb5-mips64-u2-k2-k4-k7-k8-k9 matt-nb4-mips64-k7-u2a-k9b matt-nb5-mips64-u1-k1-k5 netbsd-5-0-1-RELEASE jym-xensuspend-nbase netbsd-5-0-RELEASE netbsd-5-0-RC4 netbsd-5-0-RC3 netbsd-5-0-RC2 jym-xensuspend-base netbsd-5-0-RC1 netbsd-5-base matt-mips64-base2 mjf-devfs2-base netbsd-4-0-1-RELEASE wrstuden-revivesa-base-3 wrstuden-revivesa-base-2 wrstuden-fixsa-newbase wrstuden-revivesa-base-1 yamt-pf42-base4 yamt-pf42-base3 hpcarm-cleanup-nbase yamt-pf42-baseX yamt-pf42-base2 wrstuden-revivesa-base yamt-pf42-base keiichi-mipv6-base matt-armv6-nbase matt-armv6-prevmlocking wrstuden-fixsa-base-1 netbsd-4-0-RELEASE cube-autoconf-base netbsd-4-0-RC5 netbsd-4-0-RC4 netbsd-4-0-RC3 netbsd-4-0-RC2 netbsd-4-0-RC1 matt-armv6-base matt-mips64-base hpcarm-cleanup-base netbsd-3-1-1-RELEASE netbsd-3-0-3-RELEASE wrstuden-fixsa-base abandoned-netbsd-4-base netbsd-3-1-RELEASE netbsd-3-0-2-RELEASE netbsd-3-1-RC4 netbsd-3-1-RC3 netbsd-3-1-RC2 netbsd-3-1-RC1 netbsd-4-base netbsd-3-0-1-RELEASE netbsd-3-0-RELEASE netbsd-3-0-RC6 netbsd-3-0-RC5 netbsd-3-0-RC4 netbsd-3-0-RC3 netbsd-3-0-RC2 netbsd-3-0-RC1 netbsd-3-base
1.5 28-Feb-2005 wiz

branches: 1.5.48;
Bump date for new SECURITY CONSIDERATIONS section.


1.4 27-Feb-2005 thorpej

Add a SECURITY CONSIDRATIONS section.


1.3 26-Feb-2005 thorpej

Minor wording consistency nit.


1.2 12-Dec-2004 christos

- NetBSD build glue
- Warning fixes
- RCSID's


1.1 12-Dec-2004 christos

branches: 1.1.1;
Initial revision


1.32 12-Oct-2025 kre

Adapt call of ssh_add_identity_constrained() after openssh update

Note, this commit log entry belongs to the previous commit (1.31)
and is to fix my screwup in the previous commit, Apologies all.

With the recent openssh update, ssh_add_identity_constrained() has had
its "maxsign" parameter removed. Adapt the mapping macro from
ssh_add_identity() -> ssh_add_identity_constrained() to cope.

While here, change the octal 0 (00) that was being passed to as the
final (size_t) arg to be a nice simple decimal 0 instead.

This should fix the current build breakage.


1.31 12-Oct-2025 kre

/* $NetBSD: pam_ssh.c,v 1.30 2022/06/15 08:31:34 hannken Exp $ */

/*-
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by ThinkSec AS and
* NAI Labs, the Security Research Division of Network Associates, Inc.
* under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
* DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <sys/cdefs.h>
#ifdef __FreeBSD__
__FBSDID("$FreeBSD: src/lib/libpam/modules/pam_ssh/pam_ssh.c,v 1.40 2004/02/10 10:13:21 des Exp $");
#else
__RCSID("$NetBSD: pam_ssh.c,v 1.30 2022/06/15 08:31:34 hannken Exp $");
#endif

#include <sys/param.h>
#include <sys/wait.h>

#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define PAM_SM_AUTH
#define PAM_SM_SESSION

#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <security/openpam.h>

#include <openssl/evp.h>

#include "sshkey.h"
#include "sshbuf.h"
#include "authfd.h"
#include "authfile.h"

#define ssh_add_identity(auth, key, comment) \
ssh_add_identity_constrained(auth, key, comment, 0, 0, NULL, NULL, 0)

extern char **environ;

struct pam_ssh_key {
struct sshkey *key;
char *comment;
};

static const char *pam_ssh_prompt = "SSH passphrase: ";
static const char *pam_ssh_have_keys = "pam_ssh_have_keys";

static const char *pam_ssh_keyfiles[] = {
".ssh/identity", /* SSH1 RSA key */
".ssh/id_rsa", /* SSH2 RSA key */
".ssh/id_dsa", /* SSH2 DSA key */
".ssh/id_ecdsa", /* SSH2 ECDSA key */
NULL
};

static const char *pam_ssh_agent = "/usr/bin/ssh-agent";
static const char *const pam_ssh_agent_argv[] = { "ssh_agent", "-s", NULL };
static const char *const pam_ssh_agent_envp[] = { NULL };

/*
* Attempts to load a private key from the specified file in the specified
* directory, using the specified passphrase. If successful, returns a
* struct pam_ssh_key containing the key and its comment.
*/
static struct pam_ssh_key *
pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase,
int nullok)
{
struct pam_ssh_key *psk;
char fn[PATH_MAX];
int r;
char *comment;
struct sshkey *key;

if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn))
return (NULL);
comment = NULL;
/*
* If the key is unencrypted, OpenSSL ignores the passphrase, so
* it will seem like the user typed in the right one. This allows
* a user to circumvent nullok by providing a dummy passphrase.
* Verify that the key really *is* encrypted by trying to load it
* with an empty passphrase, and if the key is not encrypted,
* accept only an empty passphrase.
*/
r = sshkey_load_private(fn, "", &key, &comment);
if (r == 0 && !(*passphrase == '\0' && nullok)) {
openpam_log(PAM_LOG_DEBUG, "rejected unencrypted key from %s", fn);
sshkey_free(key);
free(comment);
return (NULL);
}
if (r)
r = sshkey_load_private(fn, passphrase, &key, &comment);
if (r) {
openpam_log(PAM_LOG_DEBUG, "failed to load key from %s", fn);
if (comment != NULL)
free(comment);
return (NULL);
}

openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s", comment, fn);
if ((psk = malloc(sizeof(*psk))) == NULL) {
sshkey_free(key);
free(comment);
return (NULL);
}
psk->key = key;
psk->comment = comment;
return (psk);
}

/*
* Wipes a private key and frees the associated resources.
*/
static void
pam_ssh_free_key(pam_handle_t *pamh __unused,
void *data, int pam_err __unused)
{
struct pam_ssh_key *psk;

psk = data;
sshkey_free(psk->key);
free(psk->comment);
free(psk);
}

PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
int argc __unused, const char *argv[] __unused)
{
const char **kfn, *passphrase, *user;
const void *item;
struct passwd *pwd, pwres;
struct pam_ssh_key *psk;
int nkeys, nullok, pam_err, pass;
char pwbuf[1024];

nullok = (openpam_get_option(pamh, "nullok") != NULL);

/* PEM is not loaded by default */
OpenSSL_add_all_algorithms();

/* get user name and home directory */
pam_err = pam_get_user(pamh, &user, NULL);
if (pam_err != PAM_SUCCESS)
return (pam_err);
if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
pwd == NULL)
return (PAM_USER_UNKNOWN);
if (pwd->pw_dir == NULL)
return (PAM_AUTH_ERR);

nkeys = 0;
pass = (pam_get_item(pamh, PAM_AUTHTOK, &item) == PAM_SUCCESS &&
item != NULL);
load_keys:
/* get passphrase */
pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
&passphrase, pam_ssh_prompt);
if (pam_err != PAM_SUCCESS)
return (pam_err);

/* switch to user credentials */
pam_err = openpam_borrow_cred(pamh, pwd);
if (pam_err != PAM_SUCCESS)
return (pam_err);

/* try to load keys from all keyfiles we know of */
for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) {
psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase, nullok);
if (psk != NULL) {
pam_set_data(pamh, *kfn, psk, pam_ssh_free_key);
++nkeys;
}
}

/* switch back to arbitrator credentials */
openpam_restore_cred(pamh);

/*
* If we tried an old token and didn't get anything, and
* try_first_pass was specified, try again after prompting the
* user for a new passphrase.
*/
if (nkeys == 0 && pass == 1 &&
openpam_get_option(pamh, "try_first_pass") != NULL) {
pam_set_item(pamh, PAM_AUTHTOK, NULL);
pass = 0;
goto load_keys;
}

/* no keys? */
if (nkeys == 0)
return (PAM_AUTH_ERR);

pam_set_data(pamh, pam_ssh_have_keys, NULL, NULL);
return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
int argc __unused, const char *argv[] __unused)
{

return (PAM_SUCCESS);
}

/*
* Parses a line from ssh-agent's output.
*/
static void
pam_ssh_process_agent_output(pam_handle_t *pamh, FILE *f)
{
char *line, *p, *key, *val;
size_t len;

while ((line = fgetln(f, &len)) != NULL) {
if (len < 4 || strncmp(line, "SSH_", 4) != 0)
continue;

/* find equal sign at end of key */
for (p = key = line; p < line + len; ++p)
if (*p == '=')
break;
if (p == line + len || *p != '=')
continue;
*p = '\0';

/* find semicolon at end of value */
for (val = ++p; p < line + len; ++p)
if (*p == ';')
break;
if (p == line + len || *p != ';')
continue;
*p = '\0';

/* store key-value pair in environment */
openpam_log(PAM_LOG_DEBUG, "got %s: %s", key, val);
pam_setenv(pamh, key, val, 1);
}
}

/*
* Starts an ssh agent and stores the environment variables derived from
* its output.
*/
static int
pam_ssh_start_agent(pam_handle_t *pamh, struct passwd *pwd)
{
int agent_pipe[2];
pid_t pid;
FILE *f;

/* get a pipe which we will use to read the agent's output */
if (pipe(agent_pipe) == -1)
return (PAM_SYSTEM_ERR);

/* start the agent */
openpam_log(PAM_LOG_DEBUG, "starting an ssh agent");
pid = fork();
if (pid == (pid_t)-1) {
/* failed */
close(agent_pipe[0]);
close(agent_pipe[1]);
return (PAM_SYSTEM_ERR);
}
if (pid == 0) {
#ifndef F_CLOSEM
int fd;
#endif
/* child: drop privs, close fds and start agent */
if (setgid(pwd->pw_gid) == -1) {
openpam_log(PAM_LOG_DEBUG, "%s: Cannot setgid %d (%s)",
__func__, (int)pwd->pw_gid, strerror(errno));
goto done;
}
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
openpam_log(PAM_LOG_DEBUG,
"%s: Cannot initgroups for %s (%s)",
__func__, pwd->pw_name, strerror(errno));
goto done;
}
if (setuid(pwd->pw_uid) == -1) {
openpam_log(PAM_LOG_DEBUG, "%s: Cannot setuid %d (%s)",
__func__, (int)pwd->pw_uid, strerror(errno));
goto done;
}
(void)close(STDIN_FILENO);
(void)open(_PATH_DEVNULL, O_RDONLY);
(void)dup2(agent_pipe[1], STDOUT_FILENO);
(void)dup2(agent_pipe[1], STDERR_FILENO);
#ifdef F_CLOSEM
(void)fcntl(3, F_CLOSEM, 0);
#else
for (fd = 3; fd < getdtablesize(); ++fd)
(void)close(fd);
#endif
(void)execve(pam_ssh_agent,
(char **)__UNCONST(pam_ssh_agent_argv),
(char **)__UNCONST(pam_ssh_agent_envp));
done:
_exit(127);
}

/* parent */
close(agent_pipe[1]);
if ((f = fdopen(agent_pipe[0], "r")) == NULL)
return (PAM_SYSTEM_ERR);
pam_ssh_process_agent_output(pamh, f);
fclose(f);

return (PAM_SUCCESS);
}

/*
* Adds previously stored keys to a running agent.
*/
static int
pam_ssh_add_keys_to_agent(pam_handle_t *pamh)
{
const struct pam_ssh_key *psk;
const char **kfn;
char **envlist, **env;
int pam_err;
int agent_fd;

/* switch to PAM environment */
envlist = environ;
if ((environ = pam_getenvlist(pamh)) == NULL) {
openpam_log(PAM_LOG_DEBUG, "%s: cannot get envlist",
__func__);
environ = envlist;
return (PAM_SYSTEM_ERR);
}

/* get a connection to the agent */
if (ssh_get_authentication_socket(&agent_fd) != 0) {
openpam_log(PAM_LOG_DEBUG,
"%s: cannot get authentication connection",
__func__);
pam_err = PAM_SYSTEM_ERR;
agent_fd = -1;
goto end;
}

/* look for keys to add to it */
for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) {
const void *vp;
pam_err = pam_get_data(pamh, *kfn, &vp);
psk = vp;
if (pam_err == PAM_SUCCESS && psk != NULL) {
if (ssh_add_identity(agent_fd, psk->key, psk->comment))
openpam_log(PAM_LOG_DEBUG,
"added %s to ssh agent", psk->comment);
else
openpam_log(PAM_LOG_DEBUG, "failed "
"to add %s to ssh agent", psk->comment);
/* we won't need the key again, so wipe it */
pam_set_data(pamh, *kfn, NULL, NULL);
}
}
pam_err = PAM_SUCCESS;
end:
/* disconnect from agent */
if (agent_fd != -1)
ssh_close_authentication_socket(agent_fd);

/* switch back to original environment */
for (env = environ; *env != NULL; ++env)
free(*env);
free(environ);
environ = envlist;

return (pam_err);
}

PAM_EXTERN int
pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
int argc __unused, const char *argv[] __unused)
{
struct passwd *pwd, pwres;
const char *user;
const void *data;
int pam_err = PAM_SUCCESS;
char pwbuf[1024];

/* no keys, no work */
if (pam_get_data(pamh, pam_ssh_have_keys, &data) != PAM_SUCCESS &&
openpam_get_option(pamh, "want_agent") == NULL)
return (PAM_SUCCESS);

/* switch to user credentials */
pam_err = pam_get_user(pamh, &user, NULL);
if (pam_err != PAM_SUCCESS)
return (pam_err);
if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
pwd == NULL)
return (PAM_USER_UNKNOWN);

/* start the agent */
pam_err = pam_ssh_start_agent(pamh, pwd);
if (pam_err != PAM_SUCCESS)
return pam_err;

pam_err = openpam_borrow_cred(pamh, pwd);
if (pam_err != PAM_SUCCESS)
return pam_err;

/* we have an agent, see if we can add any keys to it */
pam_err = pam_ssh_add_keys_to_agent(pamh);
if (pam_err != PAM_SUCCESS) {
/* XXX ignore failures */
openpam_log(PAM_LOG_DEBUG, "failed adding keys to ssh agent");
pam_err = PAM_SUCCESS;
}

openpam_restore_cred(pamh);
return pam_err;
}

PAM_EXTERN int
pam_sm_close_session(pam_handle_t *pamh, int flags __unused,
int argc __unused, const char *argv[] __unused)
{
const char *ssh_agent_pid;
char *end;
int status;
pid_t pid;

if ((ssh_agent_pid = pam_getenv(pamh, "SSH_AGENT_PID")) == NULL) {
openpam_log(PAM_LOG_DEBUG, "no ssh agent");
return (PAM_SUCCESS);
}
pid = (pid_t)strtol(ssh_agent_pid, &end, 10);
if (*ssh_agent_pid == '\0' || *end != '\0') {
openpam_log(PAM_LOG_DEBUG, "invalid ssh agent pid");
return (PAM_SESSION_ERR);
}
openpam_log(PAM_LOG_DEBUG, "killing ssh agent %d", (int)pid);
if (kill(pid, SIGTERM) == -1 ||
(waitpid(pid, &status, 0) == -1 && errno != ECHILD))
return (PAM_SYSTEM_ERR);
return (PAM_SUCCESS);
}

PAM_MODULE_ENTRY("pam_ssh");


Revision tags: perseant-exfatfs-base-20250801 netbsd-11-base netbsd-10-1-RELEASE perseant-exfatfs-base-20240630 perseant-exfatfs-base netbsd-10-0-RELEASE netbsd-10-0-RC6 netbsd-10-0-RC5 netbsd-10-0-RC4 netbsd-10-0-RC3 netbsd-10-0-RC2 netbsd-10-0-RC1 netbsd-10-base
1.30 15-Jun-2022 hannken

Set provider to NULL -- "pam" is not a valid security key helper library.
Now ssh-agent no longer fails key addition with

error: Cannot add provider: RSA is not an authenticator-hosted key


1.29 24-Feb-2022 christos

Add constrain arguments


Revision tags: cjep_sun2x-base1 cjep_sun2x-base cjep_staticlib_x-base1 cjep_staticlib_x-base phil-wifi-20200421 phil-wifi-20200411 is-mlppp-base phil-wifi-20200406
1.28 27-Feb-2020 christos

This takes a provider now


Revision tags: netbsd-9-3-RELEASE netbsd-9-2-RELEASE netbsd-9-1-RELEASE netbsd-9-0-RELEASE netbsd-9-0-RC2 netbsd-9-0-RC1 phil-wifi-20191119 netbsd-9-base phil-wifi-20190609
1.27 01-Jun-2019 mlelstv

branches: 1.27.2;
Fix key loading logic and add log message when rejecting an unencrypted key.


Revision tags: pgoyette-compat-20190127 pgoyette-compat-20190118 pgoyette-compat-1226 pgoyette-compat-1126 pgoyette-compat-1020 pgoyette-compat-0930 pgoyette-compat-0906
1.26 26-Aug-2018 christos

adjust to new libssh api.


Revision tags: pgoyette-compat-0728 phil-wifi-base pgoyette-compat-0625 pgoyette-compat-0521 pgoyette-compat-0502 pgoyette-compat-0422 pgoyette-compat-0415
1.25 07-Apr-2018 christos

branches: 1.25.2;
fix and use the macro.


1.24 07-Apr-2018 christos

function grew an extra argument now.


Revision tags: netbsd-8-3-RELEASE netbsd-8-2-RELEASE netbsd-8-1-RELEASE netbsd-8-1-RC1 netbsd-8-0-RELEASE netbsd-8-0-RC2 netbsd-8-0-RC1 pgoyette-compat-0407 pgoyette-compat-0330 pgoyette-compat-0322 pgoyette-compat-0315 pgoyette-compat-base matt-nb8-mediatek-base perseant-stdc-iso10646-base netbsd-8-base prg-localcount2-base3 prg-localcount2-base2 prg-localcount2-base1 prg-localcount2-base pgoyette-localcount-20170426 bouyer-socketcan-base1 pgoyette-localcount-20170320 bouyer-socketcan-base pgoyette-localcount-20170107 pgoyette-localcount-20161104 localcount-20160914 pgoyette-localcount-20160806 pgoyette-localcount-20160726 pgoyette-localcount-base
1.23 04-Apr-2015 christos

branches: 1.23.14;
Adapt to the new API.


Revision tags: netbsd-6-0-6-RELEASE netbsd-6-1-5-RELEASE netbsd-7-base yamt-pagecache-base9 netbsd-6-1-4-RELEASE netbsd-6-0-5-RELEASE tls-earlyentropy-base riastradh-xf86-video-intel-2-7-1-pre-2-21-15 riastradh-drm2-base3 netbsd-6-1-3-RELEASE netbsd-6-0-4-RELEASE netbsd-6-1-2-RELEASE netbsd-6-0-3-RELEASE netbsd-6-1-1-RELEASE riastradh-drm2-base2 riastradh-drm2-base1 riastradh-drm2-base netbsd-6-0-2-RELEASE netbsd-6-1-RELEASE netbsd-6-1-RC4 netbsd-6-1-RC3 agc-symver-base netbsd-6-1-RC2 netbsd-6-1-RC1 yamt-pagecache-base8 netbsd-6-0-1-RELEASE yamt-pagecache-base7 matt-nb6-plus-nbase yamt-pagecache-base6 netbsd-6-0-RELEASE netbsd-6-0-RC2 tls-maxphys-base matt-nb6-plus-base netbsd-6-0-RC1 yamt-pagecache-base5 yamt-pagecache-base4 netbsd-6-base
1.22 06-Jan-2012 drochner

branches: 1.22.2; 1.22.8; 1.22.14; 1.22.18;
pull in from FreeBSD rev.1.41: Narrow the use of user credentials.
(call pam_get_authtok() with caller's rights rather than user's)


1.21 03-Jan-2012 christos

avoid using %m in format.


1.20 16-Dec-2011 drochner

support ECDSA keys used by recent ssh


1.19 16-Dec-2011 drochner

disallow empty passphrases per default, and implement the "nullok"
option to allow it if the administator wishes, from FreeBSD


1.18 16-Dec-2011 drochner

-remove remainders of the misguided changes in revs 1.5-1.9
-iron out more unnecessary differences to FreeBSD


Revision tags: yamt-pagecache-base3 yamt-pagecache-base2 yamt-pagecache-base cherry-xenmp-base
1.17 06-May-2011 drochner

branches: 1.17.4;
remove excess newlines in debug output


Revision tags: bouyer-quota2-nbase bouyer-quota2-base matt-mips64-premerge-20101231
1.16 21-Nov-2010 adam

Use ssh_add_identity_constrained() instead of ssh_add_identity()


Revision tags: netbsd-5-2-3-RELEASE netbsd-5-1-5-RELEASE netbsd-5-2-2-RELEASE netbsd-5-1-4-RELEASE netbsd-5-2-1-RELEASE netbsd-5-1-3-RELEASE netbsd-5-2-RELEASE netbsd-5-2-RC1 netbsd-5-1-2-RELEASE netbsd-5-1-1-RELEASE matt-nb5-mips64-premerge-20101231 matt-nb5-pq3-base netbsd-5-1-RELEASE netbsd-5-1-RC4 matt-nb5-mips64-k15 netbsd-5-1-RC3 netbsd-5-1-RC2 netbsd-5-1-RC1 netbsd-5-0-2-RELEASE matt-nb5-mips64-premerge-20091211 matt-premerge-20091211 matt-nb5-mips64-u2-k2-k4-k7-k8-k9 matt-nb4-mips64-k7-u2a-k9b matt-nb5-mips64-u1-k1-k5 netbsd-5-0-1-RELEASE jym-xensuspend-nbase netbsd-5-0-RELEASE netbsd-5-0-RC4 netbsd-5-0-RC3 netbsd-5-0-RC2 jym-xensuspend-base netbsd-5-0-RC1 netbsd-5-base matt-mips64-base2 mjf-devfs2-base wrstuden-revivesa-base-3 wrstuden-revivesa-base-2 wrstuden-revivesa-base-1 yamt-pf42-base4 yamt-pf42-base3 hpcarm-cleanup-nbase yamt-pf42-baseX yamt-pf42-base2 wrstuden-revivesa-base yamt-pf42-base keiichi-mipv6-base matt-armv6-nbase hpcarm-cleanup-base
1.15 27-Jan-2008 christos

Fix compilation


Revision tags: cube-autoconf-base matt-armv6-base
1.14 15-Sep-2007 ragge

__FUNCTION__ -> __func__.


Revision tags: netbsd-4-0-1-RELEASE wrstuden-fixsa-newbase wrstuden-fixsa-base-1 netbsd-4-0-RELEASE netbsd-4-0-RC5 netbsd-4-0-RC4 netbsd-4-0-RC3 netbsd-4-0-RC2 netbsd-4-0-RC1 matt-mips64-base wrstuden-fixsa-base netbsd-4-base
1.13 29-Sep-2006 dogcow

branches: 1.13.8;
new ssh import requires another include


Revision tags: abandoned-netbsd-4-base
1.12 19-Mar-2006 jnemeth

Fix coverity run 5, issue 2018 -- memory leak.
Approved by christos.


1.11 19-Apr-2005 christos

check for pwd != in getpw*_r functions.


1.10 31-Mar-2005 thorpej

Use getpwnam_r().


1.9 17-Mar-2005 christos

remove debugging printf's


Revision tags: netbsd-3-base
1.8 14-Mar-2005 christos

branches: 1.8.2;
remove code to deal with authorized keys. it has no place here.


1.7 14-Mar-2005 christos

Go back to rev-1.5. This is better than what was there before, but I am
still uncertain about the proper way to dealing what keys to accept.


1.6 14-Mar-2005 christos

Revert previous. This is not the right fix.


1.5 14-Mar-2005 christos

Do not let keys that are not listed in authorized_keys participate
in authentication. Problem reported by Maximum Entropy.


1.4 27-Feb-2005 christos

NetBSD does not allow setuid(user) when euid=user, and ruid=0. Change
the logic for setting the uid/gid/groups for the agent around and also
add error checking. I.e. Don't exec the agent, if we could not set
the proper environment for it. Add a few more debugging lines. Now ssh
authentication works through xdm.


1.3 03-Jan-2005 lukem

s/ifndef/ifdef/ for __FreeBSD__


1.2 12-Dec-2004 christos

- NetBSD build glue
- Warning fixes
- RCSID's


1.1 12-Dec-2004 christos

branches: 1.1.1;
Initial revision