aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2002-03-17 15:01:29 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2002-03-17 15:01:29 +0000
commit9167caac56eb0dbcb6ce8c80c8ed30bd4b5fcbd5 (patch)
treea2c19973567893c19ef411550411799612c77ae4 /lib
parent236c08a5bcad524da4829074abf67755937e68ec (diff)
downloadsrc-9167caac56eb0dbcb6ce8c80c8ed30bd4b5fcbd5.tar.gz
src-9167caac56eb0dbcb6ce8c80c8ed30bd4b5fcbd5.zip
This commit was manufactured by cvs2svn to create branch 'RELENG_4'.
Notes
Notes: svn path=/stable/4/; revision=92504
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/gen/readpassphrase.3187
-rw-r--r--lib/libpam/modules/pam_opie/pam_opie.8123
-rw-r--r--lib/libpam/modules/pam_ssh/pam_ssh.8148
-rw-r--r--lib/libpam/modules/pam_ssh/pam_ssh.c595
4 files changed, 1053 insertions, 0 deletions
diff --git a/lib/libc/gen/readpassphrase.3 b/lib/libc/gen/readpassphrase.3
new file mode 100644
index 000000000000..cfa6cf0631db
--- /dev/null
+++ b/lib/libc/gen/readpassphrase.3
@@ -0,0 +1,187 @@
+.\" $OpenBSD: readpassphrase.3,v 1.7 2001/12/15 15:37:51 millert Exp $
+.\"
+.\" Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
+.\" All rights reserved.
+.\"
+.\" 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 ``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 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 7, 2001
+.Dt READPASSPHRASE 3
+.Os
+.Sh NAME
+.Nm readpassphrase
+.Nd get a passphrase from the user
+.Sh SYNOPSIS
+.In readpassphrase.h
+.Ft "char *"
+.Fn readpassphrase "const char *prompt" "char *buf" "size_t bufsiz" "int flags"
+.Sh DESCRIPTION
+The
+.Fn readpassphrase
+function displays a prompt to, and reads in a passphrase from,
+.Pa /dev/tty .
+If this file is inaccessible
+and the
+.Dv RPP_REQUIRE_TTY
+flag is not set,
+.Fn readpassphrase
+displays the prompt on the standard error output and reads from the standard
+input.
+In this case it is generally not possible to turn off echo.
+.Pp
+Up to
+.Fa bufsiz
+\- 1 characters (one is for the
+.Dv NUL )
+are read into the provided buffer
+.Fa buf .
+Any additional
+characters and the terminating newline (or return) character are discarded.
+.Pp
+.Fn readpassphrase
+takes the following optional
+.Fa flags :
+.Pp
+.Bl -tag -width ".Dv RPP_REQUIRE_TTY" -compact
+.It Dv RPP_ECHO_OFF
+turn off echo (default behavior)
+.It Dv RPP_ECHO_ON
+leave echo on
+.It Dv RPP_REQUIRE_TTY
+fail if there is no tty
+.It Dv RPP_FORCELOWER
+force input to lower case
+.It Dv RPP_FORCEUPPER
+force input to upper case
+.It Dv RPP_SEVENBIT
+strip the high bit from input
+.El
+.Pp
+The calling process should zero the passphrase as soon as possible to
+avoid leaving the cleartext passphrase visible in the process's address
+space.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn readpassphrase
+returns a pointer to the null-terminated passphrase.
+If an error is encountered, the terminal state is restored and
+a
+.Dv NULL
+pointer is returned.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINTR
+The
+.Fn readpassphrase
+function was interrupted by a signal.
+.It Bq Er EINVAL
+The
+.Fa bufsiz
+argument was zero.
+.It Bq Er EIO
+The process is a member of a background process attempting to read
+from its controlling terminal, the process is ignoring or blocking
+the
+.Dv SIGTTIN
+signal or the process group is orphaned.
+.It Bq Er EMFILE
+The process has already reached its limit for open file descriptors.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er ENOTTY
+There is no controlling terminal and the
+.Dv RPP_REQUIRE_TTY
+flag was specified.
+.El
+.Sh EXAMPLES
+The following code fragment will read a passphrase from
+.Pa /dev/tty
+into the buffer
+.Fa passbuf .
+.Bd -literal -offset indent
+char passbuf[1024];
+
+\&...
+
+if (readpassphrase("Response: ", passbuf, sizeof(passbuf),
+ RPP_REQUIRE_TTY) == NULL)
+ errx(1, "unable to read passphrase");
+
+if (compare(transform(passbuf), epass) != 0)
+ errx(1, "bad passphrase");
+
+\&...
+
+memset(passbuf, 0, sizeof(passbuf));
+.Ed
+.Sh SIGNALS
+.Fn readpassphrase
+will catch the following signals:
+.Pp
+.Bl -tag -compact
+.It Dv SIGINT
+.It Dv SIGHUP
+.It Dv SIGQUIT
+.It Dv SIGTERM
+.It Dv SIGTSTP
+.It Dv SIGTTIN
+.It Dv SIGTTOU
+.El
+.Pp
+When one of the above signals is intercepted, terminal echo will
+be restored if it had previously been turned off.
+If a signal handler was installed for the signal when
+.Fn readpassphrase
+was called that handler is then executed.
+If no handler was previously installed for the signal then the
+default action is taken as per
+.Xr sigaction 2 .
+.Pp
+The
+.Dv SIGTSTP , SIGTTIN ,
+and
+.Dv SIGTTOU
+signals (stop signal generated from keyboard or due to terminal I/O
+from a background proccess) are treated specially.
+When the process is resumed after it has been stopped,
+.Fn readpassphrase
+will reprint the prompt and the user may then enter a passphrase.
+.Sh FILES
+.Bl -tag -width ".Pa /dev/tty" -compact
+.It Pa /dev/tty
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr getpass 3
+.Sh STANDARDS
+The
+.Fn readpassphrase
+function is an
+extension and should not be used if portability is desired.
+.Sh HISTORY
+The
+.Fn readpassphrase
+function first appeared in
+.Ox 2.9 .
diff --git a/lib/libpam/modules/pam_opie/pam_opie.8 b/lib/libpam/modules/pam_opie/pam_opie.8
new file mode 100644
index 000000000000..bae696d1b16e
--- /dev/null
+++ b/lib/libpam/modules/pam_opie/pam_opie.8
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 7, 2001
+.Dt PAM_OPIE 8
+.Os
+.Sh NAME
+.Nm pam_opie
+.Nd OPIE PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_opie
+.Op Ar options
+.Sh DESCRIPTION
+The OPIE authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+that of authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+It also provides a null function for session management.
+.Pp
+Note that this module does not enforce
+.Xr opieaccess 5
+checks.
+There is a separate module,
+.Xr pam_opieaccess 8 ,
+for this purpose.
+.Ss OPIE Authentication Module
+The OPIE authentication component
+provides functions to verify the identity of a user
+.Pq Fn pam_sm_authenticate ,
+which obtains the relevant
+.Xr opie 4
+credentials.
+It provides the user with an OPIE challenge,
+and verifies that this is correct with
+.Xr opiechallenge 3 .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm auth_as_self"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm auth_as_self
+This option will require the user
+to authenticate themself as the user
+given by
+.Xr getlogin 2 ,
+not as the account they are attempting to access.
+This is primarily for services like
+.Xr su 1 ,
+where the user's ability to retype
+their own password
+might be deemed sufficient.
+.It Cm no_fake_prompts
+Do not generate fake challenges for users who do not have an OPIE key.
+Note that this can leak information to a hypothetical attacker about
+who uses OPIE and who does not, but it can be useful on systems where
+some users want to use OPIE but most do not.
+.El
+.Pp
+Note that
+.Nm
+ignores the standard options
+.Cm try_first_pass
+and
+.Cm use_first_pass ,
+since a challenge must be generated before the user can submit a valid
+response.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/opiekeys" -compact
+.It Pa /etc/opiekeys
+default OPIE password database.
+.El
+.Sh SEE ALSO
+.Xr passwd 1 ,
+.Xr getlogin 2 ,
+.Xr opiechallenge 3 ,
+.Xr syslog 3 ,
+.Xr opie 4 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.8 b/lib/libpam/modules/pam_ssh/pam_ssh.8
new file mode 100644
index 000000000000..a932d0255671
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/pam_ssh.8
@@ -0,0 +1,148 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 26, 2001
+.Dt PAM_SSH 8
+.Os
+.Sh NAME
+.Nm pam_ssh
+.Nd SSH PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_ssh
+.Op Ar options
+.Sh DESCRIPTION
+The
+SSH
+authentication service module for PAM,
+.Nm
+provides functionality for two PAM categories:
+authentication
+and session management.
+In terms of the
+.Ar module-type
+parameter, they are the
+.Dq Li auth
+and
+.Dq Li session
+features.
+It also provides null functions for the remaining categories.
+.Ss SSH Authentication Module
+The
+SSH
+authentication component
+provides a function to verify the identity of a user
+.Pq Fn pam_sm_authenticate ,
+by prompting the user for a passphrase and verifying that it can
+decrypt the target user's SSH key using that passphrase.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm use_first_pass
+If the authentication module
+is not the first in the stack,
+and a previous module
+obtained the user's password,
+that password is used
+to authenticate the user.
+If this fails,
+the authentication module returns failure
+without prompting the user for a password.
+This option has no effect
+if the authentication module
+is the first in the stack,
+or if no previous modules
+obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option,
+except that if the previously obtained password fails,
+the user is prompted for another password.
+.El
+.Ss SSH Session Management Module
+The
+SSH
+session management component
+provides functions to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+The
+.Fn pam_sm_open_session
+function starts an SSH agent,
+passing it any private keys it decrypted
+during the authentication phase,
+and sets the environment variables
+the agent specifies.
+The
+.Fn pam_sm_close_session
+function kills the previously started SSH agent
+by sending it a
+.Dv SIGTERM .
+.Pp
+The following options may be passed to the session management module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa $HOME/.ssh2/id_dsa_*" -compact
+.It Pa $HOME/.ssh/identity
+SSH1/OpenSSH RSA key.
+.It Pa $HOME/.ssh/id_dsa
+OpenSSH DSA key.
+.It Pa $HOME/.ssh2/id_rsa_*
+SSH2 RSA keys.
+.It Pa $HOME/.ssh2/id_dsa_*
+SSH2 DSA keys.
+.El
+.Sh SEE ALSO
+.Xr ssh-agent 1 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.c b/lib/libpam/modules/pam_ssh/pam_ssh.c
new file mode 100644
index 000000000000..7285c79aa3db
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/pam_ssh.c
@@ -0,0 +1,595 @@
+/*-
+ * Copyright (c) 1999, 2000 Andrew J. Korty
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <dirent.h>
+#include <pwd.h>
+#include <signal.h>
+#include <ssh.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#include <openssl/dsa.h>
+#include <openssl/evp.h>
+
+#include "key.h"
+#include "authfd.h"
+#include "authfile.h"
+#include "log.h"
+#include "pam_ssh.h"
+
+static int auth_via_key(pam_handle_t *, int, const char *, const char *, const struct passwd *, const char *);
+static void key_cleanup(pam_handle_t *, void *, int);
+static void ssh_cleanup(pam_handle_t *, void *, int);
+
+/*
+ * Generic cleanup function for SSH "Key" type.
+ */
+
+static void
+key_cleanup(pam_handle_t *pamh __unused, void *data, int error_status __unused)
+{
+ if (data)
+ key_free(data);
+}
+
+
+/*
+ * Generic PAM cleanup function for this module.
+ */
+
+static void
+ssh_cleanup(pam_handle_t *pamh __unused, void *data, int error_status __unused)
+{
+ if (data)
+ free(data);
+}
+
+
+/*
+ * Authenticate a user's key by trying to decrypt it with the password
+ * provided. The key and its comment are then stored for later
+ * retrieval by the session phase. An increasing index is embedded in
+ * the PAM variable names so this function may be called multiple times
+ * for multiple keys.
+ */
+
+static int
+auth_via_key(pam_handle_t *pamh, int type, const char *file,
+ const char *dir, const struct passwd *user, const char *pass)
+{
+ char *comment; /* private key comment */
+ char *data_name; /* PAM state */
+ static int indx = 0; /* for saved keys */
+ Key *key; /* user's key */
+ char *path; /* to key files */
+ int retval; /* from calls */
+ uid_t saved_uid; /* caller's uid */
+
+ /* locate the user's private key file */
+ if (!asprintf(&path, "%s/%s", dir, file)) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ return PAM_SERVICE_ERR;
+ }
+ saved_uid = geteuid();
+ /*
+ * Try to decrypt the private key with the passphrase provided.
+ * If success, the user is authenticated.
+ */
+ seteuid(user->pw_uid);
+ key = key_load_private_type(type, path, pass, &comment);
+ free(path);
+ seteuid(saved_uid);
+ if (key == NULL)
+ return PAM_AUTH_ERR;
+ /*
+ * Save the key and comment to pass to ssh-agent in the session
+ * phase.
+ */
+ if (!asprintf(&data_name, "ssh_private_key_%d", indx)) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ free(comment);
+ return PAM_SERVICE_ERR;
+ }
+ retval = pam_set_data(pamh, data_name, key, key_cleanup);
+ free(data_name);
+ if (retval != PAM_SUCCESS) {
+ key_free(key);
+ free(comment);
+ return retval;
+ }
+ if (!asprintf(&data_name, "ssh_key_comment_%d", indx)) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ free(comment);
+ return PAM_SERVICE_ERR;
+ }
+ retval = pam_set_data(pamh, data_name, comment, ssh_cleanup);
+ free(data_name);
+ if (retval != PAM_SUCCESS) {
+ free(comment);
+ return retval;
+ }
+ ++indx;
+ return PAM_SUCCESS;
+}
+
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, int argc, const char **argv)
+{
+ struct options options; /* module options */
+ int authenticated; /* user authenticated? */
+ char *dotdir; /* .ssh2 dir name */
+ struct dirent *dotdir_ent; /* .ssh2 dir entry */
+ DIR *dotdir_p; /* .ssh2 dir pointer */
+ const char *pass; /* passphrase */
+ struct passwd *pwd; /* user's passwd entry */
+ struct passwd *pwd_keep; /* our own copy */
+ int retval; /* from calls */
+ int pam_auth_dsa; /* Authorised via DSA */
+ int pam_auth_rsa; /* Authorised via RSA */
+ const char *user; /* username */
+
+ pam_std_option(&options, NULL, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ pwd = getpwnam(user);
+ if (pwd == NULL || pwd->pw_dir == NULL)
+ /* delay? */
+ PAM_RETURN(PAM_AUTH_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ /*
+ * Pass prompt message to application and receive
+ * passphrase.
+ */
+ retval = pam_get_authtok(pamh, &pass, NEED_PASSPHRASE);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ OpenSSL_add_all_algorithms(); /* required for DSA */
+
+ PAM_LOG("Got passphrase");
+
+ /*
+ * Either the DSA or the RSA key will authenticate us, but if
+ * we can decrypt both, we'll do so here so we can cache them in
+ * the session phase.
+ */
+ if (!asprintf(&dotdir, "%s/%s", pwd->pw_dir, SSH_CLIENT_DIR)) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ pam_auth_dsa = auth_via_key(pamh, KEY_DSA, SSH_CLIENT_ID_DSA, dotdir,
+ pwd, pass);
+ pam_auth_rsa = auth_via_key(pamh, KEY_RSA1, SSH_CLIENT_IDENTITY, dotdir,
+ pwd, pass);
+ authenticated = 0;
+ if (pam_auth_dsa == PAM_SUCCESS)
+ authenticated++;
+ if (pam_auth_rsa == PAM_SUCCESS)
+ authenticated++;
+
+ PAM_LOG("Done pre-authenticating; got %d", authenticated);
+
+ /*
+ * Compatibility with SSH2 from SSH Communications Security.
+ */
+ if (!asprintf(&dotdir, "%s/%s", pwd->pw_dir, SSH2_CLIENT_DIR)) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ /*
+ * Try to load anything that looks like a private key. For
+ * now, we only support DSA and RSA keys.
+ */
+ dotdir_p = opendir(dotdir);
+ while (dotdir_p && (dotdir_ent = readdir(dotdir_p))) {
+ /* skip public keys */
+ if (strcmp(&dotdir_ent->d_name[dotdir_ent->d_namlen -
+ strlen(SSH2_PUB_SUFFIX)], SSH2_PUB_SUFFIX) == 0)
+ continue;
+ /* DSA keys */
+ if (strncmp(dotdir_ent->d_name, SSH2_DSA_PREFIX,
+ strlen(SSH2_DSA_PREFIX)) == 0)
+ retval = auth_via_key(pamh, KEY_DSA,
+ dotdir_ent->d_name, dotdir, pwd, pass);
+ /* RSA keys */
+ else if (strncmp(dotdir_ent->d_name, SSH2_RSA_PREFIX,
+ strlen(SSH2_RSA_PREFIX)) == 0)
+ retval = auth_via_key(pamh, KEY_RSA,
+ dotdir_ent->d_name, dotdir, pwd, pass);
+ /* skip other files */
+ else
+ continue;
+ authenticated += (retval == PAM_SUCCESS);
+ }
+ if (!authenticated) {
+ PAM_VERBOSE_ERROR("SSH authentication refused");
+ PAM_RETURN(PAM_AUTH_ERR);
+ }
+
+ PAM_LOG("Done authenticating; got %d", authenticated);
+
+ /*
+ * Copy the passwd entry (in case successive calls are made)
+ * and save it for the session phase.
+ */
+ pwd_keep = malloc(sizeof *pwd);
+ if (pwd_keep == NULL) {
+ syslog(LOG_CRIT, "%m");
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ memcpy(pwd_keep, pwd, sizeof *pwd_keep);
+ retval = pam_set_data(pamh, "ssh_passwd_entry", pwd_keep, ssh_cleanup);
+ if (retval != PAM_SUCCESS) {
+ free(pwd_keep);
+ PAM_RETURN(retval);
+ }
+
+ PAM_LOG("Saved ssh_passwd_entry");
+
+ PAM_RETURN(PAM_SUCCESS);
+}
+
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
+{
+ struct options options; /* module options */
+
+ pam_std_option(&options, NULL, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ PAM_RETURN(PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused, int argc ,const char **argv)
+{
+ struct options options;
+
+ pam_std_option(&options, NULL, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ PAM_RETURN(PAM_IGNORE);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
+{
+ struct options options;
+
+ pam_std_option(&options, NULL, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ PAM_RETURN(PAM_IGNORE);
+}
+
+typedef AuthenticationConnection AC;
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags __unused, int argc, const char **argv)
+{
+ struct options options; /* module options */
+ AC *ac; /* to ssh-agent */
+ char *agent_socket; /* agent socket */
+ char *comment; /* on private key */
+ char *env_end; /* end of env */
+ char *env_file; /* to store env */
+ FILE *env_fp; /* env_file handle */
+ char *env_value; /* envariable value */
+ char *data_name; /* PAM state */
+ int final; /* final return value */
+ int indx; /* for saved keys */
+ Key *key; /* user's private key */
+ FILE *lpipe; /* ssh-agent handle */
+ struct passwd *pwd; /* user's passwd entry */
+ int retval; /* from calls */
+ uid_t saved_uid; /* caller's uid */
+ const char *tty; /* tty or display name */
+ char hname[MAXHOSTNAMELEN]; /* local hostname */
+ char env_string[BUFSIZ]; /* environment string */
+
+ pam_std_option(&options, NULL, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ /* dump output of ssh-agent in ~/.ssh */
+ retval = pam_get_data(pamh, "ssh_passwd_entry", (const void **)&pwd);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ PAM_LOG("Got ssh_passwd_entry");
+
+ /* use the tty or X display name in the filename */
+ retval = pam_get_item(pamh, PAM_TTY, (const void **)&tty);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ PAM_LOG("Got TTY");
+
+ if (gethostname(hname, sizeof hname) == 0) {
+ if (asprintf(&env_file, "%s/.ssh/agent-%s%s%s",
+ pwd->pw_dir, hname, *tty == ':' ? "" : ":", tty)
+ == -1) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ }
+ else if (asprintf(&env_file, "%s/.ssh/agent-%s", pwd->pw_dir,
+ tty) == -1) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Got env_file: %s", env_file);
+
+ /* save the filename so we can delete the file on session close */
+ retval = pam_set_data(pamh, "ssh_agent_env", env_file, ssh_cleanup);
+ if (retval != PAM_SUCCESS) {
+ free(env_file);
+ PAM_RETURN(retval);
+ }
+
+ PAM_LOG("Saved env_file");
+
+ /* start the agent as the user */
+ saved_uid = geteuid();
+ seteuid(pwd->pw_uid);
+ env_fp = fopen(env_file, "w");
+ if (env_fp != NULL)
+ chmod(env_file, S_IRUSR);
+ lpipe = popen(SSH_AGENT, "r");
+ seteuid(saved_uid);
+ if (!lpipe) {
+ syslog(LOG_ERR, "%s: %s: %m", MODULE_NAME, SSH_AGENT);
+ if (env_fp)
+ fclose(env_fp);
+ PAM_RETURN(PAM_SESSION_ERR);
+ }
+
+ PAM_LOG("Agent started as user");
+
+ /*
+ * Save environment for application with pam_putenv().
+ */
+ agent_socket = NULL;
+ while (fgets(env_string, sizeof env_string, lpipe)) {
+ if (env_fp)
+ fputs(env_string, env_fp);
+ env_value = strchr(env_string, '=');
+ if (env_value == NULL)
+ continue;
+ env_end = strchr(env_value, ';');
+ if (env_end == NULL)
+ continue;
+ *env_end = '\0';
+ /* pass to the application ... */
+ retval = pam_putenv(pamh, env_string);
+ if (retval != PAM_SUCCESS) {
+ pclose(lpipe);
+ if (env_fp)
+ fclose(env_fp);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Put to environment: %s", env_string);
+
+ *env_value++ = '\0';
+ if (strcmp(&env_string[strlen(env_string) -
+ strlen(ENV_SOCKET_SUFFIX)], ENV_SOCKET_SUFFIX) == 0) {
+ agent_socket = strdup(env_value);
+ if (agent_socket == NULL) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ }
+ else if (strcmp(&env_string[strlen(env_string) -
+ strlen(ENV_PID_SUFFIX)], ENV_PID_SUFFIX) == 0) {
+ env_value = strdup(env_value);
+ if (env_value == NULL) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ retval = pam_set_data(pamh, "ssh_agent_pid",
+ env_value, ssh_cleanup);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ PAM_LOG("Environment write successful");
+ }
+ }
+ if (env_fp)
+ fclose(env_fp);
+ retval = pclose(lpipe);
+ switch (retval) {
+ case -1:
+ syslog(LOG_ERR, "%s: %s: %m", MODULE_NAME, SSH_AGENT);
+ PAM_RETURN(PAM_SESSION_ERR);
+ case 0:
+ break;
+ case 127:
+ syslog(LOG_ERR, "%s: cannot execute %s", MODULE_NAME,
+ SSH_AGENT);
+ PAM_RETURN(PAM_SESSION_ERR);
+ default:
+ syslog(LOG_ERR, "%s: %s exited %s %d", MODULE_NAME,
+ SSH_AGENT, WIFSIGNALED(retval) ? "on signal" :
+ "with status", WIFSIGNALED(retval) ? WTERMSIG(retval) :
+ WEXITSTATUS(retval));
+ PAM_RETURN(PAM_SESSION_ERR);
+ }
+ if (agent_socket == NULL)
+ PAM_RETURN(PAM_SESSION_ERR);
+
+ PAM_LOG("Environment saved");
+
+ /*
+ * Connect to the agent.
+ *
+ * XXX Because ssh_get_authentication_connection() gets the
+ * XXX agent parameters from the environment, we have to
+ * XXX temporarily replace the environment with the PAM
+ * XXX environment list. This is a hack.
+ */
+ {
+ extern char **environ;
+ char **saved, **evp;
+
+ saved = environ;
+ if ((environ = pam_getenvlist(pamh)) == NULL) {
+ environ = saved;
+ syslog(LOG_ERR, "%s: %m", MODULE_NAME);
+ PAM_RETURN(PAM_BUF_ERR);
+ }
+ ac = ssh_get_authentication_connection();
+ for (evp = environ; *evp; evp++)
+ free(*evp);
+ free(environ);
+ environ = saved;
+ }
+ if (!ac) {
+ syslog(LOG_ERR, "%s: %s: %m", MODULE_NAME, agent_socket);
+ PAM_RETURN(PAM_SESSION_ERR);
+ }
+
+ PAM_LOG("Connected to agent");
+
+ /* hand off each private key to the agent */
+ final = 0;
+ for (indx = 0; ; indx++) {
+ if (!asprintf(&data_name, "ssh_private_key_%d", indx)) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ ssh_close_authentication_connection(ac);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ retval = pam_get_data(pamh, data_name, (const void **)&key);
+ free(data_name);
+ if (retval != PAM_SUCCESS)
+ break;
+ if (!asprintf(&data_name, "ssh_key_comment_%d", indx)) {
+ syslog(LOG_CRIT, "%s: %m", MODULE_NAME);
+ ssh_close_authentication_connection(ac);
+ PAM_RETURN(PAM_SERVICE_ERR);
+ }
+ retval = pam_get_data(pamh, data_name, (const void **)&comment);
+ free(data_name);
+ if (retval != PAM_SUCCESS)
+ break;
+ retval = ssh_add_identity(ac, key, comment);
+ if (!final)
+ final = retval;
+ }
+ ssh_close_authentication_connection(ac);
+
+ PAM_LOG("Keys handed off");
+
+ PAM_RETURN(final ? PAM_SUCCESS : PAM_SESSION_ERR);
+}
+
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags __unused, int argc, const char **argv)
+{
+ struct options options; /* module options */
+ const char *env_file; /* ssh-agent environment */
+ pid_t pid; /* ssh-agent process id */
+ int retval; /* from calls */
+ const char *ssh_agent_pid; /* ssh-agent pid string */
+
+ pam_std_option(&options, NULL, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ /* retrieve environment filename, then remove the file */
+ retval = pam_get_data(pamh, "ssh_agent_env", (const void **)&env_file);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ unlink(env_file);
+
+ PAM_LOG("Got ssh_agent_env");
+
+ /* retrieve the agent's process id */
+ retval = pam_get_data(pamh, "ssh_agent_pid", (const void **)&ssh_agent_pid);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ PAM_LOG("Got ssh_agent_pid");
+
+ /*
+ * Kill the agent. SSH2 from SSH Communications Security does
+ * not have a -k option, so we just call kill().
+ */
+ pid = atoi(ssh_agent_pid);
+ if (pid <= 0)
+ PAM_RETURN(PAM_SESSION_ERR);
+ if (kill(pid, SIGTERM) != 0) {
+ syslog(LOG_ERR, "%s: %s: %m", MODULE_NAME, ssh_agent_pid);
+ PAM_RETURN(PAM_SESSION_ERR);
+ }
+
+ PAM_LOG("Agent killed");
+
+ PAM_RETURN(PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_ssh");