summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ssh/sshd
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/ssh/sshd')
-rw-r--r--usr/src/cmd/ssh/sshd/Makefile119
-rw-r--r--usr/src/cmd/ssh/sshd/altprivsep.c1187
-rw-r--r--usr/src/cmd/ssh/sshd/auth-bsdauth.c126
-rw-r--r--usr/src/cmd/ssh/sshd/auth-chall.c84
-rw-r--r--usr/src/cmd/ssh/sshd/auth-krb4.c370
-rw-r--r--usr/src/cmd/ssh/sshd/auth-krb5.c407
-rw-r--r--usr/src/cmd/ssh/sshd/auth-options.c299
-rw-r--r--usr/src/cmd/ssh/sshd/auth-pam.c617
-rw-r--r--usr/src/cmd/ssh/sshd/auth-passwd.c206
-rw-r--r--usr/src/cmd/ssh/sshd/auth-rh-rsa.c91
-rw-r--r--usr/src/cmd/ssh/sshd/auth-rhosts.c299
-rw-r--r--usr/src/cmd/ssh/sshd/auth-rsa.c328
-rw-r--r--usr/src/cmd/ssh/sshd/auth-sia.c126
-rw-r--r--usr/src/cmd/ssh/sshd/auth-skey.c104
-rw-r--r--usr/src/cmd/ssh/sshd/auth.c794
-rw-r--r--usr/src/cmd/ssh/sshd/auth1.c466
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-chall.c358
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-gss.c533
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-hostbased.c220
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-kbdint.c90
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-none.c139
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-pam.c458
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-passwd.c78
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-pubkey.c359
-rw-r--r--usr/src/cmd/ssh/sshd/auth2.c695
-rw-r--r--usr/src/cmd/ssh/sshd/bsmaudit.c316
-rw-r--r--usr/src/cmd/ssh/sshd/bsmaudit.h48
-rw-r--r--usr/src/cmd/ssh/sshd/groupaccess.c123
-rw-r--r--usr/src/cmd/ssh/sshd/gss-serv.c516
-rw-r--r--usr/src/cmd/ssh/sshd/loginrec.c1533
-rw-r--r--usr/src/cmd/ssh/sshd/mapfile-intf49
-rw-r--r--usr/src/cmd/ssh/sshd/servconf.c1494
-rw-r--r--usr/src/cmd/ssh/sshd/serverloop.c1310
-rw-r--r--usr/src/cmd/ssh/sshd/session.c2641
-rw-r--r--usr/src/cmd/ssh/sshd/sshd.c2051
-rw-r--r--usr/src/cmd/ssh/sshd/sshlogin.c126
-rw-r--r--usr/src/cmd/ssh/sshd/sshpty.c420
37 files changed, 0 insertions, 19180 deletions
diff --git a/usr/src/cmd/ssh/sshd/Makefile b/usr/src/cmd/ssh/sshd/Makefile
deleted file mode 100644
index 5c4d296bf3..0000000000
--- a/usr/src/cmd/ssh/sshd/Makefile
+++ /dev/null
@@ -1,119 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# cmd/ssh/sshd/Makefile
-
-PROG= sshd
-
-DIRS= $(ROOTLIBSSH) $(ROOTLIBSUNSSH)
-
-OBJS = sshd.o \
- altprivsep.o \
- auth.o \
- auth1.o \
- auth2.o \
- auth-options.o \
- auth2-chall.o \
- auth2-gss.o \
- auth2-hostbased.o \
- auth2-kbdint.o \
- auth2-none.o \
- auth2-passwd.o \
- auth2-pam.o \
- auth2-pubkey.o \
- auth-bsdauth.o \
- auth-chall.o \
- auth-rhosts.o \
- auth-krb4.o \
- auth-krb5.o \
- auth-pam.o \
- auth-passwd.o \
- auth-rsa.o \
- auth-rh-rsa.o \
- auth-sia.o \
- auth-skey.o \
- bsmaudit.o \
- groupaccess.o \
- gss-serv.o \
- loginrec.o \
- servconf.o \
- serverloop.o \
- session.o \
- sshlogin.o \
- sshpty.o
-
-EXTOBJS = sftp-server.o
-
-SRCS = $(OBJS:.o=.c) ../sftp-server/sftp-server.c
-
-include ../../Makefile.cmd
-include ../Makefile.ssh-common
-
-LDLIBS += $(SSH_COMMON_LDLIBS) -lsocket \
- -lnsl \
- -lz \
- -lpam \
- -lbsm \
- -lwrap \
- -lcrypto \
- -lgss \
- -lcontract
-MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB)
-LDFLAGS += $(MAPFILES:%=-M%)
-
-POFILE_DIR= ..
-
-.KEEP_STATE:
-
-.PARALLEL: $(OBJS)
-
-all: $(PROG)
-
-$(PROG): $(OBJS) $(EXTOBJS) $(MAPFILES) ../libssh/$(MACH)/libssh.a \
- ../libopenbsd-compat/$(MACH)/libopenbsd-compat.a
- $(LINK.c) $(OBJS) $(EXTOBJS) -o $@ $(LDLIBS) $(DYNFLAGS)
- $(POST_PROCESS)
-
-%.o : ../sftp-server/%.c
- $(COMPILE.c) -o $@ $<
- $(POST_PROCESS_O)
-
-install: all $(DIRS) $(ROOTLIBSSHPROG) $(ROOTLIBSSH) $(ROOTLIBSUNSSH)
-
-
-$(ROOTLIBSSHPROG)/%: %
- $(INS.file)
-
-$(ROOTLIBSUNSSHPROG)/%: %
- $(INS.file)
-
-$(DIRS):
- $(INS.dir)
-
-clean:
- $(RM) $(OBJS) $(EXTOBJS)
-
-lint: lint_SRCS
-
-include ../Makefile.msg.targ
-include ../../Makefile.targ
diff --git a/usr/src/cmd/ssh/sshd/altprivsep.c b/usr/src/cmd/ssh/sshd/altprivsep.c
deleted file mode 100644
index 6f954feab5..0000000000
--- a/usr/src/cmd/ssh/sshd/altprivsep.c
+++ /dev/null
@@ -1,1187 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-
-#include <pwd.h>
-
-#include "includes.h"
-#include "atomicio.h"
-#include "auth.h"
-#include "bufaux.h"
-#include "buffer.h"
-#include "cipher.h"
-#include "compat.h"
-#include "dispatch.h"
-#include "getput.h"
-#include "kex.h"
-#include "log.h"
-#include "mac.h"
-#include "packet.h"
-#include "uidswap.h"
-#include "ssh2.h"
-#include "sshlogin.h"
-#include "xmalloc.h"
-#include "altprivsep.h"
-#include "canohost.h"
-#include "engine.h"
-#include "servconf.h"
-
-#ifdef HAVE_BSM
-#include "bsmaudit.h"
-adt_session_data_t *ah = NULL;
-#endif /* HAVE_BSM */
-
-#ifdef GSSAPI
-#include "ssh-gss.h"
-extern Gssctxt *xxx_gssctxt;
-#endif /* GSSAPI */
-
-extern Kex *xxx_kex;
-extern u_char *session_id2;
-extern int session_id2_len;
-
-static Buffer to_monitor;
-static Buffer from_monitor;
-
-/*
- * Sun's Alternative Privilege Separation basics:
- *
- * Abstract
- * --------
- *
- * sshd(1M) fork()s and drops privs in the child while retaining privs
- * in the parent (a.k.a., the monitor). The unprivileged sshd and the
- * monitor talk over a pipe using a simple protocol.
- *
- * The monitor protocol is all about having the monitor carry out the
- * only operations that require privileges OR access to privileged
- * resources. These are: utmpx/wtmpx record keeping, auditing, and
- * SSHv2 re-keying.
- *
- * Re-Keying
- * ---------
- *
- * Re-keying is the only protocol version specific aspect of sshd in
- * which the monitor gets involved.
- *
- * The monitor processes all SSHv2 re-key protocol packets, but the
- * unprivileged sshd process does the transport layer crypto for those
- * packets.
- *
- * The monitor and its unprivileged sshd child process treat
- * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call
- * set_newkeys(), but b) the child asks the monitor for the set of
- * negotiated algorithms, key, IV and what not for the relevant
- * transport direction and then calls set_newkeys().
- *
- * Monitor Protocol
- * ----------------
- *
- * Monitor IPC message formats are similar to SSHv2 messages, minus
- * compression, encryption, padding and MACs:
- *
- * - 4 octet message length
- * - message data
- * - 1 octet message type
- * - message data
- *
- * In broad strokes:
- *
- * - IPC: pipe, exit(2)/wait4(2)
- *
- * - threads: the monitor and child are single-threaded
- *
- * - monitor main loop: a variant of server_loop2(), for re-keying only
- * - unpriv child main loop: server_loop2(), as usual
- *
- * - protocol:
- * - key exchange packets are always forwarded as is to the monitor
- * - newkeys, record_login(), record_logout() are special packets
- * using the packet type range reserved for local extensions
- *
- * - the child drops privs and runs like a normal sshd, except that it
- * sets dispatch handlers for key exchange packets that forward the
- * packets to the monitor
- *
- * Event loops:
- *
- * - all monitor protocols are synchronous: because the SSHv2 rekey
- * protocols are synchronous and because the other monitor operations
- * are synchronous (or have no replies),
- *
- * - server_loop2() is modified to check the monitor pipe for rekey
- * packets to forward to the client
- *
- * - and dispatch handlers are set, upon receipt of KEXINIT (and reset
- * when NEWKEYS is sent out) to forward incoming rekey packets to the
- * monitor.
- *
- * - the monitor runs an event loop not unlike server_loop2() and runs
- * key exchanges almost exactly as a pre-altprivsep sshd would
- *
- * - unpriv sshd exit -> monitor cleanup (including audit logout) and exit
- *
- * - fatal() in monitor -> forcibly shutdown() socket and kill/wait for
- * child (so that the audit event for the logout better reflects
- * reality -- i.e., logged out means logged out, but for bg jobs)
- *
- * Message formats:
- *
- * - key exchange packets/replies forwarded "as is"
- *
- * - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a
- * sub-type identifier (one octet)
- * - private request sub-types include:
- * - get new shared secret from last re-key
- * - record login (utmpx/wtmpx), request data contains three arguments:
- * pid, ttyname, program name
- * - record logout (utmpx/wtmpx), request data contains one argument: pid
- *
- * Reply sub-types include:
- *
- * - NOP (for record_login/logout)
- * - new shared secret from last re-key
- */
-
-static int aps_started = 0;
-static int is_monitor = 0;
-
-static pid_t monitor_pid, child_pid;
-static int pipe_fds[2];
-static int pipe_fd = -1;
-static Buffer input_pipe, output_pipe; /* for pipe I/O */
-
-static Authctxt *xxx_authctxt;
-
-/* Monitor functions */
-extern void aps_monitor_loop(Authctxt *authctxt, pid_t child_pid);
-static void aps_record_login(void);
-static void aps_record_logout(void);
-static void aps_start_rekex(void);
-Authctxt *aps_read_auth_context(void);
-
-/* main functions for handling the monitor */
-static pid_t altprivsep_start_monitor(Authctxt **authctxt);
-static void altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid);
-static int altprivsep_started(void);
-static int altprivsep_is_monitor(void);
-
-/* calls _to_ monitor from unprivileged process */
-static void altprivsep_get_newkeys(enum kex_modes mode);
-
-/* monitor-side fatal_cleanup callbacks */
-static void altprivsep_shutdown_sock(void *arg);
-
-/* Altprivsep packet utilities for communication with the monitor */
-static void altprivsep_packet_start(u_char);
-static int altprivsep_packet_send(void);
-static int altprivsep_fwd_packet(u_char type);
-
-static int altprivsep_packet_read(void);
-static void altprivsep_packet_read_expect(int type);
-
-static void altprivsep_packet_put_char(int ch);
-static void altprivsep_packet_put_int(u_int value);
-static void altprivsep_packet_put_cstring(const char *str);
-static void altprivsep_packet_put_raw(const void *buf, u_int len);
-
-static u_int altprivsep_packet_get_char(void);
-static void *altprivsep_packet_get_raw(u_int *length_ptr);
-static void *altprivsep_packet_get_string(u_int *length_ptr);
-
-Kex *prepare_for_ssh2_kex(void);
-
-/*
- * Start monitor from privileged sshd process.
- *
- * Return values are like fork(2); the parent is the monitor. The caller should
- * fatal() on error.
- *
- * Note that the monitor waits until the still privileged child finishes the
- * authentication. The child drops its privileges after the authentication.
- */
-static pid_t
-altprivsep_start_monitor(Authctxt **authctxt)
-{
- pid_t pid;
- int junk;
-
- if (aps_started)
- fatal("Monitor startup failed: missing state");
-
- buffer_init(&output_pipe);
- buffer_init(&input_pipe);
-
- if (pipe(pipe_fds) != 0) {
- error("Monitor startup failure: could not create pipes: %s",
- strerror(errno));
- return (-1);
- }
-
- (void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC);
- (void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC);
-
- monitor_pid = getpid();
-
- if ((pid = fork()) > 0) {
- /*
- * From now on, all debug messages from monitor will have prefix
- * "monitor "
- */
- set_log_txt_prefix("monitor ");
- (void) prepare_for_ssh2_kex();
- packet_set_server();
- /* parent */
- child_pid = pid;
-
- debug2("Monitor pid %ld, unprivileged child pid %ld",
- monitor_pid, child_pid);
-
- (void) close(pipe_fds[1]);
- pipe_fd = pipe_fds[0];
-
- /*
- * Signal readiness of the monitor and then read the
- * authentication context from the child.
- */
- (void) write(pipe_fd, &pid, sizeof (pid));
- packet_set_monitor(pipe_fd);
- xxx_authctxt = *authctxt = aps_read_auth_context();
-
- if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0)
- error("fcntl O_NONBLOCK: %.100s", strerror(errno));
-
- aps_started = 1;
- is_monitor = 1;
-
- debug2("Monitor started");
-
- return (pid);
- }
-
- if (pid < 0) {
- debug2("Monitor startup failure: could not fork unprivileged"
- " process: %s", strerror(errno));
- return (pid);
- }
-
- /* this is the child that will later drop privileges */
-
- /* note that Solaris has bi-directional pipes so one pipe is enough */
- (void) close(pipe_fds[0]);
- pipe_fd = pipe_fds[1];
-
- /* wait for monitor to be ready */
- debug2("Waiting for monitor");
- (void) read(pipe_fd, &junk, sizeof (junk));
- debug2("Monitor signalled readiness");
-
- buffer_init(&to_monitor);
- buffer_init(&from_monitor);
-
- /* AltPrivSep interfaces are set up */
- aps_started = 1;
- return (pid);
-}
-
-int
-altprivsep_get_pipe_fd(void)
-{
- return (pipe_fd);
-}
-
-/*
- * This function is used in the unprivileged child for all packets in the range
- * between SSH2_MSG_KEXINIT and SSH2_MSG_TRANSPORT_MAX.
- */
-void
-altprivsep_rekey(int type, u_int32_t seq, void *ctxt)
-{
- Kex *kex = (Kex *)ctxt;
-
- if (kex == NULL)
- fatal("Missing key exchange context in unprivileged process");
-
- if (type != SSH2_MSG_NEWKEYS) {
- debug2("Forwarding re-key packet (%d) to monitor", type);
- if (!altprivsep_fwd_packet(type))
- fatal("altprivsep_rekey: Monitor not responding");
- }
-
- /* tell server_loop2() that we're re-keying */
- kex->done = 0;
-
- /* NEWKEYS is special: get the new keys for client->server direction */
- if (type == SSH2_MSG_NEWKEYS) {
- debug2("received SSH2_MSG_NEWKEYS packet - "
- "getting new inbound keys from the monitor");
- altprivsep_get_newkeys(MODE_IN);
- kex->done = 1;
- }
-}
-
-void
-altprivsep_process_input(fd_set *rset)
-{
- void *data;
- int type;
- u_int dlen;
-
- if (pipe_fd == -1)
- return;
-
- if (!FD_ISSET(pipe_fd, rset))
- return;
-
- debug2("reading from pipe to monitor (%d)", pipe_fd);
- if ((type = altprivsep_packet_read()) == -1)
- fatal("altprivsep_process_input: Monitor not responding");
-
- if (!compat20)
- return; /* shouldn't happen! but be safe */
-
- if (type == 0)
- return; /* EOF -- nothing to do here */
-
- if (type >= SSH2_MSG_MAX)
- fatal("Received garbage from monitor");
-
- debug2("Read packet type %d from pipe to monitor", (u_int)type);
-
- if (type == SSH2_PRIV_MSG_ALTPRIVSEP)
- return; /* shouldn't happen! */
-
- /* NEWKEYS is special: get the new keys for server->client direction */
- if (type == SSH2_MSG_NEWKEYS) {
- debug2("forwarding SSH2_MSG_NEWKEYS packet we got from monitor to "
- "the client");
- packet_start(SSH2_MSG_NEWKEYS);
- packet_send();
- debug2("getting new outbound keys from the monitor");
- altprivsep_get_newkeys(MODE_OUT);
- return;
- }
-
- data = altprivsep_packet_get_raw(&dlen);
-
- packet_start((u_char)type);
-
- if (data != NULL && dlen > 0)
- packet_put_raw(data, dlen);
-
- packet_send();
-}
-
-static void
-altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid)
-{
- aps_monitor_loop(authctxt, child_pid);
-}
-
-static int
-altprivsep_started(void)
-{
- return (aps_started);
-}
-
-static int
-altprivsep_is_monitor(void)
-{
- return (is_monitor);
-}
-
-/*
- * A fatal cleanup function to forcibly shutdown the connection socket
- */
-static void
-altprivsep_shutdown_sock(void *arg)
-{
- int sock;
-
- if (arg == NULL)
- return;
-
- sock = *(int *)arg;
-
- (void) shutdown(sock, SHUT_RDWR);
-}
-
-/* Calls _to_ monitor from unprivileged process */
-static int
-altprivsep_fwd_packet(u_char type)
-{
- u_int len;
- void *data;
-
- altprivsep_packet_start(type);
- data = packet_get_raw(&len);
- altprivsep_packet_put_raw(data, len);
-
- /* packet_send()s any replies from the monitor to the client */
- return (altprivsep_packet_send());
-}
-
-extern Newkeys *current_keys[MODE_MAX];
-
-/* To be called from packet.c:set_newkeys() before referencing current_keys */
-static void
-altprivsep_get_newkeys(enum kex_modes mode)
-{
- Newkeys *newkeys;
- Comp *comp;
- Enc *enc;
- Mac *mac;
- u_int len;
-
- if (!altprivsep_started())
- return;
-
- if (altprivsep_is_monitor())
- return; /* shouldn't happen */
-
- /* request new keys */
- altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ);
- altprivsep_packet_put_int((u_int)mode);
- altprivsep_packet_send();
- altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
- if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP)
- fatal("Received garbage from monitor during re-keying");
-
- newkeys = xmalloc(sizeof (*newkeys));
- memset(newkeys, 0, sizeof (*newkeys));
-
- enc = &newkeys->enc;
- mac = &newkeys->mac;
- comp = &newkeys->comp;
-
- /* Cipher name, key, IV */
- enc->name = altprivsep_packet_get_string(NULL);
- if ((enc->cipher = cipher_by_name(enc->name)) == NULL)
- fatal("Monitor negotiated an unknown cipher during re-key");
-
- enc->key = altprivsep_packet_get_string(&enc->key_len);
- enc->iv = altprivsep_packet_get_string(&enc->block_size);
-
- /* MAC name */
- mac->name = altprivsep_packet_get_string(NULL);
- if (mac_setup(mac, mac->name) < 0)
- fatal("Monitor negotiated an unknown MAC algorithm "
- "during re-key");
-
- mac->key = altprivsep_packet_get_string(&len);
- if (len > mac->key_len)
- fatal("%s: bad mac key length: %d > %d", __func__, len,
- mac->key_len);
-
- /* Compression algorithm name */
- comp->name = altprivsep_packet_get_string(NULL);
- if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0)
- fatal("Monitor negotiated an unknown compression "
- "algorithm during re-key");
-
- comp->type = 0;
- comp->enabled = 0; /* forces compression re-init, as per-spec */
- if (strcmp(comp->name, "zlib") == 0)
- comp->type = 1;
-
- /*
- * Now install new keys
- *
- * For now abuse kex.c/packet.c non-interfaces. Someday, when
- * the many internal interfaces are parametrized, made reentrant
- * and thread-safe, made more consistent, and when necessary-but-
- * currently-missing interfaces are added then this bit of
- * ugliness can be revisited.
- *
- * The ugliness is in the set_newkeys(), its name and the lack
- * of a (Newkeys *) parameter, which forces us to pass the
- * newkeys through current_keys[mode]. But this saves us some
- * lines of code for now, though not comments.
- *
- * Also, we've abused, in the code above, knowledge of what
- * set_newkeys() expects the current_keys[mode] to contain.
- */
- current_keys[mode] = newkeys;
- set_newkeys(mode);
-
-}
-
-void
-altprivsep_record_login(pid_t pid, const char *ttyname)
-{
- altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN);
- altprivsep_packet_put_int(pid);
- altprivsep_packet_put_cstring(ttyname);
- altprivsep_packet_send();
- altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
-}
-
-void
-altprivsep_record_logout(pid_t pid)
-{
- altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT);
- altprivsep_packet_put_int(pid);
- altprivsep_packet_send();
- altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
-}
-
-void
-altprivsep_start_rekex(void)
-{
- altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- altprivsep_packet_put_char(APS_MSG_START_REKEX);
- altprivsep_packet_send();
- altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
-}
-
-/*
- * The monitor needs some information that its child learns during the
- * authentication process. Since the child was forked before the key exchange
- * and authentication started it must send some context to the monitor after the
- * authentication is finished. Less obvious part - monitor needs the session ID
- * since it is used in the key generation process after the key (re-)exchange is
- * finished.
- */
-void
-altprivsep_send_auth_context(Authctxt *authctxt)
-{
- debug("sending auth context to the monitor");
- altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- altprivsep_packet_put_char(APS_MSG_AUTH_CONTEXT);
- altprivsep_packet_put_int(authctxt->pw->pw_uid);
- altprivsep_packet_put_int(authctxt->pw->pw_gid);
- altprivsep_packet_put_cstring(authctxt->pw->pw_name);
- altprivsep_packet_put_raw(session_id2, session_id2_len);
- debug("will send %d bytes of auth context to the monitor",
- buffer_len(&to_monitor));
- altprivsep_packet_send();
- altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
-}
-
-static void aps_send_newkeys(void);
-
-/* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */
-/* ARGSUSED */
-void
-aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt)
-{
- u_char req_type;
-
- req_type = packet_get_char();
-
- switch (req_type) {
- case APS_MSG_NEWKEYS_REQ:
- aps_send_newkeys();
- break;
- case APS_MSG_RECORD_LOGIN:
- aps_record_login();
- break;
- case APS_MSG_RECORD_LOGOUT:
- aps_record_logout();
- break;
- case APS_MSG_START_REKEX:
- aps_start_rekex();
- break;
- default:
- break;
- }
-}
-
-/* Monitor-side handlers for APS_MSG_* */
-static
-void
-aps_send_newkeys(void)
-{
- Newkeys *newkeys;
- Enc *enc;
- Mac *mac;
- Comp *comp;
- enum kex_modes mode;
-
- /* get direction for which newkeys are wanted */
- mode = (enum kex_modes) packet_get_int();
- packet_check_eom();
-
- /* get those newkeys */
- newkeys = kex_get_newkeys(mode);
- enc = &newkeys->enc;
- mac = &newkeys->mac;
- comp = &newkeys->comp;
-
- /*
- * Negotiated algorithms, client->server and server->client, for
- * cipher, mac and compression.
- */
- packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- packet_put_char(APS_MSG_NEWKEYS_REP);
- packet_put_cstring(enc->name);
- packet_put_string(enc->key, enc->key_len);
- packet_put_string(enc->iv, enc->block_size);
- packet_put_cstring(mac->name);
- packet_put_string(mac->key, mac->key_len);
- packet_put_cstring(comp->name);
-
- packet_send();
- free_keys(newkeys);
-}
-
-struct _aps_login_rec {
- pid_t lr_pid;
- char *lr_tty;
- struct _aps_login_rec *next;
-};
-
-typedef struct _aps_login_rec aps_login_rec;
-
-static aps_login_rec *aps_login_list = NULL;
-
-static
-void
-aps_record_login(void)
-{
- aps_login_rec *new_rec;
- struct stat sbuf;
- size_t proc_path_len;
- char *proc_path;
-
- new_rec = xmalloc(sizeof (aps_login_rec));
- memset(new_rec, 0, sizeof (aps_login_rec));
-
- new_rec->lr_pid = packet_get_int();
- new_rec->lr_tty = packet_get_string(NULL);
-
- proc_path_len = snprintf(NULL, 0, "/proc/%d", new_rec->lr_pid);
- proc_path = xmalloc(proc_path_len + 1);
- (void) snprintf(proc_path, proc_path_len + 1, "/proc/%d",
- new_rec->lr_pid);
-
- if (stat(proc_path, &sbuf) ||
- sbuf.st_uid != xxx_authctxt->pw->pw_uid ||
- stat(new_rec->lr_tty, &sbuf) < 0 ||
- sbuf.st_uid != xxx_authctxt->pw->pw_uid) {
- debug2("Spurious record_login request from unprivileged sshd");
- xfree(proc_path);
- xfree(new_rec->lr_tty);
- xfree(new_rec);
- return;
- }
-
- /* Insert new record on list */
- new_rec->next = aps_login_list;
- aps_login_list = new_rec;
-
- record_login(new_rec->lr_pid, new_rec->lr_tty, NULL,
- xxx_authctxt->user);
-
- packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- packet_send();
-
- xfree(proc_path);
-}
-
-static
-void
-aps_record_logout(void)
-{
- aps_login_rec **p, *q;
- pid_t pid;
-
- pid = packet_get_int();
- packet_check_eom();
-
- for (p = &aps_login_list; *p != NULL; p = &q->next) {
- q = *p;
- if (q->lr_pid == pid) {
- record_logout(q->lr_pid, q->lr_tty, NULL,
- xxx_authctxt->user);
-
- /* dequeue */
- *p = q->next;
- xfree(q->lr_tty);
- xfree(q);
- break;
- }
- }
-
- packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- packet_send();
-}
-
-static
-void
-aps_start_rekex(void)
-{
- /*
- * Send confirmation. We could implement it without that but it doesn't
- * bring any harm to do that and we are consistent with other subtypes
- * of our private SSH2_PRIV_MSG_ALTPRIVSEP message type.
- */
- packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- packet_send();
-
- /*
- * KEX_INIT message could be the one that reached the limit. In that
- * case, it was already forwarded to us from the unnprivileged child,
- * and maybe even acted upon. Obviously we must not send another
- * KEX_INIT message.
- */
- if (!(xxx_kex->flags & KEX_INIT_SENT))
- kex_send_kexinit(xxx_kex);
- else
- debug2("rekeying already in progress");
-}
-
-/*
- * This is the monitor side of altprivsep_send_auth_context().
- */
-Authctxt *
-aps_read_auth_context(void)
-{
- unsigned char *tmp;
- Authctxt *authctxt;
-
- /*
- * After the successful authentication we get the context. Getting
- * end-of-file means that authentication failed and we can exit as well.
- */
- debug("reading the context from the child");
- packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
- debug3("got SSH2_PRIV_MSG_ALTPRIVSEP");
- if (packet_get_char() != APS_MSG_AUTH_CONTEXT) {
- fatal("APS_MSG_AUTH_CONTEXT message subtype expected.");
- }
-
- authctxt = xcalloc(1, sizeof(Authctxt));
- authctxt->pw = xcalloc(1, sizeof(struct passwd));
-
- /* uid_t and gid_t are integers (UNIX spec) */
- authctxt->pw->pw_uid = packet_get_int();
- authctxt->pw->pw_gid = packet_get_int();
- authctxt->pw->pw_name = packet_get_string(NULL);
- authctxt->user = xstrdup(authctxt->pw->pw_name);
- debug3("uid/gid/username %d/%d/%s", authctxt->pw->pw_uid,
- authctxt->pw->pw_gid, authctxt->user);
- session_id2 = (unsigned char *)packet_get_raw((unsigned int*)&session_id2_len);
-
- /* we don't have this for SSH1. In that case, session_id2_len is 0. */
- if (session_id2_len > 0) {
- tmp = (unsigned char *)xmalloc(session_id2_len);
- memcpy(tmp, session_id2, session_id2_len);
- session_id2 = tmp;
- debug3("read session ID (%d B)", session_id2_len);
- xxx_kex->session_id = tmp;
- xxx_kex->session_id_len = session_id2_len;
- }
- debug("finished reading the context");
-
- /* send confirmation */
- packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
- packet_send();
-
- return (authctxt);
-}
-
-
-/* Utilities for communication with the monitor */
-static void
-altprivsep_packet_start(u_char type)
-{
- buffer_clear(&to_monitor);
- buffer_put_char(&to_monitor, type);
-}
-
-static void
-altprivsep_packet_put_char(int ch)
-{
- buffer_put_char(&to_monitor, ch);
-}
-
-static void
-altprivsep_packet_put_int(u_int value)
-{
- buffer_put_int(&to_monitor, value);
-}
-
-static void
-altprivsep_packet_put_cstring(const char *str)
-{
- buffer_put_cstring(&to_monitor, str);
-}
-
-static void
-altprivsep_packet_put_raw(const void *buf, u_int len)
-{
- buffer_append(&to_monitor, buf, len);
-}
-
-/*
- * Send a monitor packet to the monitor. This function is blocking.
- *
- * Returns -1 if the monitor pipe has been closed earlier, fatal()s if
- * there's any other problems.
- */
-static int
-altprivsep_packet_send(void)
-{
- ssize_t len;
- u_int32_t plen; /* packet length */
- u_char plen_buf[sizeof (plen)];
- u_char padlen; /* padding length */
- fd_set *setp;
- int err;
-
- if (pipe_fd == -1)
- return (-1);
-
- if ((plen = buffer_len(&to_monitor)) == 0)
- return (0);
-
- /*
- * We talk the SSHv2 binary packet protocol to the monitor,
- * using the none cipher, mac and compression algorithms.
- *
- * But, interestingly, the none cipher has a block size of 8
- * bytes, thus we must pad the packet.
- *
- * Also, encryption includes the packet length, so the padding
- * must account for that field. I.e., (sizeof (packet length) +
- * sizeof (padding length) + packet length + padding length) %
- * block_size must == 0.
- *
- * Also, there must be at least four (4) bytes of padding.
- */
- padlen = (8 - ((plen + sizeof (plen) + sizeof (padlen)) % 8)) % 8;
- if (padlen < 4)
- padlen += 8;
-
- /* packet length counts padding and padding length field */
- plen += padlen + sizeof (padlen);
-
- PUT_32BIT(plen_buf, plen);
-
- setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
- memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
- FD_SET(pipe_fd, setp);
-
- while (select(pipe_fd + 1, NULL, setp, NULL, NULL) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- else
- goto pipe_gone;
- }
-
- xfree(setp);
-
- /* packet length field */
- len = atomicio(write, pipe_fd, plen_buf, sizeof (plen));
-
- if (len != sizeof (plen))
- goto pipe_gone;
-
- /* padding length field */
- len = atomicio(write, pipe_fd, &padlen, sizeof (padlen));
-
- if (len != sizeof (padlen))
- goto pipe_gone;
-
- len = atomicio(write, pipe_fd, buffer_ptr(&to_monitor), plen - 1);
-
- if (len != (plen - 1))
- goto pipe_gone;
-
- buffer_clear(&to_monitor);
-
- return (1);
-
-pipe_gone:
-
- err = errno;
-
- (void) close(pipe_fd);
-
- pipe_fd = -1;
-
- fatal("altprvsep_packet_send: Monitor not responding: %.100s",
- strerror(err));
-
- /* NOTREACHED */
- return (0);
-}
-
-/*
- * Read a monitor packet from the monitor. This function is blocking.
- */
-static int
-altprivsep_packet_read(void)
-{
- ssize_t len = -1;
- u_int32_t plen;
- u_char plen_buf[sizeof (plen)];
- u_char padlen;
- fd_set *setp;
- int err;
-
- if (pipe_fd == -1)
- return (-1);
-
- setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
- memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
- FD_SET(pipe_fd, setp);
-
- while (select(pipe_fd + 1, setp, NULL, NULL, NULL) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- else
- goto pipe_gone;
- }
-
- xfree(setp);
-
- /* packet length field */
- len = atomicio(read, pipe_fd, plen_buf, sizeof (plen));
-
- plen = GET_32BIT(plen_buf);
-
- if (len != sizeof (plen))
- goto pipe_gone;
-
- /* padding length field */
- len = atomicio(read, pipe_fd, &padlen, sizeof (padlen));
-
- if (len != sizeof (padlen))
- goto pipe_gone;
-
- plen -= sizeof (padlen);
-
- buffer_clear(&from_monitor);
- buffer_append_space(&from_monitor, plen);
-
- /* packet data + padding */
- len = atomicio(read, pipe_fd, buffer_ptr(&from_monitor), plen);
-
- if (len != plen)
- goto pipe_gone;
-
- /* remove padding */
- if (padlen > 0)
- buffer_consume_end(&from_monitor, padlen);
-
- /* packet type */
- return (buffer_get_char(&from_monitor));
-
-pipe_gone:
-
- err = errno;
-
- (void) close(pipe_fd);
-
- pipe_fd = -1;
-
- if (len < 0)
- fatal("altpriv_packet_read: Monitor not responding %.100s",
- strerror(err));
-
- debug2("Monitor pipe closed by monitor");
- return (0);
-}
-
-static void
-altprivsep_packet_read_expect(int expected)
-{
- int type;
-
- type = altprivsep_packet_read();
-
- if (type <= 0)
- fatal("altprivsep_packet_read_expect: Monitor not responding");
-
- if (type != expected)
- fatal("Protocol error in privilege separation; expected "
- "packet type %d, got %d", expected, type);
-}
-
-static u_int
-altprivsep_packet_get_char(void)
-{
- return (buffer_get_char(&from_monitor));
-}
-void
-*altprivsep_packet_get_raw(u_int *length_ptr)
-{
- if (length_ptr != NULL)
- *length_ptr = buffer_len(&from_monitor);
-
- return (buffer_ptr(&from_monitor));
-}
-void
-*altprivsep_packet_get_string(u_int *length_ptr)
-{
- return (buffer_get_string(&from_monitor, length_ptr));
-}
-
-/*
- * Start and execute the code for the monitor which never returns from this
- * function. The child will return and continue in the caller.
- */
-void
-altprivsep_start_and_do_monitor(int use_engine, int inetd, int newsock,
- int statup_pipe)
-{
- pid_t aps_child;
- Authctxt *authctxt;
-
- /*
- * The monitor will packet_close() in packet_set_monitor() called from
- * altprivsep_start_monitor() below to clean up the socket stuff before
- * it switches to pipes for communication to the child. The socket fd is
- * closed there so we must dup it here - monitor needs that socket to
- * shutdown the connection in case of any problem; see comments below.
- * Note that current newsock was assigned to connection_(in|out) which
- * are the variables used in packet_close() to close the communication
- * socket.
- */
- newsock = dup(newsock);
-
- if ((aps_child = altprivsep_start_monitor(&authctxt)) == -1)
- fatal("Monitor could not be started.");
-
- if (aps_child > 0) {
- /* ALTPRIVSEP Monitor */
-
- /*
- * The ALTPRIVSEP monitor here does:
- *
- * - record keeping and auditing
- * - PAM cleanup
- */
-
- /* this is for MaxStartups and the child takes care of that */
- (void) close(statup_pipe);
- (void) pkcs11_engine_load(use_engine);
-
- /*
- * If the monitor fatal()s it will audit/record a logout, so
- * we'd better do something to really mean it: shutdown the
- * socket but leave the child alone -- it's been disconnected
- * and we hope it exits, but killing any pid from a privileged
- * monitor could be dangerous.
- *
- * NOTE: Order matters -- these fatal cleanups must come before
- * the audit logout fatal cleanup as these functions are called
- * in LIFO.
- */
- fatal_add_cleanup((void (*)(void *))altprivsep_shutdown_sock,
- (void *)&newsock);
-
- if (compat20) {
- debug3("Recording SSHv2 session login in wtmpx");
- /*
- * record_login() relies on connection_in to be the
- * socket to get the peer address. The problem is that
- * connection_in had to be set to the pipe descriptor in
- * altprivsep_start_monitor(). It's not nice but the
- * easiest way to get the peer's address is to
- * temporarily set connection_in to the socket's file
- * descriptor.
- */
- packet_set_fds(inetd == 1 ? -1 : newsock, 0);
- record_login(getpid(), NULL, "sshd", authctxt->user);
- packet_set_fds(0, 1);
- }
-
-#ifdef HAVE_BSM
- /* Initialize the group list, audit sometimes needs it. */
- if (initgroups(authctxt->pw->pw_name,
- authctxt->pw->pw_gid) < 0) {
- perror("initgroups");
- exit (1);
- }
-
- /*
- * The monitor process fork()ed before the authentication
- * process started so at this point we have an unaudited
- * context. Thus we need to obtain the audit session data
- * from the authentication process (aps_child) which will
- * have the correct audit context for the user logging in.
- * To do so we pass along the process-ID of the aps_child
- * process so that it is referenced for this audit session
- * rather than referencing the monitor's unaudited context.
- */
- audit_sshd_login(&ah, aps_child);
-
- fatal_add_cleanup((void (*)(void *))audit_sshd_logout,
- (void *)&ah);
-#endif /* HAVE_BSM */
-
-#ifdef GSSAPI
- fatal_add_cleanup((void (*)(void *))ssh_gssapi_cleanup_creds,
- (void *)&xxx_gssctxt);
-#endif /* GSSAPI */
-
- altprivsep_do_monitor(authctxt, aps_child);
-
- /* If we got here the connection is dead. */
- fatal_remove_cleanup((void (*)(void *))altprivsep_shutdown_sock,
- (void *)&newsock);
-
- if (compat20) {
- debug3("Recording SSHv2 session logout in wtmpx");
- record_logout(getpid(), NULL, "sshd", authctxt->user);
- }
-
- /*
- * Make sure the socket is closed. The monitor can't call
- * packet_close here as it's done a packet_set_connection()
- * with the pipe to the child instead of the socket.
- */
- (void) shutdown(newsock, SHUT_RDWR);
-
-#ifdef GSSAPI
- fatal_remove_cleanup((void (*)(void *))ssh_gssapi_cleanup_creds,
- &xxx_gssctxt);
- ssh_gssapi_cleanup_creds(xxx_gssctxt);
- ssh_gssapi_server_mechs(NULL); /* release cached mechs list */
-#endif /* GSSAPI */
-
-#ifdef HAVE_BSM
- fatal_remove_cleanup((void (*)(void *))audit_sshd_logout, (void *)&ah);
- audit_sshd_logout(&ah);
-#endif /* HAVE_BSM */
-
- exit(0);
- } else {
- /*
- * This is the child, close the dup()ed file descriptor for a
- * socket. It's not needed in the child.
- */
- close(newsock);
- }
-}
diff --git a/usr/src/cmd/ssh/sshd/auth-bsdauth.c b/usr/src/cmd/ssh/sshd/auth-bsdauth.c
deleted file mode 100644
index 090fa0ef39..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-bsdauth.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) 2001 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-#include "includes.h"
-RCSID("$OpenBSD: auth-bsdauth.c,v 1.5 2002/06/30 21:59:45 deraadt Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifdef BSD_AUTH
-#include "xmalloc.h"
-#include "auth.h"
-#include "log.h"
-
-static void *
-bsdauth_init_ctx(Authctxt *authctxt)
-{
- return authctxt;
-}
-
-int
-bsdauth_query(void *ctx, char **name, char **infotxt,
- u_int *numprompts, char ***prompts, u_int **echo_on)
-{
- Authctxt *authctxt = ctx;
- char *challenge = NULL;
-
- if (authctxt->as != NULL) {
- debug2("bsdauth_query: try reuse session");
- challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
- if (challenge == NULL) {
- auth_close(authctxt->as);
- authctxt->as = NULL;
- }
- }
-
- if (challenge == NULL) {
- debug2("bsdauth_query: new bsd auth session");
- debug3("bsdauth_query: style %s",
- authctxt->style ? authctxt->style : "<default>");
- authctxt->as = auth_userchallenge(authctxt->user,
- authctxt->style, "auth-ssh", &challenge);
- if (authctxt->as == NULL)
- challenge = NULL;
- debug2("bsdauth_query: <%s>", challenge ? challenge : "empty");
- }
-
- if (challenge == NULL)
- return -1;
-
- *name = xstrdup("");
- *infotxt = xstrdup("");
- *numprompts = 1;
- *prompts = xmalloc(*numprompts * sizeof(char *));
- *echo_on = xmalloc(*numprompts * sizeof(u_int));
- (*echo_on)[0] = 0;
- (*prompts)[0] = xstrdup(challenge);
-
- return 0;
-}
-
-int
-bsdauth_respond(void *ctx, u_int numresponses, char **responses)
-{
- Authctxt *authctxt = ctx;
- int authok;
-
- if (authctxt->as == 0)
- error("bsdauth_respond: no bsd auth session");
-
- if (numresponses != 1)
- return -1;
-
- authok = auth_userresponse(authctxt->as, responses[0], 0);
- authctxt->as = NULL;
- debug3("bsdauth_respond: <%s> = <%d>", responses[0], authok);
-
- return (authok == 0) ? -1 : 0;
-}
-
-static void
-bsdauth_free_ctx(void *ctx)
-{
- Authctxt *authctxt = ctx;
-
- if (authctxt && authctxt->as) {
- auth_close(authctxt->as);
- authctxt->as = NULL;
- }
-}
-
-KbdintDevice bsdauth_device = {
- "bsdauth",
- bsdauth_init_ctx,
- bsdauth_query,
- bsdauth_respond,
- bsdauth_free_ctx
-};
-
-KbdintDevice mm_bsdauth_device = {
- "bsdauth",
- bsdauth_init_ctx,
- mm_bsdauth_query,
- mm_bsdauth_respond,
- bsdauth_free_ctx
-};
-#endif
diff --git a/usr/src/cmd/ssh/sshd/auth-chall.c b/usr/src/cmd/ssh/sshd/auth-chall.c
deleted file mode 100644
index 07073f0d98..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-chall.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2001 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-chall.c,v 1.8 2001/05/18 14:13:28 markus Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "auth.h"
-#include "log.h"
-#include "xmalloc.h"
-
-/* limited protocol v1 interface to kbd-interactive authentication */
-
-extern KbdintDevice *devices[];
-static KbdintDevice *device;
-
-char *
-get_challenge(Authctxt *authctxt)
-{
- char *challenge, *name, *info, **prompts;
- u_int i, numprompts;
- u_int *echo_on;
-
- device = devices[0]; /* we always use the 1st device for protocol 1 */
- if (device == NULL)
- return NULL;
- if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL)
- return NULL;
- if (device->query(authctxt->kbdintctxt, &name, &info,
- &numprompts, &prompts, &echo_on)) {
- device->free_ctx(authctxt->kbdintctxt);
- authctxt->kbdintctxt = NULL;
- return NULL;
- }
- if (numprompts < 1)
- fatal("get_challenge: numprompts < 1");
- challenge = xstrdup(prompts[0]);
- for (i = 0; i < numprompts; i++)
- xfree(prompts[i]);
- xfree(prompts);
- xfree(name);
- xfree(echo_on);
- xfree(info);
-
- return (challenge);
-}
-int
-verify_response(Authctxt *authctxt, const char *response)
-{
- char *resp[1];
- int res;
-
- if (device == NULL)
- return 0;
- if (authctxt->kbdintctxt == NULL)
- return 0;
- resp[0] = (char *)response;
- res = device->respond(authctxt->kbdintctxt, 1, resp);
- device->free_ctx(authctxt->kbdintctxt);
- authctxt->kbdintctxt = NULL;
- return res ? 0 : 1;
-}
diff --git a/usr/src/cmd/ssh/sshd/auth-krb4.c b/usr/src/cmd/ssh/sshd/auth-krb4.c
deleted file mode 100644
index 2a9103f232..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-krb4.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (c) 1999 Dug Song. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-krb4.c,v 1.28 2002/09/26 11:38:43 markus Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "ssh.h"
-#include "ssh1.h"
-#include "packet.h"
-#include "xmalloc.h"
-#include "log.h"
-#include "servconf.h"
-#include "uidswap.h"
-#include "auth.h"
-
-#ifdef AFS
-#include "radix.h"
-#endif
-
-#ifdef KRB4
-extern ServerOptions options;
-
-static int
-krb4_init(void *context)
-{
- static int cleanup_registered = 0;
- Authctxt *authctxt = (Authctxt *)context;
- const char *tkt_root = TKT_ROOT;
- struct stat st;
- int fd;
-
- if (!authctxt->krb4_ticket_file) {
- /* Set unique ticket string manually since we're still root. */
- authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN);
-#ifdef AFS
- if (lstat("/ticket", &st) != -1)
- tkt_root = "/ticket/";
-#endif /* AFS */
- snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%ld",
- tkt_root, authctxt->pw->pw_uid, (long)getpid());
- krb_set_tkt_string(authctxt->krb4_ticket_file);
- }
- /* Register ticket cleanup in case of fatal error. */
- if (!cleanup_registered) {
- fatal_add_cleanup(krb4_cleanup_proc, authctxt);
- cleanup_registered = 1;
- }
- /* Try to create our ticket file. */
- if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) {
- close(fd);
- return (1);
- }
- /* Ticket file exists - make sure user owns it (just passed ticket). */
- if (lstat(authctxt->krb4_ticket_file, &st) != -1) {
- if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
- st.st_uid == authctxt->pw->pw_uid)
- return (1);
- }
- /* Failure - cancel cleanup function, leaving ticket for inspection. */
- log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file);
-
- fatal_remove_cleanup(krb4_cleanup_proc, authctxt);
- cleanup_registered = 0;
-
- xfree(authctxt->krb4_ticket_file);
- authctxt->krb4_ticket_file = NULL;
-
- return (0);
-}
-
-/*
- * try krb4 authentication,
- * return 1 on success, 0 on failure, -1 if krb4 is not available
- */
-int
-auth_krb4_password(Authctxt *authctxt, const char *password)
-{
- AUTH_DAT adata;
- KTEXT_ST tkt;
- struct hostent *hp;
- struct passwd *pw;
- char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
- u_int32_t faddr;
- int r;
-
- if ((pw = authctxt->pw) == NULL)
- return (0);
-
- /*
- * Try Kerberos password authentication only for non-root
- * users and only if Kerberos is installed.
- */
- if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
- /* Set up our ticket file. */
- if (!krb4_init(authctxt)) {
- log("Couldn't initialize Kerberos ticket file for %s!",
- pw->pw_name);
- goto failure;
- }
- /* Try to get TGT using our password. */
- r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
- "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
- if (r != INTK_OK) {
- debug("Kerberos v4 password authentication for %s "
- "failed: %s", pw->pw_name, krb_err_txt[r]);
- goto failure;
- }
- /* Successful authentication. */
- chown(tkt_string(), pw->pw_uid, pw->pw_gid);
-
- /*
- * Now that we have a TGT, try to get a local
- * "rcmd" ticket to ensure that we are not talking
- * to a bogus Kerberos server.
- */
- gethostname(localhost, sizeof(localhost));
- strlcpy(phost, (char *)krb_get_phost(localhost),
- sizeof(phost));
- r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
-
- if (r == KSUCCESS) {
- if ((hp = gethostbyname(localhost)) == NULL) {
- log("Couldn't get local host address!");
- goto failure;
- }
- memmove((void *)&faddr, (void *)hp->h_addr,
- sizeof(faddr));
-
- /* Verify our "rcmd" ticket. */
- r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
- faddr, &adata, "");
- if (r == RD_AP_UNDEC) {
- /*
- * Probably didn't have a srvtab on
- * localhost. Disallow login.
- */
- log("Kerberos v4 TGT for %s unverifiable, "
- "no srvtab installed? krb_rd_req: %s",
- pw->pw_name, krb_err_txt[r]);
- goto failure;
- } else if (r != KSUCCESS) {
- log("Kerberos v4 %s ticket unverifiable: %s",
- KRB4_SERVICE_NAME, krb_err_txt[r]);
- goto failure;
- }
- } else if (r == KDC_PR_UNKNOWN) {
- /*
- * Disallow login if no rcmd service exists, and
- * log the error.
- */
- log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s "
- "not registered, or srvtab is wrong?", pw->pw_name,
- krb_err_txt[r], KRB4_SERVICE_NAME, phost);
- goto failure;
- } else {
- /*
- * TGT is bad, forget it. Possibly spoofed!
- */
- debug("WARNING: Kerberos v4 TGT possibly spoofed "
- "for %s: %s", pw->pw_name, krb_err_txt[r]);
- goto failure;
- }
- /* Authentication succeeded. */
- return (1);
- } else
- /* Logging in as root or no local Kerberos realm. */
- debug("Unable to authenticate to Kerberos.");
-
- failure:
- krb4_cleanup_proc(authctxt);
-
- if (!options.kerberos_or_local_passwd)
- return (0);
-
- /* Fall back to ordinary passwd authentication. */
- return (-1);
-}
-
-void
-krb4_cleanup_proc(void *context)
-{
- Authctxt *authctxt = (Authctxt *)context;
- debug("krb4_cleanup_proc called");
- if (authctxt->krb4_ticket_file) {
- (void) dest_tkt();
- xfree(authctxt->krb4_ticket_file);
- authctxt->krb4_ticket_file = NULL;
- }
-}
-
-int
-auth_krb4(Authctxt *authctxt, KTEXT auth, char **client, KTEXT reply)
-{
- AUTH_DAT adat = {0};
- Key_schedule schedule;
- struct sockaddr_in local, foreign;
- char instance[INST_SZ];
- socklen_t slen;
- u_int cksum;
- int r, s;
-
- s = packet_get_connection_in();
-
- slen = sizeof(local);
- memset(&local, 0, sizeof(local));
- if (getsockname(s, (struct sockaddr *) & local, &slen) < 0)
- debug("getsockname failed: %.100s", strerror(errno));
- slen = sizeof(foreign);
- memset(&foreign, 0, sizeof(foreign));
- if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 0) {
- debug("getpeername failed: %.100s", strerror(errno));
- fatal_cleanup();
- }
- instance[0] = '*';
- instance[1] = 0;
-
- /* Get the encrypted request, challenge, and session key. */
- if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
- 0, &adat, ""))) {
- debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
- return (0);
- }
- des_key_sched((des_cblock *) adat.session, schedule);
-
- *client = xmalloc(MAX_K_NAME_SZ);
- (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
- *adat.pinst ? "." : "", adat.pinst, adat.prealm);
-
- /* Check ~/.klogin authorization now. */
- if (kuserok(&adat, authctxt->user) != KSUCCESS) {
- log("Kerberos v4 .klogin authorization failed for %s to "
- "account %s", *client, authctxt->user);
- xfree(*client);
- *client = NULL;
- return (0);
- }
- /* Increment the checksum, and return it encrypted with the
- session key. */
- cksum = adat.checksum + 1;
- cksum = htonl(cksum);
-
- /* If we can't successfully encrypt the checksum, we send back an
- empty message, admitting our failure. */
- if ((r = krb_mk_priv((u_char *) & cksum, reply->dat, sizeof(cksum) + 1,
- schedule, &adat.session, &local, &foreign)) < 0) {
- debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
- reply->dat[0] = 0;
- reply->length = 0;
- } else
- reply->length = r;
-
- /* Clear session key. */
- memset(&adat.session, 0, sizeof(&adat.session));
- return (1);
-}
-#endif /* KRB4 */
-
-#ifdef AFS
-int
-auth_krb4_tgt(Authctxt *authctxt, const char *string)
-{
- CREDENTIALS creds;
- struct passwd *pw;
-
- if ((pw = authctxt->pw) == NULL)
- goto failure;
-
- temporarily_use_uid(pw);
-
- if (!radix_to_creds(string, &creds)) {
- log("Protocol error decoding Kerberos v4 TGT");
- goto failure;
- }
- if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
- strlcpy(creds.service, "krbtgt", sizeof creds.service);
-
- if (strcmp(creds.service, "krbtgt")) {
- log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s",
- creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
- creds.realm, pw->pw_name);
- goto failure;
- }
- if (!krb4_init(authctxt))
- goto failure;
-
- if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
- goto failure;
-
- if (save_credentials(creds.service, creds.instance, creds.realm,
- creds.session, creds.lifetime, creds.kvno, &creds.ticket_st,
- creds.issue_date) != KSUCCESS) {
- debug("Kerberos v4 TGT refused: couldn't save credentials");
- goto failure;
- }
- /* Successful authentication, passed all checks. */
- chown(tkt_string(), pw->pw_uid, pw->pw_gid);
-
- debug("Kerberos v4 TGT accepted (%s%s%s@%s)",
- creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
- memset(&creds, 0, sizeof(creds));
-
- restore_uid();
-
- return (1);
-
- failure:
- krb4_cleanup_proc(authctxt);
- memset(&creds, 0, sizeof(creds));
- restore_uid();
-
- return (0);
-}
-
-int
-auth_afs_token(Authctxt *authctxt, const char *token_string)
-{
- CREDENTIALS creds;
- struct passwd *pw;
- uid_t uid;
-
- if ((pw = authctxt->pw) == NULL)
- return (0);
-
- if (!radix_to_creds(token_string, &creds)) {
- log("Protocol error decoding AFS token");
- return (0);
- }
- if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
- strlcpy(creds.service, "afs", sizeof creds.service);
-
- if (strncmp(creds.pname, "AFS ID ", 7) == 0)
- uid = atoi(creds.pname + 7);
- else
- uid = pw->pw_uid;
-
- if (kafs_settoken(creds.realm, uid, &creds)) {
- log("AFS token (%s@%s) rejected for %s",
- creds.pname, creds.realm, pw->pw_name);
- memset(&creds, 0, sizeof(creds));
- return (0);
- }
- debug("AFS token accepted (%s@%s)", creds.pname, creds.realm);
- memset(&creds, 0, sizeof(creds));
-
- return (1);
-}
-#endif /* AFS */
diff --git a/usr/src/cmd/ssh/sshd/auth-krb5.c b/usr/src/cmd/ssh/sshd/auth-krb5.c
deleted file mode 100644
index 3f5416af41..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-krb5.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Kerberos v5 authentication and ticket-passing routines.
- *
- * $FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar Exp $
- */
-/*
- * Copyright (c) 2002 Daniel Kouril. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-krb5.c,v 1.9 2002/09/09 06:48:06 itojun Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "ssh.h"
-#include "ssh1.h"
-#include "packet.h"
-#include "xmalloc.h"
-#include "log.h"
-#include "servconf.h"
-#include "uidswap.h"
-#include "auth.h"
-
-#ifdef KRB5
-#include <krb5.h>
-#ifndef HEIMDAL
-#define krb5_get_err_text(context,code) error_message(code)
-#endif /* !HEIMDAL */
-
-extern ServerOptions options;
-
-static int
-krb5_init(void *context)
-{
- Authctxt *authctxt = (Authctxt *)context;
- krb5_error_code problem;
- static int cleanup_registered = 0;
-
- if (authctxt->krb5_ctx == NULL) {
- problem = krb5_init_context(&authctxt->krb5_ctx);
- if (problem)
- return (problem);
- krb5_init_ets(authctxt->krb5_ctx);
- }
- if (!cleanup_registered) {
- fatal_add_cleanup(krb5_cleanup_proc, authctxt);
- cleanup_registered = 1;
- }
- return (0);
-}
-
-/*
- * Try krb5 authentication. server_user is passed for logging purposes
- * only, in auth is received ticket, in client is returned principal
- * from the ticket
- */
-int
-auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *reply)
-{
- krb5_error_code problem;
- krb5_principal server;
- krb5_ticket *ticket;
- int fd, ret;
-
- ret = 0;
- server = NULL;
- ticket = NULL;
- reply->length = 0;
-
- problem = krb5_init(authctxt);
- if (problem)
- goto err;
-
- problem = krb5_auth_con_init(authctxt->krb5_ctx,
- &authctxt->krb5_auth_ctx);
- if (problem)
- goto err;
-
- fd = packet_get_connection_in();
-#ifdef HEIMDAL
- problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx,
- authctxt->krb5_auth_ctx, &fd);
-#else
- problem = krb5_auth_con_genaddrs(authctxt->krb5_ctx,
- authctxt->krb5_auth_ctx,fd,
- KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR |
- KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
-#endif
- if (problem)
- goto err;
-
- problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL ,
- KRB5_NT_SRV_HST, &server);
- if (problem)
- goto err;
-
- problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx,
- auth, server, NULL, NULL, &ticket);
- if (problem)
- goto err;
-
-#ifdef HEIMDAL
- problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client,
- &authctxt->krb5_user);
-#else
- problem = krb5_copy_principal(authctxt->krb5_ctx,
- ticket->enc_part2->client,
- &authctxt->krb5_user);
-#endif
- if (problem)
- goto err;
-
- /* if client wants mutual auth */
- problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
- reply);
- if (problem)
- goto err;
-
- /* Check .k5login authorization now. */
- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
- authctxt->pw->pw_name))
- goto err;
-
- if (client)
- krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
- client);
-
- ret = 1;
- err:
- if (server)
- krb5_free_principal(authctxt->krb5_ctx, server);
- if (ticket)
- krb5_free_ticket(authctxt->krb5_ctx, ticket);
- if (!ret && reply->length) {
- xfree(reply->data);
- memset(reply, 0, sizeof(*reply));
- }
-
- if (problem) {
- if (authctxt->krb5_ctx != NULL)
- debug("Kerberos v5 authentication failed: %s",
- krb5_get_err_text(authctxt->krb5_ctx, problem));
- else
- debug("Kerberos v5 authentication failed: %d",
- problem);
- }
-
- return (ret);
-}
-
-int
-auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt)
-{
- krb5_error_code problem;
- krb5_ccache ccache = NULL;
- char *pname;
- krb5_creds **creds;
-
- if (authctxt->pw == NULL || authctxt->krb5_user == NULL)
- return (0);
-
- temporarily_use_uid(authctxt->pw);
-
-#ifdef HEIMDAL
- problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
-#else
-{
- char ccname[40];
- int tmpfd;
-
- snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
-
- if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
- log("mkstemp(): %.100s", strerror(errno));
- problem = errno;
- goto fail;
- }
- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
- log("fchmod(): %.100s", strerror(errno));
- close(tmpfd);
- problem = errno;
- goto fail;
- }
- close(tmpfd);
- problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &ccache);
-}
-#endif
- if (problem)
- goto fail;
-
- problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
- authctxt->krb5_user);
- if (problem)
- goto fail;
-
-#ifdef HEIMDAL
- problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
- ccache, tgt);
- if (problem)
- goto fail;
-#else
- problem = krb5_rd_cred(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
- tgt, &creds, NULL);
- if (problem)
- goto fail;
- problem = krb5_cc_store_cred(authctxt->krb5_ctx, ccache, *creds);
- if (problem)
- goto fail;
-#endif
-
- authctxt->krb5_fwd_ccache = ccache;
- ccache = NULL;
-
- authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
-
- problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
- &pname);
- if (problem)
- goto fail;
-
- debug("Kerberos v5 TGT accepted (%s)", pname);
-
- restore_uid();
-
- return (1);
-
- fail:
- if (problem)
- debug("Kerberos v5 TGT passing failed: %s",
- krb5_get_err_text(authctxt->krb5_ctx, problem));
- if (ccache)
- krb5_cc_destroy(authctxt->krb5_ctx, ccache);
-
- restore_uid();
-
- return (0);
-}
-
-int
-auth_krb5_password(Authctxt *authctxt, const char *password)
-{
-#ifndef HEIMDAL
- krb5_creds creds;
- krb5_principal server;
- char ccname[40];
- int tmpfd;
-#endif
- krb5_error_code problem;
-
- if (authctxt->pw == NULL)
- return (0);
-
- temporarily_use_uid(authctxt->pw);
-
- problem = krb5_init(authctxt);
- if (problem)
- goto out;
-
- problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name,
- &authctxt->krb5_user);
- if (problem)
- goto out;
-
-#ifdef HEIMDAL
- problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops,
- &authctxt->krb5_fwd_ccache);
- if (problem)
- goto out;
-
- problem = krb5_cc_initialize(authctxt->krb5_ctx,
- authctxt->krb5_fwd_ccache, authctxt->krb5_user);
- if (problem)
- goto out;
-
- restore_uid();
- problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
- authctxt->krb5_fwd_ccache, password, 1, NULL);
- temporarily_use_uid(authctxt->pw);
-
- if (problem)
- goto out;
-
-#else
- problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds,
- authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL);
- if (problem)
- goto out;
-
- problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
- KRB5_NT_SRV_HST, &server);
- if (problem)
- goto out;
-
- restore_uid();
- problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server,
- NULL, NULL, NULL);
- krb5_free_principal(authctxt->krb5_ctx, server);
- temporarily_use_uid(authctxt->pw);
- if (problem)
- goto out;
-
- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
- authctxt->pw->pw_name)) {
- problem = -1;
- goto out;
- }
-
- snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
-
- if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
- log("mkstemp(): %.100s", strerror(errno));
- problem = errno;
- goto out;
- }
-
- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
- log("fchmod(): %.100s", strerror(errno));
- close(tmpfd);
- problem = errno;
- goto out;
- }
- close(tmpfd);
-
- problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &authctxt->krb5_fwd_ccache);
- if (problem)
- goto out;
-
- problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
- authctxt->krb5_user);
- if (problem)
- goto out;
-
- problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
- &creds);
- if (problem)
- goto out;
-#endif
-
- authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
-
- out:
- restore_uid();
-
- if (problem) {
- if (authctxt->krb5_ctx != NULL && problem!=-1)
- debug("Kerberos password authentication failed: %s",
- krb5_get_err_text(authctxt->krb5_ctx, problem));
- else
- debug("Kerberos password authentication failed: %d",
- problem);
-
- krb5_cleanup_proc(authctxt);
-
- if (options.kerberos_or_local_passwd)
- return (-1);
- else
- return (0);
- }
- return (1);
-}
-
-void
-krb5_cleanup_proc(void *context)
-{
- Authctxt *authctxt = (Authctxt *)context;
-
- debug("krb5_cleanup_proc called");
- if (authctxt->krb5_fwd_ccache) {
- krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
- authctxt->krb5_fwd_ccache = NULL;
- }
- if (authctxt->krb5_user) {
- krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
- authctxt->krb5_user = NULL;
- }
- if (authctxt->krb5_auth_ctx) {
- krb5_auth_con_free(authctxt->krb5_ctx,
- authctxt->krb5_auth_ctx);
- authctxt->krb5_auth_ctx = NULL;
- }
- if (authctxt->krb5_ctx) {
- krb5_free_context(authctxt->krb5_ctx);
- authctxt->krb5_ctx = NULL;
- }
-}
-
-#endif /* KRB5 */
diff --git a/usr/src/cmd/ssh/sshd/auth-options.c b/usr/src/cmd/ssh/sshd/auth-options.c
deleted file mode 100644
index b186cbe045..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-options.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-options.c,v 1.26 2002/07/30 17:03:55 markus Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "xmalloc.h"
-#include "match.h"
-#include "log.h"
-#include "canohost.h"
-#include "channels.h"
-#include "auth-options.h"
-#include "servconf.h"
-#include "misc.h"
-#include "auth.h"
-
-/* Flags set authorized_keys flags */
-int no_port_forwarding_flag = 0;
-int no_agent_forwarding_flag = 0;
-int no_x11_forwarding_flag = 0;
-int no_pty_flag = 0;
-
-/* "command=" option. */
-char *forced_command = NULL;
-
-/* "environment=" options. */
-struct envstring *custom_environment = NULL;
-
-extern ServerOptions options;
-
-void
-auth_clear_options(void)
-{
- no_agent_forwarding_flag = 0;
- no_port_forwarding_flag = 0;
- no_pty_flag = 0;
- no_x11_forwarding_flag = 0;
- while (custom_environment) {
- struct envstring *ce = custom_environment;
- custom_environment = ce->next;
- xfree(ce->s);
- xfree(ce);
- }
- if (forced_command) {
- xfree(forced_command);
- forced_command = NULL;
- }
- channel_clear_permitted_opens();
- auth_debug_reset();
-}
-
-/*
- * return 1 if access is granted, 0 if not.
- * side effect: sets key option flags
- */
-int
-auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
-{
- const char *cp;
- int i;
-
- /* reset options */
- auth_clear_options();
-
- if (!opts)
- return 1;
-
- while (*opts && *opts != ' ' && *opts != '\t') {
- cp = "no-port-forwarding";
- if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- auth_debug_add("Port forwarding disabled.");
- no_port_forwarding_flag = 1;
- opts += strlen(cp);
- goto next_option;
- }
- cp = "no-agent-forwarding";
- if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- auth_debug_add("Agent forwarding disabled.");
- no_agent_forwarding_flag = 1;
- opts += strlen(cp);
- goto next_option;
- }
- cp = "no-X11-forwarding";
- if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- auth_debug_add("X11 forwarding disabled.");
- no_x11_forwarding_flag = 1;
- opts += strlen(cp);
- goto next_option;
- }
- cp = "no-pty";
- if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- auth_debug_add("Pty allocation disabled.");
- no_pty_flag = 1;
- opts += strlen(cp);
- goto next_option;
- }
- cp = "command=\"";
- if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- opts += strlen(cp);
- forced_command = xmalloc(strlen(opts) + 1);
- i = 0;
- while (*opts) {
- if (*opts == '"')
- break;
- if (*opts == '\\' && opts[1] == '"') {
- opts += 2;
- forced_command[i++] = '"';
- continue;
- }
- forced_command[i++] = *opts++;
- }
- if (!*opts) {
- debug("%.100s, line %lu: missing end quote",
- file, linenum);
- auth_debug_add("%.100s, line %lu: missing end quote",
- file, linenum);
- xfree(forced_command);
- forced_command = NULL;
- goto bad_option;
- }
- forced_command[i] = 0;
- auth_debug_add("Forced command: %.900s", forced_command);
- opts++;
- goto next_option;
- }
- cp = "environment=\"";
- if (options.permit_user_env &&
- strncasecmp(opts, cp, strlen(cp)) == 0) {
- char *s;
- struct envstring *new_envstring;
-
- opts += strlen(cp);
- s = xmalloc(strlen(opts) + 1);
- i = 0;
- while (*opts) {
- if (*opts == '"')
- break;
- if (*opts == '\\' && opts[1] == '"') {
- opts += 2;
- s[i++] = '"';
- continue;
- }
- s[i++] = *opts++;
- }
- if (!*opts) {
- debug("%.100s, line %lu: missing end quote",
- file, linenum);
- auth_debug_add("%.100s, line %lu: missing end quote",
- file, linenum);
- xfree(s);
- goto bad_option;
- }
- s[i] = 0;
- auth_debug_add("Adding to environment: %.900s", s);
- debug("Adding to environment: %.900s", s);
- opts++;
- new_envstring = xmalloc(sizeof(struct envstring));
- new_envstring->s = s;
- new_envstring->next = custom_environment;
- custom_environment = new_envstring;
- goto next_option;
- }
- cp = "from=\"";
- if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- const char *remote_ip = get_remote_ipaddr();
- const char *remote_host = get_canonical_hostname(
- options.verify_reverse_mapping);
- char *patterns = xmalloc(strlen(opts) + 1);
-
- opts += strlen(cp);
- i = 0;
- while (*opts) {
- if (*opts == '"')
- break;
- if (*opts == '\\' && opts[1] == '"') {
- opts += 2;
- patterns[i++] = '"';
- continue;
- }
- patterns[i++] = *opts++;
- }
- if (!*opts) {
- debug("%.100s, line %lu: missing end quote",
- file, linenum);
- auth_debug_add("%.100s, line %lu: missing end quote",
- file, linenum);
- xfree(patterns);
- goto bad_option;
- }
- patterns[i] = 0;
- opts++;
- if (match_host_and_ip(remote_host, remote_ip,
- patterns) != 1) {
- xfree(patterns);
- log("Authentication tried for %.100s with "
- "correct key but not from a permitted "
- "host (host=%.200s, ip=%.200s).",
- pw->pw_name, remote_host, remote_ip);
- auth_debug_add("Your host '%.200s' is not "
- "permitted to use this key for login.",
- remote_host);
- /* deny access */
- return 0;
- }
- xfree(patterns);
- /* Host name matches. */
- goto next_option;
- }
- cp = "permitopen=\"";
- if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- char host[256], sport[6];
- u_short port;
- char *patterns = xmalloc(strlen(opts) + 1);
-
- opts += strlen(cp);
- i = 0;
- while (*opts) {
- if (*opts == '"')
- break;
- if (*opts == '\\' && opts[1] == '"') {
- opts += 2;
- patterns[i++] = '"';
- continue;
- }
- patterns[i++] = *opts++;
- }
- if (!*opts) {
- debug("%.100s, line %lu: missing end quote",
- file, linenum);
- auth_debug_add("%.100s, line %lu: missing end quote",
- file, linenum);
- xfree(patterns);
- goto bad_option;
- }
- patterns[i] = 0;
- opts++;
- if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 &&
- sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
- debug("%.100s, line %lu: Bad permitopen specification "
- "<%.100s>", file, linenum, patterns);
- auth_debug_add("%.100s, line %lu: "
- "Bad permitopen specification", file, linenum);
- xfree(patterns);
- goto bad_option;
- }
- if ((port = a2port(sport)) == 0) {
- debug("%.100s, line %lu: Bad permitopen port <%.100s>",
- file, linenum, sport);
- auth_debug_add("%.100s, line %lu: "
- "Bad permitopen port", file, linenum);
- xfree(patterns);
- goto bad_option;
- }
- if (options.allow_tcp_forwarding)
- channel_add_permitted_opens(host, port);
- xfree(patterns);
- goto next_option;
- }
-next_option:
- /*
- * Skip the comma, and move to the next option
- * (or break out if there are no more).
- */
- if (!*opts)
- fatal("Bugs in auth-options.c option processing.");
- if (*opts == ' ' || *opts == '\t')
- break; /* End of options. */
- if (*opts != ',')
- goto bad_option;
- opts++;
- /* Process the next option. */
- }
-
- auth_debug_send();
-
- /* grant access */
- return 1;
-
-bad_option:
- log("Bad options in %.100s file, line %lu: %.50s",
- file, linenum, opts);
- auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
- file, linenum, opts);
-
- auth_debug_send();
-
- /* deny access */
- return 0;
-}
diff --git a/usr/src/cmd/ssh/sshd/auth-pam.c b/usr/src/cmd/ssh/sshd/auth-pam.c
deleted file mode 100644
index c3686b4928..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-pam.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Copyright (c) 2000 Damien Miller. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include "includes.h"
-
-#ifdef USE_PAM
-#include "xmalloc.h"
-#include "log.h"
-#include "auth.h"
-#include "auth-options.h"
-#include "auth-pam.h"
-#include "buffer.h"
-#include "servconf.h"
-#include "canohost.h"
-#include "compat.h"
-#include "misc.h"
-#include "sshlogin.h"
-#include "ssh-gss.h"
-
-#include <security/pam_appl.h>
-
-extern char *__progname;
-
-extern u_int utmp_len;
-extern ServerOptions options;
-
-extern Authmethod method_kbdint;
-
-RCSID("$Id: auth-pam.c,v 1.54 2002/07/28 20:24:08 stevesk Exp $");
-
-#define NEW_AUTHTOK_MSG \
- "Warning: Your password has expired, please change it now."
-
-/* PAM conversation for non-interactive userauth methods */
-static int do_pam_conversation(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr);
-
-static void do_pam_cleanup_proc(void *context);
-
-static char *get_method_name(Authctxt *authctxt);
-
-/* PAM conversation for non-interactive userauth methods */
-static struct pam_conv conv = {
- (int (*)())do_pam_conversation,
- NULL
-};
-static char *__pam_msg = NULL;
-
-static
-char *
-get_method_name(Authctxt *authctxt)
-{
- if (!authctxt)
- return "(unknown)";
-
- if (!compat20)
- return (authctxt->v1_auth_name) ? authctxt->v1_auth_name :
- "(sshv1-unknown)";
-
- if (!authctxt->method || !authctxt->method->name)
- return "(sshv2-unknown)";
-
- return authctxt->method->name;
-}
-
-char *
-derive_pam_service_name(Authmethod *method)
-{
- char *svcname = xmalloc(BUFSIZ);
-
- /*
- * If PamServiceName is set we use that for everything, including
- * SSHv1
- */
- if (options.pam_service_name != NULL) {
- (void) strlcpy(svcname, options.pam_service_name, BUFSIZ);
- return (svcname);
- }
-
- if (compat20 && method) {
- char *method_name = method->name;
-
- if (!method_name)
- fatal("Userauth method unknown while starting PAM");
-
- /*
- * For SSHv2 we use "sshd-<userauth name>
- * The "sshd" prefix can be changed via the PAMServicePrefix
- * sshd_config option.
- */
- if (strcmp(method_name, "none") == 0) {
- snprintf(svcname, BUFSIZ, "%s-none",
- options.pam_service_prefix);
- }
- if (strcmp(method_name, "password") == 0) {
- snprintf(svcname, BUFSIZ, "%s-password",
- options.pam_service_prefix);
- }
- if (strcmp(method_name, "keyboard-interactive") == 0) {
- /* "keyboard-interactive" is too long, shorten it */
- snprintf(svcname, BUFSIZ, "%s-kbdint",
- options.pam_service_prefix);
- }
- if (strcmp(method_name, "publickey") == 0) {
- /* "publickey" is too long, shorten it */
- snprintf(svcname, BUFSIZ, "%s-pubkey",
- options.pam_service_prefix);
- }
- if (strcmp(method_name, "hostbased") == 0) {
- /* "hostbased" can't really be shortened... */
- snprintf(svcname, BUFSIZ, "%s-hostbased",
- options.pam_service_prefix);
- }
- if (strncmp(method_name, "gss", 3) == 0) {
- /* "gss" is too short, elongate it */
- snprintf(svcname, BUFSIZ, "%s-gssapi",
- options.pam_service_prefix);
- }
- return svcname;
- } else {
- /* SSHv1 doesn't get to be so cool */
- snprintf(svcname, BUFSIZ, "%s-v1",
- options.pam_service_prefix);
- }
- return svcname;
-}
-
-void
-new_start_pam(Authctxt *authctxt, struct pam_conv *conv)
-{
- int retval;
- pam_handle_t *pamh;
- const char *rhost;
- char *svc;
- char *user = NULL;
- pam_stuff *pam;
-
- if (authctxt == NULL)
- fatal("Internal error during userauth");
-
- if (compat20 && authctxt->method == NULL)
- fatal("Userauth method unknown while starting PAM");
-
- /* PAM service selected here */
- svc = derive_pam_service_name(authctxt->method);
- debug2("Starting PAM service %s for method %s", svc,
- get_method_name(authctxt));
-
- if (authctxt->user != NULL)
- user = authctxt->user;
-
- /* Cleanup previous PAM state */
- if (authctxt->pam != NULL) {
- fatal_remove_cleanup(&do_pam_cleanup_proc, authctxt->pam);
- do_pam_cleanup_proc(authctxt->pam);
- }
-
- pam = xmalloc(sizeof(pam_stuff));
- (void) memset(pam, 0, sizeof(pam_stuff));
-
- /*
- * pam->last_pam_retval has to be and is considered
- * along with pam->state.
- *
- * pam->state = 0; -> no PAM auth, account, etc, work
- * done yet. (Set by memset() above.)
- *
- * pam->last_pam_retval = PAM_SUCCESS; -> meaningless at
- * this point.
- *
- * See finish_userauth_do_pam() below.
- */
- pam->authctxt = authctxt;
- pam->last_pam_retval = PAM_SUCCESS;
-
- authctxt->pam = pam;
-
- /* Free any previously stored text/error PAM prompts */
- if (__pam_msg) {
- xfree(__pam_msg);
- __pam_msg = NULL;
- }
-
- if ((retval = pam_start(svc, user, conv, &pamh)) != PAM_SUCCESS) {
- fatal("PAM initialization failed during %s userauth",
- get_method_name(authctxt));
- }
-
- free(svc);
-
- fatal_add_cleanup((void (*)(void *)) &do_pam_cleanup_proc,
- (void *) authctxt->pam);
-
- rhost = get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping);
- if ((retval = pam_set_item(pamh, PAM_RHOST, rhost)) != PAM_SUCCESS) {
- (void) pam_end(pamh, retval);
- fatal("Could not set PAM_RHOST item during %s userauth",
- get_method_name(authctxt));
- }
-
- if ((retval = pam_set_item(pamh, PAM_TTY, "sshd")) != PAM_SUCCESS) {
- (void) pam_end(pamh, retval);
- fatal("Could not set PAM_TTY item during %s userauth",
- get_method_name(authctxt));
- }
-
- if (authctxt->cuser != NULL)
- if ((retval = pam_set_item(pamh, PAM_AUSER, authctxt->cuser)) != PAM_SUCCESS) {
- (void) pam_end(pamh, retval);
- fatal("Could not set PAM_AUSER item during %s userauth",
- get_method_name(authctxt));
- }
-
- authctxt->pam->h = pamh;
-}
-
-/*
- * To be called from userauth methods, directly (as in keyboard-interactive) or
- * indirectly (from auth_pam_password() or from do_pam_non_initial_userauth().
- *
- * The caller is responsible for calling new_start_pam() first.
- *
- * PAM state is not cleaned up here on error. This is left to subsequent calls
- * to new_start_pam() or to the cleanup function upon authentication error.
- */
-int
-finish_userauth_do_pam(Authctxt *authctxt)
-{
- int retval;
- char *user, *method;
-
- /* Various checks; fail gracefully */
- if (authctxt == NULL || authctxt->pam == NULL)
- return PAM_SYSTEM_ERR; /* shouldn't happen */
-
- if (compat20) {
- if (authctxt->method == NULL || authctxt->method->name == NULL)
- return PAM_SYSTEM_ERR; /* shouldn't happen */
- method = authctxt->method->name;
- } else if ((method = authctxt->v1_auth_name) == NULL)
- return PAM_SYSTEM_ERR; /* shouldn't happen */
-
- if (AUTHPAM_DONE(authctxt))
- return PAM_SYSTEM_ERR; /* shouldn't happen */
-
- if (!(authctxt->pam->state & PAM_S_DONE_ACCT_MGMT)) {
- retval = pam_acct_mgmt(authctxt->pam->h, 0);
- authctxt->pam->last_pam_retval = retval;
- if (retval == PAM_NEW_AUTHTOK_REQD) {
- userauth_force_kbdint();
- return retval;
- }
- if (retval != PAM_SUCCESS)
- return retval;
- authctxt->pam->state |= PAM_S_DONE_ACCT_MGMT;
- }
-
- /*
- * Handle PAM_USER change, if any.
- *
- * We do this before pam_open_session() because we need the PAM_USER's
- * UID for:
- *
- * a) PermitRootLogin checking
- * b) to get at the lastlog entry before pam_open_session() updates it.
- */
- retval = pam_get_item(authctxt->pam->h, PAM_USER, (void **) &user);
- if (retval != PAM_SUCCESS) {
- fatal("PAM failure: pam_get_item(PAM_USER) "
- "returned %d: %.200s", retval,
- PAM_STRERROR(authctxt->pam->h, retval));
- }
-
- if (user == NULL || *user == '\0') {
- debug("PAM set NULL PAM_USER");
- return PAM_PERM_DENIED;
- }
-
- if (strcmp(user, authctxt->user) != 0) {
- log("PAM changed the SSH username");
- pwfree(&authctxt->pw);
- authctxt->pw = getpwnamallow(user);
- authctxt->valid = (authctxt->pw != NULL);
- xfree(authctxt->user);
- authctxt->user = xstrdup(user);
- }
-
- if (!authctxt->valid) {
- debug2("PAM set PAM_USER to unknown user");
- /*
- * Return success, userauth_finish() will catch
- * this and send back a failure message.
- */
- return PAM_SUCCESS;
- }
-
- /* Check PermitRootLogin semantics */
- if (authctxt->pw->pw_uid == 0 && !auth_root_allowed(method))
- return PAM_PERM_DENIED;
-
- if (!(authctxt->pam->state & PAM_S_DONE_SETCRED)) {
- retval = pam_setcred(authctxt->pam->h,
- PAM_ESTABLISH_CRED);
- authctxt->pam->last_pam_retval = retval;
- if (retval != PAM_SUCCESS)
- return retval;
- authctxt->pam->state |= PAM_S_DONE_SETCRED;
-
-#ifdef GSSAPI
- /*
- * Store GSS-API delegated creds after pam_setcred(), which may
- * have set the current credential store.
- */
- ssh_gssapi_storecreds(NULL, authctxt);
-#endif /* GSSAPI */
- }
-
- /*
- * On Solaris pam_unix_session.so updates the lastlog, but does
- * not converse a PAM_TEXT_INFO message about it. So we need to
- * fetch the lastlog entry here and save it for use later.
- */
- authctxt->last_login_time =
- get_last_login_time(authctxt->pw->pw_uid,
- authctxt->pw->pw_name,
- authctxt->last_login_host,
- sizeof(authctxt->last_login_host));
-
- if (!(authctxt->pam->state & PAM_S_DONE_OPEN_SESSION)) {
- retval = pam_open_session(authctxt->pam->h, 0);
- authctxt->pam->last_pam_retval = retval;
- if (retval != PAM_SUCCESS)
- return retval;
- authctxt->pam->state |= PAM_S_DONE_OPEN_SESSION;
- }
-
- /*
- * All PAM work done successfully.
- *
- * PAM handle stays around so we can call pam_close_session() on
- * it later.
- */
- return PAM_SUCCESS;
-}
-
-/*
- * PAM conversation function for non-interactive userauth methods that
- * really cannot do any prompting. Password userauth and CHANGEREQ can
- * always set the PAM_AUTHTOK and PAM_OLDAUTHTOK items to avoid
- * conversation (and if they do and nonetheless some module tries to
- * converse, then password userauth / CHANGEREQ MUST fail).
- *
- * Except, PAM_TEXT_INFO and PAM_ERROR_MSG prompts can be squirelled
- * away and shown to the user later.
- *
- * Keyboard-interactive userauth has its own much more interesting
- * conversation function.
- *
- */
-static int
-do_pam_conversation(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr)
-{
- struct pam_response *reply;
- int count;
-
- /* PAM will free this later */
- reply = xmalloc(num_msg * sizeof(*reply));
-
- (void) memset(reply, 0, num_msg * sizeof(*reply));
-
- for (count = 0; count < num_msg; count++) {
- /*
- * We can't use stdio yet, queue messages for
- * printing later
- */
- switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
- case PAM_PROMPT_ECHO_ON:
- xfree(reply);
- return PAM_CONV_ERR;
- case PAM_PROMPT_ECHO_OFF:
- xfree(reply);
- return PAM_CONV_ERR;
- break;
- case PAM_ERROR_MSG:
- case PAM_TEXT_INFO:
- if (PAM_MSG_MEMBER(msg, count, msg) != NULL) {
- message_cat(&__pam_msg,
- PAM_MSG_MEMBER(msg, count, msg));
- }
- reply[count].resp = xstrdup("");
- reply[count].resp_retcode = PAM_SUCCESS;
- break;
- default:
- xfree(reply);
- return PAM_CONV_ERR;
- }
- }
-
- *resp = reply;
-
- return PAM_SUCCESS;
-}
-
-/* Called at exit to cleanly shutdown PAM */
-static void
-do_pam_cleanup_proc(void *context)
-{
- int pam_retval;
- pam_stuff *pam = (pam_stuff *) context;
-
- if (pam == NULL)
- return;
-
- if (pam->authctxt != NULL && pam->authctxt->pam == pam) {
- pam->authctxt->pam_retval = pam->last_pam_retval;
- pam->authctxt->pam = NULL;
- pam->authctxt = NULL;
- }
-
- if (pam->h == NULL)
- return;
-
- /*
- * We're in fatal_cleanup() or not in userauth or without a
- * channel -- can't converse now, too bad.
- */
- pam_retval = pam_set_item(pam->h, PAM_CONV, NULL);
- if (pam_retval != PAM_SUCCESS) {
- log("Cannot remove PAM conv, close session or delete creds[%d]: %.200s",
- pam_retval, PAM_STRERROR(pam->h, pam_retval));
- goto cleanup;
- }
-
- if (pam->state & PAM_S_DONE_OPEN_SESSION) {
- pam_retval = pam_close_session(pam->h, 0);
- if (pam_retval != PAM_SUCCESS)
- log("Cannot close PAM session[%d]: %.200s",
- pam_retval, PAM_STRERROR(pam->h, pam_retval));
- }
-
- if (pam->state & PAM_S_DONE_SETCRED) {
- pam_retval = pam_setcred(pam->h, PAM_DELETE_CRED);
- if (pam_retval != PAM_SUCCESS)
- debug("Cannot delete credentials[%d]: %.200s",
- pam_retval, PAM_STRERROR(pam->h, pam_retval));
- }
-
-cleanup:
-
- /* Use the previous PAM result, if not PAM_SUCCESS for pam_end() */
- if (pam->last_pam_retval != PAM_SUCCESS)
- pam_retval = pam_end(pam->h, pam->last_pam_retval);
- else if (pam_retval != PAM_SUCCESS)
- pam_retval = pam_end(pam->h, pam_retval);
- else
- pam_retval = pam_end(pam->h, PAM_ABORT);
-
- if (pam_retval != PAM_SUCCESS)
- log("Cannot release PAM authentication[%d]: %.200s",
- pam_retval, PAM_STRERROR(pam->h, pam_retval));
-
- xfree(pam);
-}
-
-/* Attempt password authentation using PAM */
-int
-auth_pam_password(Authctxt *authctxt, const char *password)
-{
- int retval;
-
- /* Ensure we have a fresh PAM handle / state */
- new_start_pam(authctxt, &conv);
-
- retval = pam_set_item(authctxt->pam->h, PAM_AUTHTOK, password);
- if (retval != PAM_SUCCESS) {
- authctxt->pam->last_pam_retval = retval;
- return 1;
- }
-
- retval = pam_authenticate(authctxt->pam->h,
- options.permit_empty_passwd ? 0 :
- PAM_DISALLOW_NULL_AUTHTOK);
-
- if (retval != PAM_SUCCESS) {
- authctxt->pam->last_pam_retval = retval;
- return 0;
- }
-
- if ((retval = finish_userauth_do_pam(authctxt)) != PAM_SUCCESS)
- return 0;
-
- if (authctxt->method)
- authctxt->method->authenticated = 1; /* SSHv2 */
-
- return 1;
-}
-
-int
-do_pam_non_initial_userauth(Authctxt *authctxt)
-{
- new_start_pam(authctxt, NULL);
- return (finish_userauth_do_pam(authctxt) == PAM_SUCCESS);
-}
-
-/* Cleanly shutdown PAM */
-void finish_pam(Authctxt *authctxt)
-{
- fatal_remove_cleanup(&do_pam_cleanup_proc, authctxt->pam);
- do_pam_cleanup_proc(authctxt->pam);
-}
-
-static
-char **
-find_env(char **env, char *var)
-{
- char **p;
- int len;
-
- if (strchr(var, '=') == NULL)
- len = strlen(var);
- else
- len = (strchr(var, '=') - var) + 1;
-
- for ( p = env ; p != NULL && *p != NULL ; p++ ) {
- if (strncmp(*p, var, len) == 0)
- return (p);
- }
-
- return (NULL);
-}
-
-/* Return list of PAM environment strings */
-char **
-fetch_pam_environment(Authctxt *authctxt)
-{
-#ifdef HAVE_PAM_GETENVLIST
- char **penv;
-
- if (authctxt == NULL || authctxt->pam == NULL ||
- authctxt->pam->h == NULL)
- return (NULL);
-
- penv = pam_getenvlist(authctxt->pam->h);
-
- return (penv);
-#else /* HAVE_PAM_GETENVLIST */
- return(NULL);
-#endif /* HAVE_PAM_GETENVLIST */
-}
-
-void free_pam_environment(char **env)
-{
- int i;
-
- if (env != NULL) {
- for (i = 0; env[i] != NULL; i++)
- xfree(env[i]);
- }
-
- xfree(env);
-}
-
-/* Print any messages that have been generated during authentication */
-/* or account checking to stderr */
-void print_pam_messages(void)
-{
- if (__pam_msg != NULL)
- (void) fputs(__pam_msg, stderr);
-}
-
-/* Append a message to buffer */
-void message_cat(char **p, const char *a)
-{
- char *cp;
- size_t new_len;
-
- new_len = strlen(a);
-
- if (*p) {
- size_t len = strlen(*p);
-
- *p = xrealloc(*p, new_len + len + 2);
- cp = *p + len;
- } else
- *p = cp = xmalloc(new_len + 2);
-
- (void) memcpy(cp, a, new_len);
- cp[new_len] = '\n';
- cp[new_len + 1] = '\0';
-}
-
-#endif /* USE_PAM */
diff --git a/usr/src/cmd/ssh/sshd/auth-passwd.c b/usr/src/cmd/ssh/sshd/auth-passwd.c
deleted file mode 100644
index 815231d4d4..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-passwd.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Password authentication. This file contains the functions to check whether
- * the password is valid for the user.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- *
- * Copyright (c) 1999 Dug Song. All rights reserved.
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-passwd.c,v 1.27 2002/05/24 16:45:16 stevesk Exp $");
-
-#include "packet.h"
-#include "log.h"
-#include "servconf.h"
-#include "auth.h"
-
-#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA)
-/* Don't need any of these headers for the PAM or SIA cases */
-# ifdef HAVE_CRYPT_H
-# include <crypt.h>
-# endif
-# ifdef WITH_AIXAUTHENTICATE
-# include <login.h>
-# endif
-# ifdef __hpux
-# include <hpsecurity.h>
-# include <prot.h>
-# endif
-# if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
-# include <shadow.h>
-# endif
-# if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW)
-# include <sys/label.h>
-# include <sys/audit.h>
-# include <pwdadj.h>
-# endif
-# if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
-# include "md5crypt.h"
-# endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
-
-# ifdef HAVE_CYGWIN
-# undef ERROR
-# include <windows.h>
-# include <sys/cygwin.h>
-# define is_winnt (GetVersion() < 0x80000000)
-# endif
-#endif /* !USE_PAM && !HAVE_OSF_SIA */
-
-extern ServerOptions options;
-#ifdef WITH_AIXAUTHENTICATE
-extern char *aixloginmsg;
-#endif
-
-/*
- * Tries to authenticate the user using password. Returns true if
- * authentication succeeds.
- */
-int
-auth_password(Authctxt *authctxt, const char *password)
-{
-#if defined(USE_PAM)
- if (*password == '\0' && options.permit_empty_passwd == 0)
- return 0;
- return auth_pam_password(authctxt, password);
-#elif defined(HAVE_OSF_SIA)
- if (*password == '\0' && options.permit_empty_passwd == 0)
- return 0;
- return auth_sia_password(authctxt, password);
-#else
- struct passwd * pw = authctxt->pw;
- char *encrypted_password;
- char *pw_password;
- char *salt;
-#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
- struct spwd *spw;
-#endif
-#if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW)
- struct passwd_adjunct *spw;
-#endif
-#ifdef WITH_AIXAUTHENTICATE
- char *authmsg;
- int authsuccess;
- int reenter = 1;
-#endif
-
- /* deny if no user. */
- if (pw == NULL)
- return 0;
-#ifndef HAVE_CYGWIN
- if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
- return 0;
-#endif
- if (*password == '\0' && options.permit_empty_passwd == 0)
- return 0;
-#ifdef KRB5
- if (options.kerberos_authentication == 1) {
- int ret = auth_krb5_password(authctxt, password);
- if (ret == 1 || ret == 0)
- return ret;
- /* Fall back to ordinary passwd authentication. */
- }
-#endif
-#ifdef HAVE_CYGWIN
- if (is_winnt) {
- HANDLE hToken = cygwin_logon_user(pw, password);
-
- if (hToken == INVALID_HANDLE_VALUE)
- return 0;
- cygwin_set_impersonation_token(hToken);
- return 1;
- }
-#endif
-#ifdef WITH_AIXAUTHENTICATE
- authsuccess = (authenticate(pw->pw_name,password,&reenter,&authmsg) == 0);
-
- if (authsuccess)
- /* We don't have a pty yet, so just label the line as "ssh" */
- if (loginsuccess(authctxt->user,
- get_canonical_hostname(options.verify_reverse_mapping),
- "ssh", &aixloginmsg) < 0)
- aixloginmsg = NULL;
-
- return(authsuccess);
-#endif
-#ifdef KRB4
- if (options.kerberos_authentication == 1) {
- int ret = auth_krb4_password(authctxt, password);
- if (ret == 1 || ret == 0)
- return ret;
- /* Fall back to ordinary passwd authentication. */
- }
-#endif
-#ifdef BSD_AUTH
- if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
- (char *)password) == 0)
- return 0;
- else
- return 1;
-#endif
- pw_password = pw->pw_passwd;
-
- /*
- * Various interfaces to shadow or protected password data
- */
-#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
- spw = getspnam(pw->pw_name);
- if (spw != NULL)
- pw_password = spw->sp_pwdp;
-#endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */
-
-#if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW)
- if (issecure() && (spw = getpwanam(pw->pw_name)) != NULL)
- pw_password = spw->pwa_passwd;
-#endif /* defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW) */
-
- /* Check for users with no password. */
- if ((password[0] == '\0') && (pw_password[0] == '\0'))
- return 1;
-
- if (pw_password[0] != '\0')
- salt = pw_password;
- else
- salt = "xx";
-
-#ifdef HAVE_MD5_PASSWORDS
- if (is_md5_salt(salt))
- encrypted_password = md5_crypt(password, salt);
- else
- encrypted_password = crypt(password, salt);
-#else /* HAVE_MD5_PASSWORDS */
- encrypted_password = crypt(password, salt);
-#endif /* HAVE_MD5_PASSWORDS */
-
- /* Authentication is accepted if the encrypted passwords are identical. */
- return (strcmp(encrypted_password, pw_password) == 0);
-#endif /* !USE_PAM && !HAVE_OSF_SIA */
-}
diff --git a/usr/src/cmd/ssh/sshd/auth-rh-rsa.c b/usr/src/cmd/ssh/sshd/auth-rh-rsa.c
deleted file mode 100644
index ab10e1738a..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-rh-rsa.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Rhosts or /etc/hosts.equiv authentication combined with RSA host
- * authentication.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-rh-rsa.c,v 1.34 2002/03/25 09:25:06 markus Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "packet.h"
-#include "uidswap.h"
-#include "log.h"
-#include "servconf.h"
-#include "key.h"
-#include "hostfile.h"
-#include "pathnames.h"
-#include "auth.h"
-#include "canohost.h"
-
-/* import */
-extern ServerOptions options;
-
-int
-auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
- Key *client_host_key)
-{
- HostStatus host_status;
-
- /* Check if we would accept it using rhosts authentication. */
- if (!auth_rhosts(pw, cuser))
- return 0;
-
- host_status = check_key_in_hostfiles(pw, client_host_key,
- chost, _PATH_SSH_SYSTEM_HOSTFILE,
- options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
-
- return (host_status == HOST_OK);
-}
-
-/*
- * Tries to authenticate the user using the .rhosts file and the host using
- * its host key. Returns true if authentication succeeds.
- */
-int
-auth_rhosts_rsa(struct passwd *pw, char *cuser, Key *client_host_key)
-{
- char *chost;
-
- debug("Trying rhosts with RSA host authentication for client user %.100s",
- cuser);
-
- if (pw == NULL || client_host_key == NULL ||
- client_host_key->rsa == NULL)
- return 0;
-
- chost = (char *)get_canonical_hostname(options.verify_reverse_mapping);
- debug("Rhosts RSA authentication: canonical host %.900s", chost);
-
- if (!auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key)) {
- debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
- packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
- return 0;
- }
- /* A matching host key was found and is known. */
-
- /* Perform the challenge-response dialog with the client for the host key. */
- if (!auth_rsa_challenge_dialog(client_host_key)) {
- log("Client on %.800s failed to respond correctly to host authentication.",
- chost);
- return 0;
- }
- /*
- * We have authenticated the user using .rhosts or /etc/hosts.equiv,
- * and the host using RSA. We accept the authentication.
- */
-
- verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
- pw->pw_name, cuser, chost);
- packet_send_debug("Rhosts with RSA host authentication accepted.");
- return 1;
-}
diff --git a/usr/src/cmd/ssh/sshd/auth-rhosts.c b/usr/src/cmd/ssh/sshd/auth-rhosts.c
deleted file mode 100644
index 2326eef8ae..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-rhosts.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Rhosts authentication. This file contains code to check whether to admit
- * the login based on rhosts authentication. This file also processes
- * /etc/hosts.equiv.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-rhosts.c,v 1.28 2002/05/13 21:26:49 markus Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "packet.h"
-#include "uidswap.h"
-#include "pathnames.h"
-#include "log.h"
-#include "servconf.h"
-#include "canohost.h"
-#include "auth.h"
-
-/* import */
-extern ServerOptions options;
-
-/*
- * This function processes an rhosts-style file (.rhosts, .shosts, or
- * /etc/hosts.equiv). This returns true if authentication can be granted
- * based on the file, and returns zero otherwise.
- */
-
-static int
-check_rhosts_file(const char *filename, const char *hostname,
- const char *ipaddr, const char *client_user,
- const char *server_user)
-{
- FILE *f;
- char buf[1024]; /* Must not be larger than host, user, dummy below. */
-
- /* Open the .rhosts file, deny if unreadable */
- f = fopen(filename, "r");
- if (!f)
- return 0;
-
- while (fgets(buf, sizeof(buf), f)) {
- /* All three must be at least as big as buf to avoid overflows. */
- char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
- int negated;
-
- for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (*cp == '#' || *cp == '\n' || !*cp)
- continue;
-
- /*
- * NO_PLUS is supported at least on OSF/1. We skip it (we
- * don't ever support the plus syntax).
- */
- if (strncmp(cp, "NO_PLUS", 7) == 0)
- continue;
-
- /*
- * This should be safe because each buffer is as big as the
- * whole string, and thus cannot be overwritten.
- */
- switch (sscanf(buf, "%1024s %1024s %1024s",
- hostbuf, userbuf, dummy)) {
- case 0:
- auth_debug_add("Found empty line in %.100s.", filename);
- continue;
- case 1:
- /* Host name only. */
- strlcpy(userbuf, server_user, sizeof(userbuf));
- break;
- case 2:
- /* Got both host and user name. */
- break;
- case 3:
- auth_debug_add("Found garbage in %.100s.", filename);
- continue;
- default:
- /* Weird... */
- continue;
- }
-
- host = hostbuf;
- user = userbuf;
- negated = 0;
-
- /* Process negated host names, or positive netgroups. */
- if (host[0] == '-') {
- negated = 1;
- host++;
- } else if (host[0] == '+')
- host++;
-
- if (user[0] == '-') {
- negated = 1;
- user++;
- } else if (user[0] == '+')
- user++;
-
- /* Check for empty host/user names (particularly '+'). */
- if (!host[0] || !user[0]) {
- /* We come here if either was '+' or '-'. */
- auth_debug_add("Ignoring wild host/user names in %.100s.",
- filename);
- continue;
- }
- /* Verify that host name matches. */
- if (host[0] == '@') {
- if (!innetgr(host + 1, hostname, NULL, NULL) &&
- !innetgr(host + 1, ipaddr, NULL, NULL))
- continue;
- } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
- continue; /* Different hostname. */
-
- /* Verify that user name matches. */
- if (user[0] == '@') {
- if (!innetgr(user + 1, NULL, client_user, NULL))
- continue;
- } else if (strcmp(user, client_user) != 0)
- continue; /* Different username. */
-
- /* Found the user and host. */
- fclose(f);
-
- /* If the entry was negated, deny access. */
- if (negated) {
- auth_debug_add("Matched negative entry in %.100s.",
- filename);
- return 0;
- }
- /* Accept authentication. */
- return 1;
- }
-
- /* Authentication using this file denied. */
- fclose(f);
- return 0;
-}
-
-/*
- * Tries to authenticate the user using the .shosts or .rhosts file. Returns
- * true if authentication succeeds. If ignore_rhosts is true, only
- * /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
- */
-
-int
-auth_rhosts(struct passwd *pw, const char *client_user)
-{
- const char *hostname, *ipaddr;
-
- hostname = get_canonical_hostname(options.verify_reverse_mapping);
- ipaddr = get_remote_ipaddr();
- return auth_rhosts2(pw, client_user, hostname, ipaddr);
-}
-
-static int
-auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostname,
- const char *ipaddr)
-{
- char buf[1024];
- struct stat st;
- static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
- u_int rhosts_file_index;
-
- debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s",
- client_user, hostname, ipaddr);
-
- /* no user given */
- if (pw == NULL)
- return 0;
-
- /* Switch to the user's uid. */
- temporarily_use_uid(pw);
- /*
- * Quick check: if the user has no .shosts or .rhosts files, return
- * failure immediately without doing costly lookups from name
- * servers.
- */
- for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
- rhosts_file_index++) {
- /* Check users .rhosts or .shosts. */
- snprintf(buf, sizeof buf, "%.500s/%.100s",
- pw->pw_dir, rhosts_files[rhosts_file_index]);
- if (stat(buf, &st) >= 0)
- break;
- }
- /* Switch back to privileged uid. */
- restore_uid();
-
- /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
- if (!rhosts_files[rhosts_file_index] &&
- stat(_PATH_RHOSTS_EQUIV, &st) < 0 &&
- stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0)
- return 0;
-
- /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
- if (pw->pw_uid != 0) {
- if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr,
- client_user, pw->pw_name)) {
- auth_debug_add("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
- hostname, ipaddr);
- return 1;
- }
- if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr,
- client_user, pw->pw_name)) {
- auth_debug_add("Accepted for %.100s [%.100s] by %.100s.",
- hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
- return 1;
- }
- }
- /*
- * Check that the home directory is owned by root or the user, and is
- * not group or world writable.
- */
- if (stat(pw->pw_dir, &st) < 0) {
- log("Rhosts authentication refused for %.100s: "
- "no home directory %.200s", pw->pw_name, pw->pw_dir);
- auth_debug_add("Rhosts authentication refused for %.100s: "
- "no home directory %.200s", pw->pw_name, pw->pw_dir);
- return 0;
- }
- if (options.strict_modes &&
- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0)) {
- log("Rhosts authentication refused for %.100s: "
- "bad ownership or modes for home directory.", pw->pw_name);
- auth_debug_add("Rhosts authentication refused for %.100s: "
- "bad ownership or modes for home directory.", pw->pw_name);
- return 0;
- }
- /* Temporarily use the user's uid. */
- temporarily_use_uid(pw);
-
- /* Check all .rhosts files (currently .shosts and .rhosts). */
- for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
- rhosts_file_index++) {
- /* Check users .rhosts or .shosts. */
- snprintf(buf, sizeof buf, "%.500s/%.100s",
- pw->pw_dir, rhosts_files[rhosts_file_index]);
- if (stat(buf, &st) < 0)
- continue;
-
- /*
- * Make sure that the file is either owned by the user or by
- * root, and make sure it is not writable by anyone but the
- * owner. This is to help avoid novices accidentally
- * allowing access to their account by anyone.
- */
- if (options.strict_modes &&
- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0)) {
- log("Rhosts authentication refused for %.100s: bad modes for %.200s",
- pw->pw_name, buf);
- auth_debug_add("Bad file modes for %.200s", buf);
- continue;
- }
- /* Check if we have been configured to ignore .rhosts and .shosts files. */
- if (options.ignore_rhosts) {
- auth_debug_add("Server has been configured to ignore %.100s.",
- rhosts_files[rhosts_file_index]);
- continue;
- }
- /* Check if authentication is permitted by the file. */
- if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
- auth_debug_add("Accepted by %.100s.",
- rhosts_files[rhosts_file_index]);
- /* Restore the privileged uid. */
- restore_uid();
- auth_debug_add("Accepted host %s ip %s client_user %s server_user %s",
- hostname, ipaddr, client_user, pw->pw_name);
- return 1;
- }
- }
-
- /* Restore the privileged uid. */
- restore_uid();
- return 0;
-}
-
-int
-auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
- const char *ipaddr)
-{
- int ret;
-
- auth_debug_reset();
- ret = auth_rhosts2_raw(pw, client_user, hostname, ipaddr);
- auth_debug_send();
- return ret;
-}
diff --git a/usr/src/cmd/ssh/sshd/auth-rsa.c b/usr/src/cmd/ssh/sshd/auth-rsa.c
deleted file mode 100644
index 3e0e6ea50d..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-rsa.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * RSA-based authentication. This code determines whether to admit a login
- * based on RSA authentication. This file also contains functions to check
- * validity of the host key.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth-rsa.c,v 1.56 2002/06/10 16:53:06 stevesk Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <openssl/rsa.h>
-#include <openssl/md5.h>
-
-#include "rsa.h"
-#include "packet.h"
-#include "xmalloc.h"
-#include "ssh1.h"
-#include "mpaux.h"
-#include "uidswap.h"
-#include "match.h"
-#include "auth-options.h"
-#include "pathnames.h"
-#include "log.h"
-#include "servconf.h"
-#include "auth.h"
-#include "hostfile.h"
-#include "ssh.h"
-
-/* import */
-extern ServerOptions options;
-
-/*
- * Session identifier that is used to bind key exchange and authentication
- * responses to a particular session.
- */
-extern u_char session_id[16];
-
-/*
- * The .ssh/authorized_keys file contains public keys, one per line, in the
- * following format:
- * options bits e n comment
- * where bits, e and n are decimal numbers,
- * and comment is any string of characters up to newline. The maximum
- * length of a line is 8000 characters. See the documentation for a
- * description of the options.
- */
-
-BIGNUM *
-auth_rsa_generate_challenge(Key *key)
-{
- BIGNUM *challenge;
- BN_CTX *ctx;
-
- if ((challenge = BN_new()) == NULL)
- fatal("auth_rsa_generate_challenge: BN_new() failed");
- /* Generate a random challenge. */
- BN_rand(challenge, 256, 0, 0);
- if ((ctx = BN_CTX_new()) == NULL)
- fatal("auth_rsa_generate_challenge: BN_CTX_new() failed");
- BN_mod(challenge, challenge, key->rsa->n, ctx);
- BN_CTX_free(ctx);
-
- return challenge;
-}
-
-int
-auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
-{
- u_char buf[32], mdbuf[16];
- MD5_CTX md;
- int len;
-
- /* don't allow short keys */
- if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
- error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits",
- BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
- return (0);
- }
-
- /* The response is MD5 of decrypted challenge plus session id. */
- len = BN_num_bytes(challenge);
- if (len <= 0 || len > 32)
- fatal("auth_rsa_verify_response: bad challenge length %d", len);
- memset(buf, 0, 32);
- BN_bn2bin(challenge, buf + 32 - len);
- MD5_Init(&md);
- MD5_Update(&md, buf, 32);
- MD5_Update(&md, session_id, 16);
- MD5_Final(mdbuf, &md);
-
- /* Verify that the response is the original challenge. */
- if (memcmp(response, mdbuf, 16) != 0) {
- /* Wrong answer. */
- return (0);
- }
- /* Correct answer. */
- return (1);
-}
-
-/*
- * Performs the RSA authentication challenge-response dialog with the client,
- * and returns true (non-zero) if the client gave the correct answer to
- * our challenge; returns zero if the client gives a wrong answer.
- */
-
-int
-auth_rsa_challenge_dialog(Key *key)
-{
- BIGNUM *challenge, *encrypted_challenge;
- u_char response[16];
- int i, success;
-
- if ((encrypted_challenge = BN_new()) == NULL)
- fatal("auth_rsa_challenge_dialog: BN_new() failed");
-
- challenge = auth_rsa_generate_challenge(key);
-
- /* Encrypt the challenge with the public key. */
- rsa_public_encrypt(encrypted_challenge, challenge, key->rsa);
-
- /* Send the encrypted challenge to the client. */
- packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
- packet_put_bignum(encrypted_challenge);
- packet_send();
- BN_clear_free(encrypted_challenge);
- packet_write_wait();
-
- /* Wait for a response. */
- packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- response[i] = packet_get_char();
- packet_check_eom();
-
- success = auth_rsa_verify_response(key, challenge, response);
- BN_clear_free(challenge);
- return (success);
-}
-
-/*
- * check if there's user key matching client_n,
- * return key if login is allowed, NULL otherwise
- */
-
-int
-auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
-{
- char line[8192], *file;
- int allowed = 0;
- u_int bits;
- FILE *f;
- u_long linenum = 0;
- struct stat st;
- Key *key;
-
- /* Temporarily use the user's uid. */
- temporarily_use_uid(pw);
-
- /* The authorized keys. */
- file = authorized_keys_file(pw);
- debug("trying public RSA key file %s", file);
-
- /* Fail quietly if file does not exist */
- if (stat(file, &st) < 0) {
- /* Restore the privileged uid. */
- restore_uid();
- xfree(file);
- return (0);
- }
- /* Open the file containing the authorized keys. */
- f = fopen(file, "r");
- if (!f) {
- /* Restore the privileged uid. */
- restore_uid();
- xfree(file);
- return (0);
- }
- if (options.strict_modes &&
- secure_filename(f, file, pw, line, sizeof(line)) != 0) {
- xfree(file);
- fclose(f);
- log("Authentication refused: %s", line);
- restore_uid();
- return (0);
- }
-
- /* Flag indicating whether the key is allowed. */
- allowed = 0;
-
- key = key_new(KEY_RSA1);
-
- /*
- * Go though the accepted keys, looking for the current key. If
- * found, perform a challenge-response dialog to verify that the
- * user really has the corresponding private key.
- */
- while (fgets(line, sizeof(line), f)) {
- char *cp;
- char *options;
-
- linenum++;
-
- /* Skip leading whitespace, empty and comment lines. */
- for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (!*cp || *cp == '\n' || *cp == '#')
- continue;
-
- /*
- * Check if there are options for this key, and if so,
- * save their starting address and skip the option part
- * for now. If there are no options, set the starting
- * address to NULL.
- */
- if (*cp < '0' || *cp > '9') {
- int quoted = 0;
- options = cp;
- for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
- if (*cp == '\\' && cp[1] == '"')
- cp++; /* Skip both */
- else if (*cp == '"')
- quoted = !quoted;
- }
- } else
- options = NULL;
-
- /* Parse the key from the line. */
- if (hostfile_read_key(&cp, &bits, key) == 0) {
- debug("%.100s, line %lu: non ssh1 key syntax",
- file, linenum);
- continue;
- }
- /* cp now points to the comment part. */
-
- /* Check if the we have found the desired key (identified by its modulus). */
- if (BN_cmp(key->rsa->n, client_n) != 0)
- continue;
-
- /* check the real bits */
- if (bits != BN_num_bits(key->rsa->n))
- log("Warning: %s, line %lu: keysize mismatch: "
- "actual %d vs. announced %d.",
- file, linenum, BN_num_bits(key->rsa->n), bits);
-
- /* We have found the desired key. */
- /*
- * If our options do not allow this key to be used,
- * do not send challenge.
- */
- if (!auth_parse_options(pw, options, file, linenum))
- continue;
-
- /* break out, this key is allowed */
- allowed = 1;
- break;
- }
-
- /* Restore the privileged uid. */
- restore_uid();
-
- /* Close the file. */
- xfree(file);
- fclose(f);
-
- /* return key if allowed */
- if (allowed && rkey != NULL)
- *rkey = key;
- else
- key_free(key);
- return (allowed);
-}
-
-/*
- * Performs the RSA authentication dialog with the client. This returns
- * 0 if the client could not be authenticated, and 1 if authentication was
- * successful. This may exit if there is a serious protocol violation.
- */
-int
-auth_rsa(struct passwd *pw, BIGNUM *client_n)
-{
- Key *key;
- char *fp;
-
- /* no user given */
- if (pw == NULL)
- return 0;
-
- if (!auth_rsa_key_allowed(pw, client_n, &key)) {
- auth_clear_options();
- return (0);
- }
-
- /* Perform the challenge-response dialog for this key. */
- if (!auth_rsa_challenge_dialog(key)) {
- /* Wrong response. */
- verbose("Wrong response to RSA authentication challenge.");
- packet_send_debug("Wrong response to RSA authentication challenge.");
- /*
- * Break out of the loop. Otherwise we might send
- * another challenge and break the protocol.
- */
- key_free(key);
- return (0);
- }
- /*
- * Correct response. The client has been successfully
- * authenticated. Note that we have not yet processed the
- * options; this will be reset if the options cause the
- * authentication to be rejected.
- */
- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
- verbose("Found matching %s key: %s",
- key_type(key), fp);
- xfree(fp);
- key_free(key);
-
- packet_send_debug("RSA authentication accepted.");
- return (1);
-}
diff --git a/usr/src/cmd/ssh/sshd/auth-sia.c b/usr/src/cmd/ssh/sshd/auth-sia.c
deleted file mode 100644
index 6afa02cf75..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-sia.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) 2002 Chris Adams. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-
-#include "includes.h"
-
-#ifdef HAVE_OSF_SIA
-#include "ssh.h"
-#include "auth.h"
-#include "auth-sia.h"
-#include "log.h"
-#include "servconf.h"
-#include "canohost.h"
-
-#include <sia.h>
-#include <siad.h>
-#include <pwd.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <sys/resource.h>
-#include <unistd.h>
-#include <string.h>
-
-extern ServerOptions options;
-extern int saved_argc;
-extern char **saved_argv;
-
-extern int errno;
-
-int
-auth_sia_password(Authctxt *authctxt, char *pass)
-{
- int ret;
- SIAENTITY *ent = NULL;
- const char *host;
- char *user = authctxt->user;
-
- host = get_canonical_hostname(options.verify_reverse_mapping);
-
- if (!user || !pass || pass[0] == '\0')
- return(0);
-
- if (sia_ses_init(&ent, saved_argc, saved_argv, host, user, NULL, 0,
- NULL) != SIASUCCESS)
- return(0);
-
- if ((ret = sia_ses_authent(NULL, pass, ent)) != SIASUCCESS) {
- error("Couldn't authenticate %s from %s", user, host);
- if (ret & SIASTOP)
- sia_ses_release(&ent);
- return(0);
- }
-
- sia_ses_release(&ent);
-
- return(1);
-}
-
-void
-session_setup_sia(char *user, char *tty)
-{
- struct passwd *pw;
- SIAENTITY *ent = NULL;
- const char *host;
-
- host = get_canonical_hostname (options.verify_reverse_mapping);
-
- if (sia_ses_init(&ent, saved_argc, saved_argv, host, user, tty, 0,
- NULL) != SIASUCCESS) {
- fatal("sia_ses_init failed");
- }
-
- if ((pw = getpwnam(user)) == NULL) {
- sia_ses_release(&ent);
- fatal("getpwnam: no user: %s", user);
- }
- if (sia_make_entity_pwd(pw, ent) != SIASUCCESS) {
- sia_ses_release(&ent);
- fatal("sia_make_entity_pwd failed");
- }
-
- ent->authtype = SIA_A_NONE;
- if (sia_ses_estab(sia_collect_trm, ent) != SIASUCCESS) {
- fatal("Couldn't establish session for %s from %s", user,
- host);
- }
-
- if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
- sia_ses_release(&ent);
- fatal("setpriority: %s", strerror (errno));
- }
-
- if (sia_ses_launch(sia_collect_trm, ent) != SIASUCCESS) {
- fatal("Couldn't launch session for %s from %s", user, host);
- }
-
- sia_ses_release(&ent);
-
- if (setreuid(geteuid(), geteuid()) < 0) {
- fatal("setreuid: %s", strerror(errno));
- }
-}
-
-#endif /* HAVE_OSF_SIA */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
diff --git a/usr/src/cmd/ssh/sshd/auth-skey.c b/usr/src/cmd/ssh/sshd/auth-skey.c
deleted file mode 100644
index 436f66aed8..0000000000
--- a/usr/src/cmd/ssh/sshd/auth-skey.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2001 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-#include "includes.h"
-RCSID("$OpenBSD: auth-skey.c,v 1.20 2002/06/30 21:59:45 deraadt Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifdef SKEY
-
-#include <skey.h>
-
-#include "xmalloc.h"
-#include "auth.h"
-
-static void *
-skey_init_ctx(Authctxt *authctxt)
-{
- return authctxt;
-}
-
-int
-skey_query(void *ctx, char **name, char **infotxt,
- u_int* numprompts, char ***prompts, u_int **echo_on)
-{
- Authctxt *authctxt = ctx;
- char challenge[1024], *p;
- int len;
- struct skey skey;
-
- if (skeychallenge(&skey, authctxt->user, challenge) == -1)
- return -1;
-
- *name = xstrdup("");
- *infotxt = xstrdup("");
- *numprompts = 1;
- *prompts = xmalloc(*numprompts * sizeof(char *));
- *echo_on = xmalloc(*numprompts * sizeof(u_int));
- (*echo_on)[0] = 0;
-
- len = strlen(challenge) + strlen(SKEY_PROMPT) + 1;
- p = xmalloc(len);
- strlcpy(p, challenge, len);
- strlcat(p, SKEY_PROMPT, len);
- (*prompts)[0] = p;
-
- return 0;
-}
-
-int
-skey_respond(void *ctx, u_int numresponses, char **responses)
-{
- Authctxt *authctxt = ctx;
-
- if (authctxt->valid &&
- numresponses == 1 &&
- skey_haskey(authctxt->pw->pw_name) == 0 &&
- skey_passcheck(authctxt->pw->pw_name, responses[0]) != -1)
- return 0;
- return -1;
-}
-
-static void
-skey_free_ctx(void *ctx)
-{
- /* we don't have a special context */
-}
-
-KbdintDevice skey_device = {
- "skey",
- skey_init_ctx,
- skey_query,
- skey_respond,
- skey_free_ctx
-};
-
-KbdintDevice mm_skey_device = {
- "skey",
- skey_init_ctx,
- mm_skey_query,
- mm_skey_respond,
- skey_free_ctx
-};
-#endif /* SKEY */
diff --git a/usr/src/cmd/ssh/sshd/auth.c b/usr/src/cmd/ssh/sshd/auth.c
deleted file mode 100644
index 64e6959ecf..0000000000
--- a/usr/src/cmd/ssh/sshd/auth.c
+++ /dev/null
@@ -1,794 +0,0 @@
-/*
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.45 2002/09/20 18:41:29 stevesk Exp $");
-
-#ifdef HAVE_LOGIN_H
-#include <login.h>
-#endif
-#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
-#include <shadow.h>
-#endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */
-
-#ifdef HAVE_LIBGEN_H
-#include <libgen.h>
-#endif
-
-#include "xmalloc.h"
-#include "match.h"
-#include "groupaccess.h"
-#include "log.h"
-#include "buffer.h"
-#include "servconf.h"
-#include "auth.h"
-#include "auth-options.h"
-#include "canohost.h"
-#include "bufaux.h"
-#include "uidswap.h"
-#include "tildexpand.h"
-#include "misc.h"
-#include "bufaux.h"
-#include "packet.h"
-#include "channels.h"
-#include "session.h"
-
-#ifdef HAVE_BSM
-#include "bsmaudit.h"
-#include <bsm/adt.h>
-#endif /* HAVE_BSM */
-
-/* import */
-extern ServerOptions options;
-
-/* Debugging messages */
-Buffer auth_debug;
-int auth_debug_init;
-
-/*
- * Check if the user is allowed to log in via ssh. If user is listed
- * in DenyUsers or one of user's groups is listed in DenyGroups, false
- * will be returned. If AllowUsers isn't empty and user isn't listed
- * there, or if AllowGroups isn't empty and one of user's groups isn't
- * listed there, false will be returned.
- * If the user's shell is not executable, false will be returned.
- * Otherwise true is returned.
- */
-int
-allowed_user(struct passwd * pw)
-{
- struct stat st;
- const char *hostname = NULL, *ipaddr = NULL;
- char *shell;
- int i;
-#ifdef WITH_AIXAUTHENTICATE
- char *loginmsg;
-#endif /* WITH_AIXAUTHENTICATE */
-#if !defined(USE_PAM) && defined(HAVE_SHADOW_H) && \
- !defined(DISABLE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
- struct spwd *spw;
-
- /* Shouldn't be called if pw is NULL, but better safe than sorry... */
- if (!pw || !pw->pw_name)
- return 0;
-
-#define DAY (24L * 60 * 60) /* 1 day in seconds */
- spw = getspnam(pw->pw_name);
- if (spw != NULL) {
- time_t today = time(NULL) / DAY;
- debug3("allowed_user: today %d sp_expire %d sp_lstchg %d"
- " sp_max %d", (int)today, (int)spw->sp_expire,
- (int)spw->sp_lstchg, (int)spw->sp_max);
-
- /*
- * We assume account and password expiration occurs the
- * day after the day specified.
- */
- if (spw->sp_expire != -1 && today > spw->sp_expire) {
- log("Account %.100s has expired", pw->pw_name);
- return 0;
- }
-
- if (spw->sp_lstchg == 0) {
- log("User %.100s password has expired (root forced)",
- pw->pw_name);
- return 0;
- }
-
- if (spw->sp_max != -1 &&
- today > spw->sp_lstchg + spw->sp_max) {
- log("User %.100s password has expired (password aged)",
- pw->pw_name);
- return 0;
- }
- }
-#else
- /* Shouldn't be called if pw is NULL, but better safe than sorry... */
- if (!pw || !pw->pw_name)
- return 0;
-#endif
-
- /*
- * Get the shell from the password data. An empty shell field is
- * legal, and means /bin/sh.
- */
- shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
-
- /* deny if shell does not exists or is not executable */
- if (stat(shell, &st) != 0) {
- log("User %.100s not allowed because shell %.100s does not exist",
- pw->pw_name, shell);
- return 0;
- }
- if (S_ISREG(st.st_mode) == 0 ||
- (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
- log("User %.100s not allowed because shell %.100s is not executable",
- pw->pw_name, shell);
- return 0;
- }
-
- if (options.num_deny_users > 0 || options.num_allow_users > 0) {
- hostname = get_canonical_hostname(options.verify_reverse_mapping);
- ipaddr = get_remote_ipaddr();
- }
-
- /* Return false if user is listed in DenyUsers */
- if (options.num_deny_users > 0) {
- for (i = 0; i < options.num_deny_users; i++)
- if (match_user(pw->pw_name, hostname, ipaddr,
- options.deny_users[i])) {
- log("User %.100s not allowed because listed in DenyUsers",
- pw->pw_name);
- return 0;
- }
- }
- /* Return false if AllowUsers isn't empty and user isn't listed there */
- if (options.num_allow_users > 0) {
- for (i = 0; i < options.num_allow_users; i++)
- if (match_user(pw->pw_name, hostname, ipaddr,
- options.allow_users[i]))
- break;
- /* i < options.num_allow_users iff we break for loop */
- if (i >= options.num_allow_users) {
- log("User %.100s not allowed because not listed in AllowUsers",
- pw->pw_name);
- return 0;
- }
- }
- if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
- /* Get the user's group access list (primary and supplementary) */
- if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
- log("User %.100s not allowed because not in any group",
- pw->pw_name);
- return 0;
- }
-
- /* Return false if one of user's groups is listed in DenyGroups */
- if (options.num_deny_groups > 0)
- if (ga_match(options.deny_groups,
- options.num_deny_groups)) {
- ga_free();
- log("User %.100s not allowed because a group is listed in DenyGroups",
- pw->pw_name);
- return 0;
- }
- /*
- * Return false if AllowGroups isn't empty and one of user's groups
- * isn't listed there
- */
- if (options.num_allow_groups > 0)
- if (!ga_match(options.allow_groups,
- options.num_allow_groups)) {
- ga_free();
- log("User %.100s not allowed because none of user's groups are listed in AllowGroups",
- pw->pw_name);
- return 0;
- }
- ga_free();
- }
-
-#ifdef WITH_AIXAUTHENTICATE
- if (loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &loginmsg) != 0) {
- if (loginmsg && *loginmsg) {
- /* Remove embedded newlines (if any) */
- char *p;
- for (p = loginmsg; *p; p++) {
- if (*p == '\n')
- *p = ' ';
- }
- /* Remove trailing newline */
- *--p = '\0';
- log("Login restricted for %s: %.100s", pw->pw_name, loginmsg);
- }
- return 0;
- }
-#endif /* WITH_AIXAUTHENTICATE */
-
- /* We found no reason not to let this user try to log on... */
- return 1;
-}
-
-Authctxt *
-authctxt_new(void)
-{
- Authctxt *authctxt = xmalloc(sizeof(*authctxt));
- memset(authctxt, 0, sizeof(*authctxt));
- return authctxt;
-}
-
-void
-auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
-{
- void (*authlog) (const char *fmt,...) = verbose;
- char *authmsg, *user_str;
-
- if (authctxt == NULL)
- fatal("%s: INTERNAL ERROR", __func__);
-
- /* Raise logging level */
- if (authenticated == 1 || !authctxt->valid)
- authlog = log;
- else if (authctxt->failures >= AUTH_FAIL_LOG ||
- authctxt->attempt >= options.max_auth_tries_log ||
- authctxt->init_attempt >= options.max_init_auth_tries_log)
- authlog = notice;
-
- if (authctxt->method) {
- authmsg = "Failed";
- if (authctxt->method->postponed)
- authmsg = "Postponed"; /* shouldn't happen */
- if (authctxt->method->abandoned)
- authmsg = "Abandoned";
- if (authctxt->method->authenticated) {
- if (userauth_check_partial_failure(authctxt))
- authmsg = "Partially accepted";
- else
- authmsg = "Accepted";
- }
- else
- authmsg = "Failed";
- }
- else {
- authmsg = authenticated ? "Accepted" : "Failed";
- }
-
- if (authctxt->user == NULL || *authctxt->user == '\0')
- user_str = "<implicit>";
- else if (!authctxt->valid)
- user_str = "<invalid username>";
- else
- user_str = authctxt->user;
-
- authlog("%s %s for %s from %.200s port %d%s",
- authmsg,
- (method != NULL) ? method : "<unknown authentication method>",
- user_str,
- get_remote_ipaddr(),
- get_remote_port(),
- info);
-
-#ifdef WITH_AIXAUTHENTICATE
- if (authenticated == 0 && strcmp(method, "password") == 0)
- loginfailed(authctxt->user,
- get_canonical_hostname(options.verify_reverse_mapping),
- "ssh");
-#endif /* WITH_AIXAUTHENTICATE */
-
-}
-
-#ifdef HAVE_BSM
-void
-audit_failed_login_cleanup(void *ctxt)
-{
- Authctxt *authctxt = (Authctxt *)ctxt;
- adt_session_data_t *ah;
-
- /*
- * This table lists the different variable combinations evaluated and
- * what the resulting PAM return value is. As the table shows
- * authctxt and authctxt->valid need to be checked before either of
- * the authctxt->pam* variables.
- *
- * authctxt-> authctxt->
- * authctxt valid authctxt->pam pam_retval PAM rval
- * -------- ---------- ------------- ------------ --------
- * NULL ANY ANY ANY PAM_ABORT
- * OK zero (0) ANY ANY PAM_USER_UNKNOWN
- * OK one (1) NULL PAM_SUCCESS PAM_PERM_DENIED
- * OK one (1) NULL !PAM_SUCCESS authctxt->
- * pam_retval
- * OK one (1) VALID ANY authctxt->
- * pam_retval (+)
- * (+) If not set then default to PAM_PERM_DENIED
- */
-
- if (authctxt == NULL) {
- /* Internal error */
- audit_sshd_login_failure(&ah, PAM_ABORT, NULL);
- return;
- }
-
- if (authctxt->valid == 0) {
- audit_sshd_login_failure(&ah, PAM_USER_UNKNOWN, NULL);
- } else if (authctxt->pam == NULL) {
- if (authctxt->pam_retval == PAM_SUCCESS) {
- audit_sshd_login_failure(&ah, PAM_PERM_DENIED,
- authctxt->user);
- } else {
- audit_sshd_login_failure(&ah, authctxt->pam_retval,
- authctxt->user);
- }
- } else {
- audit_sshd_login_failure(&ah, AUTHPAM_ERROR(authctxt,
- PAM_PERM_DENIED), authctxt->user);
- }
-}
-#endif /* HAVE_BSM */
-
-/*
- * Check whether root logins are disallowed.
- */
-int
-auth_root_allowed(char *method)
-{
- switch (options.permit_root_login) {
- case PERMIT_YES:
- return 1;
- break;
- case PERMIT_NO_PASSWD:
- if (strcmp(method, "password") != 0 &&
- strcmp(method, "keyboard-interactive") != 0)
- return 1;
- break;
- case PERMIT_FORCED_ONLY:
- if (forced_command) {
- log("Root login accepted for forced command.");
- return 1;
- }
- break;
- }
- log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
- return 0;
-}
-
-
-/*
- * Given a template and a passwd structure, build a filename
- * by substituting % tokenised options. Currently, %% becomes '%',
- * %h becomes the home directory and %u the username.
- *
- * This returns a buffer allocated by xmalloc.
- */
-char *
-expand_filename(const char *filename, struct passwd *pw)
-{
- Buffer buffer;
- char *file;
- const char *cp;
-
- if (pw == 0)
- return NULL; /* shouldn't happen */
- /*
- * Build the filename string in the buffer by making the appropriate
- * substitutions to the given file name.
- */
- buffer_init(&buffer);
- for (cp = filename; *cp; cp++) {
- if (cp[0] == '%' && cp[1] == '%') {
- buffer_append(&buffer, "%", 1);
- cp++;
- continue;
- }
- if (cp[0] == '%' && cp[1] == 'h') {
- buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
- cp++;
- continue;
- }
- if (cp[0] == '%' && cp[1] == 'u') {
- buffer_append(&buffer, pw->pw_name,
- strlen(pw->pw_name));
- cp++;
- continue;
- }
- buffer_append(&buffer, cp, 1);
- }
- buffer_append(&buffer, "\0", 1);
-
- /*
- * Ensure that filename starts anchored. If not, be backward
- * compatible and prepend the '%h/'
- */
- file = xmalloc(MAXPATHLEN);
- cp = buffer_ptr(&buffer);
- if (*cp != '/')
- snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
- else
- strlcpy(file, cp, MAXPATHLEN);
-
- buffer_free(&buffer);
- return file;
-}
-
-char *
-authorized_keys_file(struct passwd *pw)
-{
- return expand_filename(options.authorized_keys_file, pw);
-}
-
-char *
-authorized_keys_file2(struct passwd *pw)
-{
- return expand_filename(options.authorized_keys_file2, pw);
-}
-
-/* return ok if key exists in sysfile or userfile */
-HostStatus
-check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
- const char *sysfile, const char *userfile)
-{
- Key *found;
- char *user_hostfile;
- struct stat st;
- HostStatus host_status;
-
- /* Check if we know the host and its host key. */
- found = key_new(key->type);
- host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
-
- if (host_status != HOST_OK && userfile != NULL) {
- user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
- if (options.strict_modes &&
- (stat(user_hostfile, &st) == 0) &&
- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0)) {
- log("Authentication refused for %.100s: "
- "bad owner or modes for %.200s",
- pw->pw_name, user_hostfile);
- } else {
- temporarily_use_uid(pw);
- host_status = check_host_in_hostfile(user_hostfile,
- host, key, found, NULL);
- restore_uid();
- }
- xfree(user_hostfile);
- }
- key_free(found);
-
- debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
- "ok" : "not found", host);
- return host_status;
-}
-
-
-/*
- * Check a given file for security. This is defined as all components
- * of the path to the file must be owned by either the owner of
- * of the file or root and no directories must be group or world writable.
- *
- * XXX Should any specific check be done for sym links ?
- *
- * Takes an open file descriptor, the file name, a uid and and
- * error buffer plus max size as arguments.
- *
- * Returns 0 on success and -1 on failure
- */
-int
-secure_filename(FILE *f, const char *file, struct passwd *pw,
- char *err, size_t errlen)
-{
- uid_t uid;
- char buf[MAXPATHLEN], homedir[MAXPATHLEN];
- char *cp;
- int comparehome = 0;
- struct stat st;
-
- if (pw == NULL)
- return 0;
-
- uid = pw->pw_uid;
-
- if (realpath(file, buf) == NULL) {
- snprintf(err, errlen, "realpath %s failed: %s", file,
- strerror(errno));
- return -1;
- }
-
- /*
- * A user is not required to have all the files that are subject to
- * the strict mode checking in his/her home directory. If the
- * directory is not present at the moment, which might be the case if
- * the directory is not mounted until the user is authenticated, do
- * not perform the home directory check below.
- */
- if (realpath(pw->pw_dir, homedir) != NULL)
- comparehome = 1;
-
- /* check the open file to avoid races */
- if (fstat(fileno(f), &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != uid) ||
- (st.st_mode & 022) != 0) {
- snprintf(err, errlen, "bad ownership or modes for file %s",
- buf);
- return -1;
- }
-
- /* for each component of the canonical path, walking upwards */
- for (;;) {
- if ((cp = dirname(buf)) == NULL) {
- snprintf(err, errlen, "dirname() failed");
- return -1;
- }
- strlcpy(buf, cp, sizeof(buf));
-
- debug3("secure_filename: checking '%s'", buf);
- if (stat(buf, &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != uid) ||
- (st.st_mode & 022) != 0) {
- snprintf(err, errlen,
- "bad ownership or modes for directory %s", buf);
- return -1;
- }
-
- /* If we passed the homedir then we can stop. */
- if (comparehome && strcmp(homedir, buf) == 0) {
- debug3("secure_filename: terminating check at '%s'",
- buf);
- break;
- }
- /*
- * dirname should always complete with a "/" path,
- * but we can be paranoid and check for "." too
- */
- if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
- break;
- }
- return 0;
-}
-
-struct passwd *
-getpwnamallow(const char *user)
-{
-#ifdef HAVE_LOGIN_CAP
- extern login_cap_t *lc;
-#ifdef BSD_AUTH
- auth_session_t *as;
-#endif
-#endif
- struct passwd *pw;
-
- if (user == NULL || *user == '\0')
- return (NULL); /* implicit user, will be set later */
-
- parse_server_match_config(&options, user,
- get_canonical_hostname(options.verify_reverse_mapping), get_remote_ipaddr());
-
- pw = getpwnam(user);
- if (pw == NULL) {
- log("Illegal user %.100s from %.100s",
- user, get_remote_ipaddr());
- return (NULL);
- }
- if (!allowed_user(pw))
- return (NULL);
-#ifdef HAVE_LOGIN_CAP
- if ((lc = login_getclass(pw->pw_class)) == NULL) {
- debug("unable to get login class: %s", user);
- return (NULL);
- }
-#ifdef BSD_AUTH
- if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
- auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
- debug("Approval failure for %s", user);
- pw = NULL;
- }
- if (as != NULL)
- auth_close(as);
-#endif
-#endif
- if (pw != NULL)
- return (pwcopy(pw));
- return (NULL);
-}
-
-
-/*
- * The fatal_cleanup method to kill the hook. Since hook has been put into
- * new process group all descendants will be killed as well.
- */
-static void
-kill_hook(void *arg)
-{
- pid_t pid;
-
- pid = *(pid_t*)arg;
- debug("killing hook and all it's children, process group: %ld", pid);
- xfree(arg);
- (void)killpg(pid, SIGTERM);
-}
-
-/*
- * Runs the PreUserauthHook.
- * Returns -1 on execution error or the exit code of the hook if execution is
- * successful.
- */
-int
-run_auth_hook(const char *path, const char *user, const char *method)
-{
- struct stat st;
- int i, status, ret = 1;
- u_int envsize, argsize;
- char buf[256];
- char **env, **args;
- pid_t pid, *ppid;
-
- if (path == NULL || user == NULL || method == NULL) {
- return (-1);
- }
-
- /* Initialize the environment/arguments for the hook. */
- envsize = 4; /* 3 env vars + EndOfList marker */
- argsize = 4; /* 2 args + exe name + EndOfList marker */
- env = xmalloc(envsize * sizeof (char *));
- args = xmalloc(argsize * sizeof (char *));
- env[0] = NULL;
-
- /* we use the SSH env handling scheme */
- child_set_env_silent(&env, &envsize, "PATH", "/usr/bin:/bin");
- child_set_env_silent(&env, &envsize, "IFS", " \t\n");
-
- (void) snprintf(buf, sizeof (buf), "%.50s %d %.50s %d",
- get_remote_ipaddr(), get_remote_port(),
- get_local_ipaddr(packet_get_connection_in()), get_local_port());
- child_set_env_silent(&env, &envsize, "SSH_CONNECTION", buf);
-
- args[0] = xstrdup(path);
- args[1] = xstrdup(method);
- args[2] = xstrdup(user);
- args[3] = NULL;
-
- /*
- * sanity checks
- * note: the checks do not make sure that the file checked is actually
- * the same which is executed. However, in this case it shouldn't be a
- * major issue since the hook is rather static and the worst case would
- * be an uncorrect message in the log or a hook is run even though the
- * permissions are not right.
- */
-
- /* check if script does exist */
- if (stat(path, &st) < 0) {
- log("Error executing PreUserauthHook \"%s\": %s", path,
- strerror(errno));
- goto cleanup;
- }
-
- /* Check correct permissions for script (uid of SSHD, mode 500) */
- if (st.st_uid != getuid() || ((st.st_mode & 0777) != 0500)) {
- log("PreUserauthHook has invalid permissions (should be 500, is"
- " %o) or ownership (should be %d, is %d)",
- (uint) st.st_mode & 0777, getuid(), st.st_uid);
- goto cleanup;
- }
-
- if ((pid = fork()) == 0) {
- /*
- * We put the hook and all its (possible) descendants into
- * a new process group so that in case of a hanging hook
- * we can wipe out the whole "family".
- */
- if (setpgid(0, 0) != 0) {
- log("setpgid: %s", strerror(errno));
- _exit(255);
- }
- (void) execve(path, args, env);
- /* child is gone so we shouldn't get here */
- log("Error executing PreUserauthHook \"%s\": %s", path,
- strerror(errno));
- _exit(255);
- } else if (pid == -1) {
- log("Error executing PreUserauthHook \"%s\": %s", path,
- strerror(errno));
- goto cleanup;
- }
-
- /* make preparations to kill hook if it is hanging */
- ppid = xmalloc(sizeof (pid_t));
- *ppid = pid;
- fatal_add_cleanup((void (*)(void *))kill_hook, (void *) ppid);
-
- if (waitpid(pid, &status, 0) == -1) {
- log("Error executing PreUserauthHook \"%s\": %s", path,
- strerror(errno));
- goto cleanup;
- }
-
- ret = WEXITSTATUS(status);
-
- if (ret == 255) {
- ret = -1; /* execve() failed, error msg already logged */
- } else if (ret != 0) {
- log("PreUserauthHook \"%s\" failed with exit code %d",
- path, ret);
- } else {
- debug("PreUserauthHook \"%s\" finished successfully", path);
- }
-
-cleanup:
- for (i = 0; args[i] != NULL; i++) {
- xfree(args[i]);
- }
- for (i = 0; env[i] != NULL; i++) {
- xfree(env[i]);
- }
- xfree(args);
- xfree(env);
-
- fatal_remove_cleanup((void (*)(void *))kill_hook, (void *) ppid);
-
- return (ret);
-}
-
-void
-auth_debug_add(const char *fmt,...)
-{
- char buf[1024];
- va_list args;
-
- if (!auth_debug_init)
- return;
-
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
- va_end(args);
- buffer_put_cstring(&auth_debug, buf);
-}
-
-void
-auth_debug_send(void)
-{
- char *msg;
-
- if (!auth_debug_init)
- return;
- while (buffer_len(&auth_debug)) {
- msg = buffer_get_string(&auth_debug, NULL);
- packet_send_debug("%s", msg);
- xfree(msg);
- }
-}
-
-void
-auth_debug_reset(void)
-{
- if (auth_debug_init)
- buffer_clear(&auth_debug);
- else {
- buffer_init(&auth_debug);
- auth_debug_init = 1;
- }
-}
diff --git a/usr/src/cmd/ssh/sshd/auth1.c b/usr/src/cmd/ssh/sshd/auth1.c
deleted file mode 100644
index e77a021393..0000000000
--- a/usr/src/cmd/ssh/sshd/auth1.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth1.c,v 1.44 2002/09/26 11:38:43 markus Exp $");
-
-#include "xmalloc.h"
-#include "rsa.h"
-#include "ssh1.h"
-#include "packet.h"
-#include "buffer.h"
-#include "mpaux.h"
-#include "log.h"
-#include "servconf.h"
-#include "compat.h"
-#include "auth.h"
-#include "channels.h"
-#include "session.h"
-#include "uidswap.h"
-
-#ifdef HAVE_BSM
-#include "bsmaudit.h"
-extern adt_session_data_t *ah;
-#endif /* HAVE_BSM */
-
-/* import */
-extern ServerOptions options;
-
-/*
- * convert ssh auth msg type into description
- */
-static char *
-get_authname(int type)
-{
- static char buf[1024];
- switch (type) {
- case SSH_CMSG_AUTH_PASSWORD:
- return "password";
- case SSH_CMSG_AUTH_RSA:
- return "rsa";
- case SSH_CMSG_AUTH_RHOSTS_RSA:
- return "rhosts-rsa";
- case SSH_CMSG_AUTH_RHOSTS:
- return "rhosts";
- case SSH_CMSG_AUTH_TIS:
- case SSH_CMSG_AUTH_TIS_RESPONSE:
- return "challenge-response";
-#if defined(KRB4) || defined(KRB5)
- case SSH_CMSG_AUTH_KERBEROS:
- return "kerberos";
-#endif
- }
- snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
- return buf;
-}
-
-/*
- * read packets, try to authenticate the user and
- * return only if authentication is successful
- */
-static void
-do_authloop(Authctxt *authctxt)
-{
- int authenticated = 0;
- u_int bits;
- Key *client_host_key;
- BIGNUM *n;
- char *client_user, *password;
- char info[1024];
- u_int dlen;
- u_int ulen;
- int type = 0;
- struct passwd *pw = authctxt->pw;
-
- debug("Attempting authentication for %s%.100s.",
- authctxt->valid ? "" : "illegal user ", authctxt->user);
-
- /* If the user has no password, accept authentication immediately. */
- if (options.password_authentication &&
-#if defined(KRB4) || defined(KRB5)
- (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
-#endif
- auth_password(authctxt, "")) {
- auth_log(authctxt, 1, "without authentication", "");
- return;
- }
-
- /* Indicate that authentication is needed. */
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
-
- client_user = NULL;
-
- for ( ;; ) {
- /* default to fail */
- authenticated = 0;
-
- info[0] = '\0';
-
- /* Get a packet from the client. */
- authctxt->v1_auth_type = type = packet_read();
- authctxt->v1_auth_name = get_authname(type);
-
- authctxt->attempt++;
-
- /* Process the packet. */
- switch (type) {
-
-#if defined(KRB4) || defined(KRB5)
- case SSH_CMSG_AUTH_KERBEROS:
- if (!options.kerberos_authentication) {
- verbose("Kerberos authentication disabled.");
- } else {
- char *kdata = packet_get_string(&dlen);
- packet_check_eom();
-
- if (kdata[0] == 4) { /* KRB_PROT_VERSION */
-#ifdef KRB4
- KTEXT_ST tkt, reply;
- tkt.length = dlen;
- if (tkt.length < MAX_KTXT_LEN)
- memcpy(tkt.dat, kdata, tkt.length);
-
- if (auth_krb4(authctxt, &tkt,
- &client_user, &reply)) {
- authenticated = 1;
- snprintf(info, sizeof(info),
- " tktuser %.100s",
- client_user);
-
- packet_start(
- SSH_SMSG_AUTH_KERBEROS_RESPONSE);
- packet_put_string((char *)
- reply.dat, reply.length);
- packet_send();
- packet_write_wait();
- }
-#endif /* KRB4 */
- } else {
-#ifdef KRB5
- krb5_data tkt, reply;
- tkt.length = dlen;
- tkt.data = kdata;
-
- if (auth_krb5(authctxt, &tkt,
- &client_user, &reply)) {
- authenticated = 1;
- snprintf(info, sizeof(info),
- " tktuser %.100s",
- client_user);
-
- /* Send response to client */
- packet_start(
- SSH_SMSG_AUTH_KERBEROS_RESPONSE);
- packet_put_string((char *)
- reply.data, reply.length);
- packet_send();
- packet_write_wait();
-
- if (reply.length)
- xfree(reply.data);
- }
-#endif /* KRB5 */
- }
- xfree(kdata);
- }
- break;
-#endif /* KRB4 || KRB5 */
-
-#if defined(AFS) || defined(KRB5)
- /* XXX - punt on backward compatibility here. */
- case SSH_CMSG_HAVE_KERBEROS_TGT:
- packet_send_debug("Kerberos TGT passing disabled before authentication.");
- break;
-#ifdef AFS
- case SSH_CMSG_HAVE_AFS_TOKEN:
- packet_send_debug("AFS token passing disabled before authentication.");
- break;
-#endif /* AFS */
-#endif /* AFS || KRB5 */
-
- case SSH_CMSG_AUTH_RHOSTS:
- if (!options.rhosts_authentication) {
- verbose("Rhosts authentication disabled.");
- break;
- }
- /*
- * Get client user name. Note that we just have to
- * trust the client; this is one reason why rhosts
- * authentication is insecure. (Another is
- * IP-spoofing on a local network.)
- */
- client_user = packet_get_string(&ulen);
- packet_check_eom();
-
- /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
- authenticated = auth_rhosts(pw, client_user);
-
- snprintf(info, sizeof info, " ruser %.100s", client_user);
- break;
-
- case SSH_CMSG_AUTH_RHOSTS_RSA:
- if (!options.rhosts_rsa_authentication) {
- verbose("Rhosts with RSA authentication disabled.");
- break;
- }
- /*
- * Get client user name. Note that we just have to
- * trust the client; root on the client machine can
- * claim to be any user.
- */
- client_user = packet_get_string(&ulen);
-
- /* Get the client host key. */
- client_host_key = key_new(KEY_RSA1);
- bits = packet_get_int();
- packet_get_bignum(client_host_key->rsa->e);
- packet_get_bignum(client_host_key->rsa->n);
-
- if (bits != BN_num_bits(client_host_key->rsa->n))
- verbose("Warning: keysize mismatch for client_host_key: "
- "actual %d, announced %d",
- BN_num_bits(client_host_key->rsa->n), bits);
- packet_check_eom();
-
- authenticated = auth_rhosts_rsa(pw, client_user,
- client_host_key);
- key_free(client_host_key);
-
- snprintf(info, sizeof info, " ruser %.100s", client_user);
- break;
-
- case SSH_CMSG_AUTH_RSA:
- if (!options.rsa_authentication) {
- verbose("RSA authentication disabled.");
- break;
- }
- /* RSA authentication requested. */
- if ((n = BN_new()) == NULL)
- fatal("do_authloop: BN_new failed");
- packet_get_bignum(n);
- packet_check_eom();
- authenticated = auth_rsa(pw, n);
- BN_clear_free(n);
- break;
-
- case SSH_CMSG_AUTH_PASSWORD:
- authctxt->init_attempt++;
-
- if (!options.password_authentication) {
- verbose("Password authentication disabled.");
- break;
- }
- /*
- * Read user password. It is in plain text, but was
- * transmitted over the encrypted channel so it is
- * not visible to an outside observer.
- */
- password = packet_get_string(&dlen);
- packet_check_eom();
-
- /* Try authentication with the password. */
- if (authctxt->init_failures <
- options.max_init_auth_tries)
- authenticated =
- auth_password(authctxt, password);
-
- memset(password, 0, strlen(password));
- xfree(password);
- break;
-
- case SSH_CMSG_AUTH_TIS:
- debug("rcvd SSH_CMSG_AUTH_TIS");
- if (options.challenge_response_authentication == 1) {
- char *challenge = get_challenge(authctxt);
- if (challenge != NULL) {
- debug("sending challenge '%s'", challenge);
- packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
- packet_put_cstring(challenge);
- xfree(challenge);
- packet_send();
- packet_write_wait();
- continue;
- }
- }
- break;
- case SSH_CMSG_AUTH_TIS_RESPONSE:
- debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
- if (options.challenge_response_authentication == 1) {
- char *response = packet_get_string(&dlen);
- debug("got response '%s'", response);
- packet_check_eom();
- authenticated = verify_response(authctxt, response);
- memset(response, 'r', dlen);
- xfree(response);
- }
- break;
-
- default:
- /*
- * Any unknown messages will be ignored (and failure
- * returned) during authentication.
- */
- log("Unknown message during authentication: type %d", type);
- break;
- }
-#ifdef BSD_AUTH
- if (authctxt->as) {
- auth_close(authctxt->as);
- authctxt->as = NULL;
- }
-#endif
- if (!authctxt->valid && authenticated) {
- authenticated = 0;
- log("Ignoring authenticated invalid user %s",
- authctxt->user);
- }
-
-#ifdef _UNICOS
- if (type == SSH_CMSG_AUTH_PASSWORD && !authenticated)
- cray_login_failure(authctxt->user, IA_UDBERR);
- if (authenticated && cray_access_denied(authctxt->user)) {
- authenticated = 0;
- fatal("Access denied for user %s.",authctxt->user);
- }
-#endif /* _UNICOS */
-
-#ifdef HAVE_CYGWIN
- if (authenticated &&
- !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) {
- packet_disconnect("Authentication rejected for uid %d.",
- pw == NULL ? -1 : pw->pw_uid);
- authenticated = 0;
- }
-#else
- /* Special handling for root */
- if (authenticated && authctxt->pw->pw_uid == 0 &&
- !auth_root_allowed(get_authname(type)))
- authenticated = 0;
-#endif
-#ifdef USE_PAM
- if (authenticated && type != SSH_CMSG_AUTH_PASSWORD)
- authenticated = do_pam_non_initial_userauth(authctxt);
- else if (authenticated && !AUTHPAM_DONE(authctxt))
- authenticated = 0;
-
- if (!authenticated)
- authctxt->pam_retval = AUTHPAM_ERROR(authctxt,
- PAM_PERM_DENIED);
-#endif /* USE_PAM */
-
- /* Log before sending the reply */
- auth_log(authctxt, authenticated, get_authname(type), info);
-
- if (client_user != NULL) {
- xfree(client_user);
- client_user = NULL;
- }
-
- if (authenticated)
- return;
-
- if (type == SSH_CMSG_AUTH_PASSWORD)
- authctxt->init_failures++;
-
- if (authctxt->failures++ > options.max_auth_tries) {
-#ifdef HAVE_BSM
- fatal_remove_cleanup(audit_failed_login_cleanup,
- authctxt);
- audit_sshd_login_failure(&ah, PAM_MAXTRIES,
- authctxt->user);
-#endif /* HAVE_BSM */
- packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
- }
-
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- }
-}
-
-/*
- * Performs authentication of an incoming connection. Session key has already
- * been exchanged and encryption is enabled.
- */
-Authctxt *
-do_authentication(void)
-{
- Authctxt *authctxt;
- u_int ulen;
- char *user, *style = NULL;
-
- /* Get the name of the user that we wish to log in as. */
- packet_read_expect(SSH_CMSG_USER);
-
- /* Get the user name. */
- user = packet_get_string(&ulen);
- packet_check_eom();
-
- if ((style = strchr(user, ':')) != NULL)
- *style++ = '\0';
-
-#ifdef KRB5
- /* XXX - SSH.com Kerberos v5 braindeath. */
- if ((datafellows & SSH_BUG_K5USER) &&
- options.kerberos_authentication) {
- char *p;
- if ((p = strchr(user, '@')) != NULL)
- *p = '\0';
- }
-#endif
-
- authctxt = authctxt_new();
- authctxt->user = user;
- authctxt->style = style;
-
-#ifdef HAVE_BSM
- fatal_add_cleanup(audit_failed_login_cleanup, authctxt);
-#endif /* HAVE_BSM */
-
- /* Verify that the user is a valid user. */
- if ((authctxt->pw = getpwnamallow(user)) != NULL) {
- authctxt->valid = 1;
- } else {
- authctxt->valid = 0;
- debug("do_authentication: illegal user %s", user);
- }
-
- setproctitle("%s", authctxt->pw ? user : "unknown");
-
- /*
- * If we are not running as root, the user must have the same uid as
- * the server. (Unless you are running Windows)
- */
-#ifndef HAVE_CYGWIN
- if (getuid() != 0 && authctxt->pw &&
- authctxt->pw->pw_uid != getuid())
- packet_disconnect("Cannot change user when server not running as root.");
-#endif
-
- /*
- * Loop until the user has been authenticated or the connection is
- * closed, do_authloop() returns only if authentication is successful
- */
- do_authloop(authctxt);
-
- /* The user has been authenticated and accepted. */
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
-
- return (authctxt);
-}
diff --git a/usr/src/cmd/ssh/sshd/auth2-chall.c b/usr/src/cmd/ssh/sshd/auth2-chall.c
deleted file mode 100644
index 72dcc6dc5b..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-chall.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (c) 2001 Markus Friedl. All rights reserved.
- * Copyright (c) 2001 Per Allansson. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth2-chall.c,v 1.20 2002/06/30 21:59:45 deraadt Exp $");
-
-#include "ssh2.h"
-#include "auth.h"
-#include "buffer.h"
-#include "packet.h"
-#include "xmalloc.h"
-#include "dispatch.h"
-#include "auth.h"
-#include "log.h"
-
-#ifndef lint
-static void auth2_challenge_start(Authctxt *);
-static int send_userauth_info_request(Authctxt *);
-static void input_userauth_info_response(int, u_int32_t, void *);
-
-#ifdef BSD_AUTH
-extern KbdintDevice bsdauth_device;
-#else
-#ifdef SKEY
-extern KbdintDevice skey_device;
-#endif
-#endif
-
-KbdintDevice *devices[] = {
-#ifdef BSD_AUTH
- &bsdauth_device,
-#else
-#ifdef SKEY
- &skey_device,
-#endif
-#endif
- NULL
-};
-
-typedef struct KbdintAuthctxt KbdintAuthctxt;
-struct KbdintAuthctxt
-{
- char *devices;
- void *ctxt;
- KbdintDevice *device;
- u_int nreq;
-};
-
-static KbdintAuthctxt *
-kbdint_alloc(const char *devs)
-{
- KbdintAuthctxt *kbdintctxt;
- Buffer b;
- int i;
-
- kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
- if (strcmp(devs, "") == 0) {
- buffer_init(&b);
- for (i = 0; devices[i]; i++) {
- if (buffer_len(&b) > 0)
- buffer_append(&b, ",", 1);
- buffer_append(&b, devices[i]->name,
- strlen(devices[i]->name));
- }
- buffer_append(&b, "\0", 1);
- kbdintctxt->devices = xstrdup(buffer_ptr(&b));
- buffer_free(&b);
- } else {
- kbdintctxt->devices = xstrdup(devs);
- }
- debug("kbdint_alloc: devices '%s'", kbdintctxt->devices);
- kbdintctxt->ctxt = NULL;
- kbdintctxt->device = NULL;
- kbdintctxt->nreq = 0;
-
- return kbdintctxt;
-}
-static void
-kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
-{
- if (kbdintctxt->ctxt) {
- kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
- kbdintctxt->ctxt = NULL;
- }
- kbdintctxt->device = NULL;
-}
-static void
-kbdint_free(KbdintAuthctxt *kbdintctxt)
-{
- if (kbdintctxt->device)
- kbdint_reset_device(kbdintctxt);
- if (kbdintctxt->devices) {
- xfree(kbdintctxt->devices);
- kbdintctxt->devices = NULL;
- }
- xfree(kbdintctxt);
-}
-/* get next device */
-static int
-kbdint_next_device(KbdintAuthctxt *kbdintctxt)
-{
- size_t len;
- char *t;
- int i;
-
- if (kbdintctxt->device)
- kbdint_reset_device(kbdintctxt);
- do {
- len = kbdintctxt->devices ?
- strcspn(kbdintctxt->devices, ",") : 0;
-
- if (len == 0)
- break;
- for (i = 0; devices[i]; i++)
- if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
- kbdintctxt->device = devices[i];
- t = kbdintctxt->devices;
- kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
- xfree(t);
- debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
- kbdintctxt->devices : "<empty>");
- } while (kbdintctxt->devices && !kbdintctxt->device);
-
- return kbdintctxt->device ? 1 : 0;
-}
-
-/*
- * try challenge-response, set authctxt->method->postponed if we have to
- * wait for the response.
- */
-void
-auth2_challenge(Authctxt *authctxt, char *devs)
-{
- debug("auth2_challenge: user=%s devs=%s",
- authctxt->user ? authctxt->user : "<nouser>",
- devs ? devs : "<no devs>");
-
- if (authctxt->user == NULL || !devs)
- return;
- if (authctxt->method->method_data != NULL) {
- auth2_challenge_abandon(authctxt);
- authctxt->method->abandoned = 0;
- }
- authctxt->method->method_data = (void *) kbdint_alloc(devs);
- auth2_challenge_start(authctxt);
-}
-
-/* unregister kbd-int callbacks and context */
-static void
-auth2_challenge_stop(Authctxt *authctxt)
-{
- /* unregister callback */
- dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
- if (authctxt->method->method_data != NULL) {
- kbdint_free((KbdintAuthctxt *) authctxt->method->method_data);
- authctxt->method->method_data = NULL;
- }
-}
-
-void
-auth2_challenge_abandon(Authctxt *authctxt)
-{
- auth2_challenge_stop(authctxt);
- authctxt->method->abandoned = 1;
- authctxt->method->postponed = 0;
- authctxt->method->authenticated = 0;
- authctxt->method->abandons++;
- authctxt->method->attempts++;
-}
-
-/* side effect: sets authctxt->method->postponed if a reply was sent*/
-static void
-auth2_challenge_start(Authctxt *authctxt)
-{
- KbdintAuthctxt *kbdintctxt = (KbdintAuthctxt *)
- authctxt->method->method_data;
-
- debug2("auth2_challenge_start: devices %s",
- kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
-
- if (kbdint_next_device(kbdintctxt) == 0) {
- auth2_challenge_stop(authctxt);
- return;
- }
- debug("auth2_challenge_start: trying authentication method '%s'",
- kbdintctxt->device->name);
-
- if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
- auth2_challenge_stop(authctxt);
- return;
- }
- if (send_userauth_info_request(authctxt) == 0) {
- auth2_challenge_stop(authctxt);
- return;
- }
- dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
- &input_userauth_info_response);
-
- authctxt->method->postponed = 1;
-}
-
-static int
-send_userauth_info_request(Authctxt *authctxt)
-{
- KbdintAuthctxt *kbdintctxt;
- char *name, *instr, **prompts;
- int i;
- u_int *echo_on;
-
- kbdintctxt = (KbdintAuthctxt *) authctxt->method->method_data;
- if (kbdintctxt->device->query(kbdintctxt->ctxt,
- &name, &instr, &kbdintctxt->nreq, &prompts, &echo_on))
- return 0;
-
- packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
- packet_put_cstring(name);
- packet_put_utf8_cstring(instr);
- packet_put_cstring(""); /* language not used */
- packet_put_int(kbdintctxt->nreq);
- for (i = 0; i < kbdintctxt->nreq; i++) {
- packet_put_utf8_cstring(prompts[i]);
- packet_put_char(echo_on[i]);
- }
- packet_send();
- packet_write_wait();
-
- for (i = 0; i < kbdintctxt->nreq; i++)
- xfree(prompts[i]);
- xfree(prompts);
- xfree(echo_on);
- xfree(name);
- xfree(instr);
- return 1;
-}
-
-static void
-input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- KbdintAuthctxt *kbdintctxt;
- int i, res, len;
- u_int nresp;
- char **response = NULL, *method;
-
- if (authctxt == NULL)
- fatal("input_userauth_info_response: no authctxt");
- kbdintctxt = (KbdintAuthctxt *) authctxt->method->method_data;
- if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
- fatal("input_userauth_info_response: no kbdintctxt");
- if (kbdintctxt->device == NULL)
- fatal("input_userauth_info_response: no device");
-
- nresp = packet_get_int();
- if (nresp != kbdintctxt->nreq)
- fatal("input_userauth_info_response: wrong number of replies");
- if (nresp > 100)
- fatal("input_userauth_info_response: too many replies");
- if (nresp > 0) {
- response = xmalloc(nresp * sizeof(char *));
- for (i = 0; i < nresp; i++)
- response[i] = packet_get_string(NULL);
- }
- packet_check_eom();
-
- if (authctxt->valid) {
- res = kbdintctxt->device->respond(kbdintctxt->ctxt,
- nresp, response);
- } else {
- res = -1;
- }
-
- for (i = 0; i < nresp; i++) {
- memset(response[i], 'r', strlen(response[i]));
- xfree(response[i]);
- }
- if (response)
- xfree(response);
-
- authctxt->method->postponed = 0; /* reset */
- switch (res) {
- case 0:
- /* Success! */
- authctxt->method->authenticated = 1;
- break;
- case 1:
- /* Authentication needs further interaction */
- if (send_userauth_info_request(authctxt) == 1) {
- authctxt->method->postponed = 1;
- }
- break;
- default:
- /* Failure! */
- break;
- }
-
-
- len = strlen("keyboard-interactive") + 2 +
- strlen(kbdintctxt->device->name);
- method = xmalloc(len);
- snprintf(method, len, "keyboard-interactive/%s",
- kbdintctxt->device->name);
-
- if (authctxt->method->authenticated || authctxt->method->abandoned) {
- auth2_challenge_stop(authctxt);
- } else {
- /* start next device */
- /* may set authctxt->method->postponed */
- auth2_challenge_start(authctxt);
- }
- userauth_finish(authctxt, method);
- xfree(method);
-}
-
-void
-privsep_challenge_enable(void)
-{
-#ifdef BSD_AUTH
- extern KbdintDevice mm_bsdauth_device;
-#endif
-#ifdef SKEY
- extern KbdintDevice mm_skey_device;
-#endif
- /* As long as SSHv1 has devices[0] hard coded this is fine */
-#ifdef BSD_AUTH
- devices[0] = &mm_bsdauth_device;
-#else
-#ifdef SKEY
- devices[0] = &mm_skey_device;
-#endif
-#endif
-}
-#endif /* lint */
diff --git a/usr/src/cmd/ssh/sshd/auth2-gss.c b/usr/src/cmd/ssh/sshd/auth2-gss.c
deleted file mode 100644
index 8525707c1e..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-gss.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Copyright (c) 2001-2003 Simon Wilkinson. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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.
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-
-#ifdef GSSAPI
-#include "auth.h"
-#include "ssh2.h"
-#include "xmalloc.h"
-#include "log.h"
-#include "dispatch.h"
-#include "buffer.h"
-#include "servconf.h"
-#include "compat.h"
-#include "bufaux.h"
-#include "packet.h"
-
-#include <gssapi/gssapi.h>
-#include "ssh-gss.h"
-
-extern ServerOptions options;
-extern uchar_t *session_id2;
-extern int session_id2_len;
-extern Gssctxt *xxx_gssctxt;
-
-static void userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt);
-
-static void
-userauth_gssapi_keyex(Authctxt *authctxt)
-{
- gss_buffer_desc g_mic_data, mic_tok;
- Buffer mic_data;
- OM_uint32 maj_status, min_status;
-
- if (authctxt == NULL || authctxt->method == NULL)
- fatal("No authentication context during gssapi-keyex userauth");
-
- if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) {
- /* fatal()? or return? */
- debug("No GSS-API context during gssapi-keyex userauth");
- return;
- }
-
- /* Make data buffer to verify MIC with */
- buffer_init(&mic_data);
- buffer_put_string(&mic_data, session_id2, session_id2_len);
- buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
- buffer_put_cstring(&mic_data, authctxt->user);
- buffer_put_cstring(&mic_data, authctxt->service);
- buffer_put_cstring(&mic_data, authctxt->method->name);
-
- g_mic_data.value = buffer_ptr(&mic_data);
- g_mic_data.length = buffer_len(&mic_data);
-
- mic_tok.value = packet_get_string(&mic_tok.length);
-
- maj_status = gss_verify_mic(&min_status, xxx_gssctxt->context,
- &g_mic_data, &mic_tok, NULL);
-
- packet_check_eom();
- buffer_clear(&mic_data);
-
- if (maj_status != GSS_S_COMPLETE)
- debug2("MIC verification failed, GSSAPI userauth failed");
- else
- userauth_gssapi_finish(authctxt, xxx_gssctxt);
-
- /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
- if (xxx_gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
- ssh_gssapi_delete_ctx(&xxx_gssctxt);
-}
-
-static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
-static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
-static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
-static void input_gssapi_errtok(int, u_int32_t, void *);
-static void input_gssapi_exchange_complete(int type, u_int32_t plen,
- void *ctxt);
-
-static void
-userauth_gssapi_abandon(Authctxt *authctxt, Authmethod *method)
-{
- ssh_gssapi_delete_ctx((Gssctxt **)&method->method_data);
- xxx_gssctxt = NULL;
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
-}
-
-static void
-userauth_gssapi(Authctxt *authctxt)
-{
- gss_OID_set supported_mechs;
- int mechs, present = 0;
- OM_uint32 min_status;
- uint_t len;
- char *doid = NULL;
- gss_OID oid = GSS_C_NULL_OID;
-
- if (datafellows & SSH_OLD_GSSAPI) {
- debug("Early drafts of GSSAPI userauth not supported");
- return;
- }
-
- mechs = packet_get_int();
- if (mechs == 0) {
- packet_check_eom();
- debug("Mechanism negotiation is not supported");
- return;
- }
-
- ssh_gssapi_server_mechs(&supported_mechs);
-
- do {
- mechs--;
-
- if (oid != GSS_C_NULL_OID)
- ssh_gssapi_release_oid(&oid);
-
- doid = packet_get_string(&len);
-
- /* ick */
- if (doid[0] != 0x06 || (len > 2 && doid[1] != len - 2)) {
- log("Mechanism OID received using the old "
- "encoding form");
- oid = ssh_gssapi_make_oid(len, doid);
- } else {
- oid = ssh_gssapi_make_oid(len - 2, doid + 2);
- }
-
- (void) gss_test_oid_set_member(&min_status, oid,
- supported_mechs, &present);
-
- debug("Client offered gssapi userauth with %s (%s)",
- ssh_gssapi_oid_to_str(oid),
- present ? "supported" : "unsupported");
- } while (!present && (mechs > 0));
-
- if (!present) {
- /* userauth_finish() will send SSH2_MSG_USERAUTH_FAILURE */
- debug2("No mechanism offered by the client is available");
- ssh_gssapi_release_oid(&oid);
- return;
- }
-
- ssh_gssapi_build_ctx((Gssctxt **)&authctxt->method->method_data,
- 0, oid);
- ssh_gssapi_release_oid(&oid);
- /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
-
- packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
-
- /* Just return whatever we found -- the matched mech does us no good */
- packet_put_string(doid, len);
- xfree(doid);
-
- packet_send();
- packet_write_wait();
-
- /* Setup rest of gssapi userauth conversation */
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
- authctxt->method->postponed = 1;
-}
-
-static void
-input_gssapi_token(int type, u_int32_t plen, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- Gssctxt *gssctxt;
- gss_buffer_desc send_tok, recv_tok;
- OM_uint32 maj_status, min_status;
- uint_t len;
-
- if (authctxt == NULL || authctxt->method == NULL ||
- (authctxt->method->method_data == NULL)) {
- fatal("No authentication or GSSAPI context during "
- "gssapi-with-mic userauth");
- }
-
- gssctxt = authctxt->method->method_data;
- recv_tok.value = packet_get_string(&len);
- recv_tok.length = len; /* u_int vs. size_t */
-
- maj_status = ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
- packet_check_eom();
-
- if (GSS_ERROR(maj_status)) {
- ssh_gssapi_userauth_error(gssctxt);
- if (send_tok.length != 0) {
- packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
- packet_put_string(send_tok.value, send_tok.length);
- packet_send();
- packet_write_wait();
- }
- authctxt->method->postponed = 0;
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- userauth_finish(authctxt, authctxt->method->name);
- } else {
- if (send_tok.length != 0) {
- packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
- packet_put_string(send_tok.value, send_tok.length);
- packet_send();
- packet_write_wait();
- }
- if (maj_status == GSS_S_COMPLETE) {
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
- &input_gssapi_mic);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
- &input_gssapi_exchange_complete);
- }
- }
-
- gss_release_buffer(&min_status, &send_tok);
-}
-
-static void
-input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- Gssctxt *gssctxt;
- gss_buffer_desc send_tok, recv_tok;
-
- if (authctxt == NULL || authctxt->method == NULL ||
- (authctxt->method->method_data == NULL)) {
- fatal("No authentication or GSSAPI context during "
- "gssapi-with-mic userauth");
- }
-
- gssctxt = authctxt->method->method_data;
- recv_tok.value = packet_get_string(&recv_tok.length);
- packet_check_eom();
-
- /* Push the error token into GSSAPI to see what it says */
- (void) ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
-
- debug("Client sent GSS-API error token during GSS userauth-- %s",
- ssh_gssapi_last_error(gssctxt, NULL, NULL));
-
- /* We can't return anything to the client, even if we wanted to */
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
-
-
- /*
- * The client will have already moved on to the next auth and
- * will send a new userauth request. The spec says that the
- * server MUST NOT send a SSH_MSG_USERAUTH_FAILURE packet in
- * response to this.
- *
- * We leave authctxt->method->postponed == 1 here so that a call
- * to input_userauth_request() will detect this failure (as
- * userauth abandonment) and act accordingly.
- */
-}
-
-static void
-input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- Gssctxt *gssctxt;
- gss_buffer_desc g_mic_data, mic_tok;
- Buffer mic_data;
- OM_uint32 maj_status, min_status;
-
- if (authctxt == NULL || authctxt->method == NULL ||
- (authctxt->method->method_data == NULL)) {
- debug3("No authentication or GSSAPI context during "
- "gssapi-with-mic userauth");
- return;
- }
-
- gssctxt = authctxt->method->method_data;
-
- /* Make data buffer to verify MIC with */
- buffer_init(&mic_data);
- buffer_put_string(&mic_data, session_id2, session_id2_len);
- buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
- buffer_put_cstring(&mic_data, authctxt->user);
- buffer_put_cstring(&mic_data, authctxt->service);
- buffer_put_cstring(&mic_data, authctxt->method->name);
-
- g_mic_data.value = buffer_ptr(&mic_data);
- g_mic_data.length = buffer_len(&mic_data);
-
- mic_tok.value = packet_get_string(&mic_tok.length);
-
- maj_status = gss_verify_mic(&min_status, gssctxt->context,
- &g_mic_data, &mic_tok, NULL);
-
- packet_check_eom();
- buffer_free(&mic_data);
-
- if (maj_status != GSS_S_COMPLETE)
- debug2("MIC verification failed, GSSAPI userauth failed");
- else
- userauth_gssapi_finish(authctxt, gssctxt);
-
- /* Delete context from keyex */
- if (xxx_gssctxt != gssctxt)
- ssh_gssapi_delete_ctx(&xxx_gssctxt);
-
- /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
- if (gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
- ssh_gssapi_delete_ctx(&gssctxt);
-
- xxx_gssctxt = gssctxt;
-
- authctxt->method->postponed = 0;
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
- userauth_finish(authctxt, authctxt->method->name);
-}
-
-/*
- * This is called when the client thinks we've completed authentication.
- * It should only be enabled in the dispatch handler by the function above,
- * which only enables it once the GSSAPI exchange is complete.
- */
-static void
-input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- Gssctxt *gssctxt;
-
- packet_check_eom();
-
- if (authctxt == NULL || authctxt->method == NULL ||
- (authctxt->method->method_data == NULL))
- fatal("No authentication or GSSAPI context");
-
- gssctxt = authctxt->method->method_data;
-
- /*
- * SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE -> gssapi userauth
- * failure, the client should use SSH2_MSG_USERAUTH_GSSAPI_MIC
- * instead.
- *
- * There's two reasons for this:
- *
- * 1) we don't have GSS mechs that don't support integrity
- * protection, and even if we did we'd not want to use them with
- * SSHv2, and,
- *
- * 2) we currently have no way to dynamically detect whether a
- * given mechanism does or does not support integrity
- * protection, so when a context's flags do not indicate
- * integrity protection we can't know if the client simply
- * didn't request it, so we assume it didn't and reject the
- * userauth.
- *
- * We could fail partially (i.e., force the use of other
- * userauth methods without counting this one as failed). But
- * this will do for now.
- */
-#if 0
- authctxt->method->authenticated = ssh_gssapi_userok(gssctxt,
- authctxt->user);
-#endif
-
- if (xxx_gssctxt != gssctxt)
- ssh_gssapi_delete_ctx(&gssctxt);
- ssh_gssapi_delete_ctx(&gssctxt);
- authctxt->method->postponed = 0;
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
- userauth_finish(authctxt, authctxt->method->name);
-}
-
-static void
-ssh_gssapi_userauth_error(Gssctxt *ctxt)
-{
- char *errstr;
- OM_uint32 maj, min;
-
- errstr = ssh_gssapi_last_error(ctxt, &maj, &min);
- if (errstr) {
- packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
- packet_put_int(maj);
- packet_put_int(min);
- packet_put_cstring(errstr);
- packet_put_cstring("");
- packet_send();
- packet_write_wait();
- xfree(errstr);
- }
-}
-
-/*
- * Code common to gssapi-keyex and gssapi-with-mic userauth.
- *
- * Does authorization, figures out how to store delegated creds.
- */
-static void
-userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt)
-{
- char *local_user = NULL;
- gss_buffer_desc dispname;
- OM_uint32 major;
-
- if (*authctxt->user != '\0' &&
- ssh_gssapi_userok(gssctxt, authctxt->user)) {
-
- /*
- * If the client princ did not map to the requested
- * username then we don't want to clobber existing creds
- * for the user with the delegated creds.
- */
- local_user = ssh_gssapi_localname(gssctxt);
- if (local_user == NULL ||
- strcmp(local_user, authctxt->user) == 0)
- gssctxt->default_creds = 1; /* store creds as default */
-
- authctxt->method->authenticated =
- do_pam_non_initial_userauth(authctxt);
-
- } else if (*authctxt->user == '\0') {
- /* Requested username == ""; derive username from princ name */
- if ((local_user = ssh_gssapi_localname(gssctxt)) == NULL)
- return;
-
- /* Changed username (from implicit, '') */
- userauth_user_svc_change(authctxt, local_user, NULL);
-
- gssctxt->default_creds = 1; /* store creds as default */
-
- authctxt->method->authenticated =
- do_pam_non_initial_userauth(authctxt);
- }
-
- if (local_user != NULL)
- xfree(local_user);
-
- if (*authctxt->user != '\0' && authctxt->method->authenticated != 0) {
- major = gss_display_name(&gssctxt->minor, gssctxt->src_name,
- &dispname, NULL);
- if (major == GSS_S_COMPLETE) {
- log("Authorized principal %.*s, authenticated with "
- "GSS mechanism %s, to: %s",
- dispname.length, (char *)dispname.value,
- ssh_gssapi_oid_to_name(gssctxt->actual_mech),
- authctxt->user);
- }
- (void) gss_release_buffer(&gssctxt->minor, &dispname);
- }
-}
-
-#if 0
-/* Deprecated userauths -- should not be enabled */
-Authmethod method_external = {
- "external-keyx",
- &options.gss_authentication,
- userauth_gssapi_keyex,
- NULL, /* no abandon function */
- NULL,
- NULL,
- /* State counters */
- 0, 0, 0, 0,
- /* State flags */
- 0, 0, 0, 0, 0, 0
-};
-
-Authmethod method_gssapi = {
- "gssapi",
- &options.gss_authentication,
- userauth_gssapi,
- userauth_gssapi_abandon,
- NULL,
- NULL,
- /* State counters */
- 0, 0, 0, 0,
- /* State flags */
- 0, 0, 0, 0, 0, 0
-};
-#endif
-
-Authmethod method_external = {
- "gssapi-keyex",
- &options.gss_authentication,
- userauth_gssapi_keyex,
- NULL, /* no abandon function */
- NULL,
- NULL,
- /* State counters */
- 0, 0, 0, 0,
- /* State flags */
- 0, 0, 0, 0, 0, 0
-};
-
-Authmethod method_gssapi = {
- "gssapi-with-mic",
- &options.gss_authentication,
- userauth_gssapi,
- userauth_gssapi_abandon,
- NULL,
- NULL,
- /* State counters */
- 0, 0, 0, 0,
- /* State flags */
- 0, 0, 0, 0, 0, 0
-};
-
-#endif /* GSSAPI */
diff --git a/usr/src/cmd/ssh/sshd/auth2-hostbased.c b/usr/src/cmd/ssh/sshd/auth2-hostbased.c
deleted file mode 100644
index c88e308100..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-hostbased.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth2-hostbased.c,v 1.2 2002/05/31 11:35:15 markus Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "ssh2.h"
-#include "xmalloc.h"
-#include "packet.h"
-#include "buffer.h"
-#include "log.h"
-#include "servconf.h"
-#include "compat.h"
-#include "bufaux.h"
-#include "auth.h"
-
-#ifdef USE_PAM
-#include "auth-pam.h"
-#endif /* USE_PAM */
-
-#include "key.h"
-#include "canohost.h"
-#include "pathnames.h"
-
-/* import */
-extern ServerOptions options;
-extern u_char *session_id2;
-extern int session_id2_len;
-
-static void
-userauth_hostbased(Authctxt *authctxt)
-{
- Buffer b;
- Key *key = NULL;
- char *pkalg, *cuser, *chost, *service;
- u_char *pkblob, *sig;
- u_int alen, blen, slen;
- int pktype;
- int authenticated = 0;
-
- if (!authctxt || !authctxt->method)
- fatal("%s: missing context", __func__);
-
- pkalg = packet_get_string(&alen);
- pkblob = packet_get_string(&blen);
- chost = packet_get_string(NULL);
- cuser = packet_get_string(NULL);
- sig = packet_get_string(&slen);
-
- debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
- cuser, chost, pkalg, slen);
-#ifdef DEBUG_PK
- debug("signature:");
- buffer_init(&b);
- buffer_append(&b, sig, slen);
- buffer_dump(&b);
- buffer_free(&b);
-#endif
- pktype = key_type_from_name(pkalg);
- if (pktype == KEY_UNSPEC) {
- /* this is perfectly legal */
- log("userauth_hostbased: unsupported "
- "public key algorithm: %s", pkalg);
- goto done;
- }
- key = key_from_blob(pkblob, blen);
- if (key == NULL) {
- error("userauth_hostbased: cannot decode key: %s", pkalg);
- goto done;
- }
- if (key->type != pktype) {
- error("userauth_hostbased: type mismatch for decoded key "
- "(received %d, expected %d)", key->type, pktype);
- goto done;
- }
- service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
- authctxt->service;
- buffer_init(&b);
- buffer_put_string(&b, session_id2, session_id2_len);
- /* reconstruct packet */
- buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
- buffer_put_cstring(&b, authctxt->user);
- buffer_put_cstring(&b, service);
- buffer_put_cstring(&b, "hostbased");
- buffer_put_string(&b, pkalg, alen);
- buffer_put_string(&b, pkblob, blen);
- buffer_put_cstring(&b, chost);
- buffer_put_cstring(&b, cuser);
-#ifdef DEBUG_PK
- buffer_dump(&b);
-#endif
- /* test for allowed key and correct signature */
- authenticated = 0;
- if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
- key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
- authenticated = 1;
-
- buffer_clear(&b);
-done:
- /*
- * XXX TODO: Add config options for specifying users for whom
- * this userauth is insufficient and what userauths
- * may continue.
- *
- * NOTE: do_pam_non_initial_userauth() does this for
- * users with expired passwords.
- */
-#ifdef USE_PAM
- if (authenticated) {
- authctxt->cuser = cuser;
- if (!do_pam_non_initial_userauth(authctxt))
- authenticated = 0;
- /* Make sure nobody else will use this pointer since we are
- * going to free that string. */
- authctxt->cuser = NULL;
- }
-#endif /* USE_PAM */
-
- if (authenticated)
- authctxt->method->authenticated = 1;
-
- debug2("userauth_hostbased: authenticated %d", authenticated);
- if (key != NULL)
- key_free(key);
- xfree(pkalg);
- xfree(pkblob);
- xfree(cuser);
- xfree(chost);
- xfree(sig);
- return;
-}
-
-/* return 1 if given hostkey is allowed */
-int
-hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
- Key *key)
-{
- const char *resolvedname, *ipaddr, *lookup;
- HostStatus host_status;
- int len;
-
- resolvedname = get_canonical_hostname(options.verify_reverse_mapping);
- ipaddr = get_remote_ipaddr();
-
- debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
- chost, resolvedname, ipaddr);
-
- if (pw == NULL)
- return 0;
-
- if (options.hostbased_uses_name_from_packet_only) {
- if (auth_rhosts2(pw, cuser, chost, chost) == 0)
- return 0;
- lookup = chost;
- } else {
- if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
- debug2("stripping trailing dot from chost %s", chost);
- chost[len - 1] = '\0';
- }
- if (strcasecmp(resolvedname, chost) != 0)
- log("userauth_hostbased mismatch: "
- "client sends %s, but we resolve %s to %s",
- chost, ipaddr, resolvedname);
- if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
- return 0;
- lookup = resolvedname;
- }
- debug2("userauth_hostbased: access allowed by auth_rhosts2");
-
- host_status = check_key_in_hostfiles(pw, key, lookup,
- _PATH_SSH_SYSTEM_HOSTFILE,
- options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
-
- /* backward compat if no key has been found. */
- if (host_status == HOST_NEW)
- host_status = check_key_in_hostfiles(pw, key, lookup,
- _PATH_SSH_SYSTEM_HOSTFILE2,
- options.ignore_user_known_hosts ? NULL :
- _PATH_SSH_USER_HOSTFILE2);
-
- return (host_status == HOST_OK);
-}
-
-Authmethod method_hostbased = {
- "hostbased",
- &options.hostbased_authentication,
- userauth_hostbased,
- NULL, /* no abandon function */
- NULL, NULL, /* method data and hist data */
- 0, /* is not initial userauth */
- 0, 0, 0, /* counters */
- 0, 0, 0, 0, 0, 0 /* state */
-};
diff --git a/usr/src/cmd/ssh/sshd/auth2-kbdint.c b/usr/src/cmd/ssh/sshd/auth2-kbdint.c
deleted file mode 100644
index 2ea8104182..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-kbdint.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth2-kbdint.c,v 1.2 2002/05/31 11:35:15 markus Exp $");
-
-#include "packet.h"
-#include "auth.h"
-#include "log.h"
-#include "servconf.h"
-#include "xmalloc.h"
-
-/* import */
-extern ServerOptions options;
-
-static void
-userauth_kbdint(Authctxt *authctxt)
-{
- char *lang, *devs;
-
- if (!authctxt || !authctxt->method)
- fatal("%s: missing contex", __func__);
-
- lang = packet_get_string(NULL);
- devs = packet_get_string(NULL);
- packet_check_eom();
-
- debug("keyboard-interactive devs %s", devs);
-
-#ifdef USE_PAM
- if (options.kbd_interactive_authentication)
- auth2_pam(authctxt);
-#else
- if (options.challenge_response_authentication)
- auth2_challenge(authctxt, devs);
-#endif /* USE_PAM */
- xfree(devs);
- xfree(lang);
-#ifdef HAVE_CYGWIN
- if (check_nt_auth(0, authctxt->pw) == 0) {
- authctxt->method->authenticated = 0;
- return;
- }
-#endif
-}
-
-static void
-userauth_kbdint_abandon(Authctxt *authctxt, Authmethod *method)
-{
-#ifdef USE_PAM
- kbdint_pam_abandon(authctxt, method);
-#else
- auth2_challenge_abandon(authctxt);
-#endif /* USE_PAM */
-}
-
-Authmethod method_kbdint = {
- "keyboard-interactive",
- &options.kbd_interactive_authentication,
- userauth_kbdint,
- userauth_kbdint_abandon,
- NULL, NULL, /* method data and historical data */
- 1, /* initial userauth */
- 0, 0, 0, /* counters */
- 0, 0, 0, 0, 0, 0 /* state */
-};
diff --git a/usr/src/cmd/ssh/sshd/auth2-none.c b/usr/src/cmd/ssh/sshd/auth2-none.c
deleted file mode 100644
index 5d49ee95e8..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-none.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth2-none.c,v 1.4 2002/06/27 10:35:47 deraadt Exp $");
-
-#include "auth.h"
-#include "xmalloc.h"
-#include "packet.h"
-#include "log.h"
-#include "servconf.h"
-#include "atomicio.h"
-#include "compat.h"
-#include "ssh2.h"
-
-/* import */
-extern ServerOptions options;
-
-/* "none" is allowed only one time */
-static int none_enabled = 1;
-
-char *
-auth2_read_banner(void)
-{
- struct stat st;
- char *banner, *ubanner, *errstr;
- off_t len, n;
- int fd;
- uint_t ilen;
-
- if ((fd = open(options.banner, O_RDONLY)) == -1)
- return (NULL);
- if (fstat(fd, &st) == -1) {
- close(fd);
- return (NULL);
- }
- len = st.st_size;
- banner = xmalloc(len + 1);
- n = atomicio(read, fd, banner, len);
- close(fd);
-
- if (n != len) {
- xfree(banner);
- return (NULL);
- }
- banner[n] = '\0';
-
- if (datafellows & SSH_BUG_STRING_ENCODING) {
- ubanner = banner;
- } else {
- ilen = (uint_t)n;
- ubanner = g11n_convert_to_utf8(banner, &ilen, 1, &errstr);
- if (ubanner == NULL) {
- if (errstr != NULL) {
- error("Can't convert banner contents "
- "to UTF-8: %s\n", errstr);
- }
- ubanner = banner;
- } else {
- xfree(banner);
- }
- }
-
- return (ubanner);
-}
-
-static void
-userauth_banner(void)
-{
- char *banner = NULL;
-
- if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
- return;
-
- if ((banner = auth2_read_banner()) == NULL)
- goto done;
-
- packet_start(SSH2_MSG_USERAUTH_BANNER);
- packet_put_cstring(banner);
- packet_put_cstring(""); /* language, unused */
- packet_send();
- debug("userauth_banner: sent");
-done:
- if (banner)
- xfree(banner);
-}
-
-static void
-userauth_none(Authctxt *authctxt)
-{
- none_enabled = 0;
-
- if (!authctxt || !authctxt->method)
- fatal("%s: missing context", __func__);
-
- packet_check_eom();
- userauth_banner();
-#ifdef HAVE_CYGWIN
- if (check_nt_auth(1, authctxt->pw) == 0)
- return (0);
-#endif
- authctxt->method->authenticated = auth_password(authctxt, "");
-}
-
-Authmethod method_none = {
- "none",
- &none_enabled,
- userauth_none,
- NULL, /* no abandon function */
- NULL, NULL, /* method data and hist data */
- 0, /* not really initial userauth */
- 0, 0, 0, /* counters */
- 0, 0, 0, 0, 0, 0 /* state */
-};
diff --git a/usr/src/cmd/ssh/sshd/auth2-pam.c b/usr/src/cmd/ssh/sshd/auth2-pam.c
deleted file mode 100644
index 1b0fa40f2b..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-pam.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-
-RCSID("$Id: auth2-pam.c,v 1.14 2002/06/28 16:48:12 mouring Exp $");
-
-#ifdef USE_PAM
-#include <security/pam_appl.h>
-
-#include "ssh.h"
-#include "ssh2.h"
-#include "auth.h"
-#include "auth-pam.h"
-#include "auth-options.h"
-#include "packet.h"
-#include "xmalloc.h"
-#include "dispatch.h"
-#include "canohost.h"
-#include "log.h"
-#include "servconf.h"
-#include "misc.h"
-
-#ifdef HAVE_BSM
-#include "bsmaudit.h"
-#endif /* HAVE_BSM */
-
-extern u_int utmp_len;
-extern ServerOptions options;
-
-extern Authmethod method_kbdint;
-extern Authmethod method_passwd;
-
-#define SSHD_PAM_KBDINT_SVC "sshd-kbdint"
-/* Maximum attempts for changing expired password */
-#define DEF_ATTEMPTS 3
-
-static int do_pam_conv_kbd_int(int num_msg,
- struct pam_message **msg, struct pam_response **resp,
- void *appdata_ptr);
-static void input_userauth_info_response_pam(int type,
- u_int32_t seqnr,
- void *ctxt);
-
-static struct pam_conv conv2 = {
- do_pam_conv_kbd_int,
- NULL,
-};
-
-static void do_pam_kbdint_cleanup(pam_handle_t *pamh);
-static void do_pam_kbdint(Authctxt *authctxt);
-
-void
-auth2_pam(Authctxt *authctxt)
-{
- if (authctxt->user == NULL)
- fatal("auth2_pam: internal error: no user");
- if (authctxt->method == NULL)
- fatal("auth2_pam: internal error: no method");
-
- conv2.appdata_ptr = authctxt;
- new_start_pam(authctxt, &conv2);
-
- authctxt->method->method_data = NULL; /* freed in the conv func */
- dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
- &input_userauth_info_response_pam);
-
- /*
- * Since password userauth and keyboard-interactive userauth
- * both use PAM, and since keyboard-interactive is so much
- * better than password userauth, we should not allow the user
- * to try password userauth after trying keyboard-interactive.
- */
- if (method_passwd.enabled)
- *method_passwd.enabled = 0;
-
- do_pam_kbdint(authctxt);
-
- dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
-}
-
-static void
-do_pam_kbdint(Authctxt *authctxt)
-{
- int retval, retval2;
- pam_handle_t *pamh = authctxt->pam->h;
- const char *where = "authenticating";
- char *text = NULL;
-
- debug2("Calling pam_authenticate()");
- retval = pam_authenticate(pamh,
- options.permit_empty_passwd ? 0 :
- PAM_DISALLOW_NULL_AUTHTOK);
-
- if (retval != PAM_SUCCESS)
- goto cleanup;
-
- debug2("kbd-int: pam_authenticate() succeeded");
- where = "authorizing";
- retval = pam_acct_mgmt(pamh, 0);
-
- if (retval == PAM_NEW_AUTHTOK_REQD) {
- if (authctxt->valid && authctxt->pw != NULL) {
- /* send password expiration warning */
- message_cat(&text,
- gettext("Warning: Your password has expired,"
- " please change it now."));
- packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
- packet_put_cstring(""); /* name */
- packet_put_utf8_cstring(text); /* instructions */
- packet_put_cstring(""); /* language, unused */
- packet_put_int(0);
- packet_send();
- packet_write_wait();
- debug("expiration message sent");
- if (text)
- xfree(text);
- /*
- * wait for the response so it does not mix
- * with the upcoming PAM conversation
- */
- packet_read_expect(SSH2_MSG_USERAUTH_INFO_RESPONSE);
- /*
- * Can't use temporarily_use_uid() and restore_uid()
- * here because we need (euid == 0 && ruid == pw_uid)
- * whereas temporarily_use_uid() arranges for
- * (suid = 0 && euid == pw_uid && ruid == pw_uid).
- */
- (void) setreuid(authctxt->pw->pw_uid, -1);
- debug2("kbd-int: changing expired password");
- where = "changing authentication tokens (password)";
- /*
- * Depending on error returned from pam_chauthtok, we
- * need to try to change password a few times before
- * we error out and return.
- */
- int tries = 0;
- while ((retval = pam_chauthtok(pamh,
- PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) {
- if (tries++ < DEF_ATTEMPTS) {
- if ((retval == PAM_AUTHTOK_ERR) ||
- (retval == PAM_TRY_AGAIN)) {
- continue;
- }
- }
- break;
- }
- audit_sshd_chauthtok(retval, authctxt->pw->pw_uid,
- authctxt->pw->pw_gid);
- (void) setreuid(0, -1);
- } else {
- retval = PAM_PERM_DENIED;
- }
- }
-
- if (retval != PAM_SUCCESS)
- goto cleanup;
-
- authctxt->pam->state |= PAM_S_DONE_ACCT_MGMT;
-
- retval = finish_userauth_do_pam(authctxt);
-
- if (retval != PAM_SUCCESS)
- goto cleanup;
-
- /*
- * PAM handle stays around so we can call pam_close_session()
- * on it later.
- */
- authctxt->method->authenticated = 1;
- debug2("kbd-int: success (pam->state == %x)", authctxt->pam->state);
- return;
-
-cleanup:
- /*
- * Check for abandonment and cleanup. When kbdint is abandoned
- * authctxt->pam->h is NULLed and by this point a new handle may
- * be allocated.
- */
- if (authctxt->pam->h != pamh) {
- log("Keyboard-interactive (PAM) userauth abandoned "
- "while %s", where);
- if ((retval2 = pam_end(pamh, retval)) != PAM_SUCCESS) {
- log("Cannot close PAM handle after "
- "kbd-int userauth abandonment[%d]: %.200s",
- retval2, PAM_STRERROR(pamh, retval2));
- }
- authctxt->method->abandoned = 1;
-
- /*
- * Avoid double counting; these are incremented in
- * kbdint_pam_abandon() so that they reflect the correct
- * count when userauth_finish() is called before
- * unwinding the dispatch_run() loop, but they are
- * incremented again in input_userauth_request() when
- * the loop is unwound, right here.
- */
- if (authctxt->method->abandons)
- authctxt->method->abandons--;
- if (authctxt->method->attempts)
- authctxt->method->attempts--;
- }
- else {
- /* Save error value for pam_end() */
- authctxt->pam->last_pam_retval = retval;
- log("Keyboard-interactive (PAM) userauth failed[%d] "
- "while %s: %.200s", retval, where,
- PAM_STRERROR(pamh, retval));
- /* pam handle can be reused elsewhere, so no pam_end() here */
- }
-
- return;
-}
-
-static int
-do_pam_conv_kbd_int(int num_msg, struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr)
-{
- int i, j;
- char *text;
- Convctxt *conv_ctxt;
- Authctxt *authctxt = (Authctxt *)appdata_ptr;
-
- if (!authctxt || !authctxt->method) {
- debug("Missing state during PAM conversation");
- return PAM_CONV_ERR;
- }
-
- conv_ctxt = xmalloc(sizeof(Convctxt));
- (void) memset(conv_ctxt, 0, sizeof(Convctxt));
- conv_ctxt->finished = 0;
- conv_ctxt->num_received = 0;
- conv_ctxt->num_expected = 0;
- conv_ctxt->prompts = xmalloc(sizeof(int) * num_msg);
- conv_ctxt->responses = xmalloc(sizeof(struct pam_response) * num_msg);
- (void) memset(conv_ctxt->responses, 0, sizeof(struct pam_response) * num_msg);
-
- text = NULL;
- for (i = 0, conv_ctxt->num_expected = 0; i < num_msg; i++) {
- int style = PAM_MSG_MEMBER(msg, i, msg_style);
- switch (style) {
- case PAM_PROMPT_ECHO_ON:
- debug2("PAM echo on prompt: %s",
- PAM_MSG_MEMBER(msg, i, msg));
- conv_ctxt->num_expected++;
- break;
- case PAM_PROMPT_ECHO_OFF:
- debug2("PAM echo off prompt: %s",
- PAM_MSG_MEMBER(msg, i, msg));
- conv_ctxt->num_expected++;
- break;
- case PAM_TEXT_INFO:
- debug2("PAM text info prompt: %s",
- PAM_MSG_MEMBER(msg, i, msg));
- message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
- break;
- case PAM_ERROR_MSG:
- debug2("PAM error prompt: %s",
- PAM_MSG_MEMBER(msg, i, msg));
- message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
- break;
- default:
- /* Capture all these messages to be sent at once */
- message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
- break;
- }
- }
-
- if (conv_ctxt->num_expected == 0 && text == NULL) {
- xfree(conv_ctxt->prompts);
- xfree(conv_ctxt->responses);
- xfree(conv_ctxt);
- return PAM_SUCCESS;
- }
-
- authctxt->method->method_data = (void *) conv_ctxt;
-
- packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
- packet_put_cstring(""); /* Name */
- packet_put_utf8_cstring(text ? text : ""); /* Instructions */
- packet_put_cstring(""); /* Language */
- packet_put_int(conv_ctxt->num_expected);
-
- if (text)
- xfree(text);
-
- for (i = 0, j = 0; i < num_msg; i++) {
- int style = PAM_MSG_MEMBER(msg, i, msg_style);
-
- /* Skip messages which don't need a reply */
- if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
- continue;
-
- conv_ctxt->prompts[j++] = i;
- packet_put_utf8_cstring(PAM_MSG_MEMBER(msg, i, msg));
- packet_put_char(style == PAM_PROMPT_ECHO_ON);
- }
- packet_send();
- packet_write_wait();
-
- /*
- * Here the dispatch_run() loop is nested. It should be unwound
- * if keyboard-interactive userauth is abandoned (or restarted;
- * same thing).
- *
- * The condition for breaking out of the nested dispatch_run() loop is
- * ((got kbd-int info reponse) || (kbd-int abandoned))
- *
- * conv_ctxt->finished is set in either of those cases.
- *
- * When abandonment is detected the conv_ctxt->finished is set as
- * is conv_ctxt->abandoned, causing this function to signal
- * userauth nested dispatch_run() loop unwinding and to return
- * PAM_CONV_ERR;
- */
- debug2("Nesting dispatch_run loop");
- dispatch_run(DISPATCH_BLOCK, &conv_ctxt->finished, appdata_ptr);
- debug2("Nested dispatch_run loop exited");
-
- if (conv_ctxt->abandoned) {
- authctxt->unwind_dispatch_loop = 1;
- xfree(conv_ctxt->prompts);
- xfree(conv_ctxt->responses);
- xfree(conv_ctxt);
- debug("PAM conv function returns PAM_CONV_ERR");
- return PAM_CONV_ERR;
- }
-
- if (conv_ctxt->num_received == conv_ctxt->num_expected) {
- *resp = conv_ctxt->responses;
- xfree(conv_ctxt->prompts);
- xfree(conv_ctxt);
- debug("PAM conv function returns PAM_SUCCESS");
- return PAM_SUCCESS;
- }
-
- debug("PAM conv function returns PAM_CONV_ERR");
- xfree(conv_ctxt->prompts);
- xfree(conv_ctxt->responses);
- xfree(conv_ctxt);
- return PAM_CONV_ERR;
-}
-
-static void
-input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- Convctxt *conv_ctxt;
- unsigned int nresp = 0, rlen = 0, i = 0;
- char *resp;
-
- if (authctxt == NULL)
- fatal("input_userauth_info_response_pam: no authentication context");
-
- /* Check for spurious/unexpected info response */
- if (method_kbdint.method_data == NULL) {
- debug("input_userauth_info_response_pam: no method context");
- return;
- }
-
- conv_ctxt = (Convctxt *) method_kbdint.method_data;
-
- nresp = packet_get_int(); /* Number of responses. */
- debug("got %d responses", nresp);
-
-
-#if 0
- if (nresp != conv_ctxt->num_expected)
- fatal("%s: Received incorrect number of responses "
- "(expected %d, received %u)", __func__,
- conv_ctxt->num_expected, nresp);
-#endif
-
- if (nresp > 100)
- fatal("%s: too many replies", __func__);
-
- for (i = 0; i < nresp && i < conv_ctxt->num_expected ; i++) {
- int j = conv_ctxt->prompts[i];
-
- /*
- * We assume that ASCII charset is used for password
- * although the protocol requires UTF-8 encoding for the
- * password string. Therefore, we don't perform code
- * conversion for the string.
- */
- resp = packet_get_string(&rlen);
- if (i < conv_ctxt->num_expected) {
- conv_ctxt->responses[j].resp_retcode = PAM_SUCCESS;
- conv_ctxt->responses[j].resp = xstrdup(resp);
- conv_ctxt->num_received++;
- }
- xfree(resp);
- }
-
- if (nresp < conv_ctxt->num_expected)
- fatal("%s: too few replies (%d < %d)", __func__,
- nresp, conv_ctxt->num_expected);
-
- /* XXX - This could make a covert channel... */
- if (nresp > conv_ctxt->num_expected)
- debug("Ignoring additional PAM replies");
-
- conv_ctxt->finished = 1;
-
- packet_check_eom();
-}
-
-#if 0
-int
-kbdint_pam_abandon_chk(Authctxt *authctxt, Authmethod *method)
-{
- if (!method)
- return 0; /* fatal(), really; it'll happen somewhere else */
-
- if (!method->method_data)
- return 0;
-
- return 1;
-}
-#endif
-
-void
-kbdint_pam_abandon(Authctxt *authctxt, Authmethod *method)
-{
- Convctxt *conv_ctxt;
-
- /*
- * But, if it ever becomes desirable and possible to support
- * kbd-int userauth abandonment, here's what must be done.
- */
- if (!method)
- return;
-
- if (!method->method_data)
- return;
-
- conv_ctxt = (Convctxt *) method->method_data;
-
- /* dispatch_run() loop will exit */
- conv_ctxt->abandoned = 1;
- conv_ctxt->finished = 1;
-
- /*
- * The method_data will be free in the corresponding, active
- * conversation function
- */
- method->method_data = NULL;
-
- /* update counts that can't be updated elsewhere */
- method->abandons++;
- method->attempts++;
-
- /* Finally, we cannot re-use the current current PAM handle */
- authctxt->pam->h = NULL; /* Let the conv function cleanup */
-}
-#endif
diff --git a/usr/src/cmd/ssh/sshd/auth2-passwd.c b/usr/src/cmd/ssh/sshd/auth2-passwd.c
deleted file mode 100644
index 9a1837fb05..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-passwd.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth2-passwd.c,v 1.2 2002/05/31 11:35:15 markus Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "xmalloc.h"
-#include "packet.h"
-#include "log.h"
-#include "auth.h"
-#include "servconf.h"
-
-/* import */
-extern ServerOptions options;
-
-static void
-userauth_passwd(Authctxt *authctxt)
-{
- char *password;
- int change;
- u_int len;
-
- if (!authctxt || !authctxt->method)
- fatal("%s: missing context", __func__);
-
- change = packet_get_char();
- if (change)
- log("password change not supported");
- password = packet_get_string(&len);
- packet_check_eom();
- if (
-#ifdef HAVE_CYGWIN
- check_nt_auth(1, authctxt->pw) &&
-#endif
- auth_password(authctxt, password) == 1) {
- authctxt->method->authenticated = 1;
- }
- memset(password, 0, len);
- xfree(password);
-}
-
-Authmethod method_passwd = {
- "password",
- &options.password_authentication,
- userauth_passwd,
- NULL, /* no abandon function */
- NULL, NULL, /* method data and hist data */
- 1, /* initial userauth */
- 0, 0, 0, /* counters */
- 0, 0, 0, 0, 0, 0 /* state */
-};
diff --git a/usr/src/cmd/ssh/sshd/auth2-pubkey.c b/usr/src/cmd/ssh/sshd/auth2-pubkey.c
deleted file mode 100644
index 658634c195..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2-pubkey.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth2-pubkey.c,v 1.2 2002/05/31 11:35:15 markus Exp $");
-
-#include "ssh2.h"
-#include "xmalloc.h"
-#include "packet.h"
-#include "buffer.h"
-#include "log.h"
-#include "servconf.h"
-#include "compat.h"
-#include "bufaux.h"
-#include "auth.h"
-#include "key.h"
-#include "pathnames.h"
-#include "uidswap.h"
-#include "auth-options.h"
-#include "canohost.h"
-
-#ifdef USE_PAM
-#include <security/pam_appl.h>
-#include "auth-pam.h"
-#endif /* USE_PAM */
-
-/* import */
-extern ServerOptions options;
-extern u_char *session_id2;
-extern int session_id2_len;
-
-static void
-userauth_pubkey(Authctxt *authctxt)
-{
- Buffer b;
- Key *key = NULL;
- char *pkalg;
- u_char *pkblob, *sig;
- u_int alen, blen, slen;
- int have_sig, pktype;
- int authenticated = 0;
-
- if (!authctxt || !authctxt->method)
- fatal("%s: missing context", __func__);
-
- have_sig = packet_get_char();
- if (datafellows & SSH_BUG_PKAUTH) {
- debug2("userauth_pubkey: SSH_BUG_PKAUTH");
- /* no explicit pkalg given */
- pkblob = packet_get_string(&blen);
- buffer_init(&b);
- buffer_append(&b, pkblob, blen);
- /* so we have to extract the pkalg from the pkblob */
- pkalg = buffer_get_string(&b, &alen);
- buffer_free(&b);
- } else {
- pkalg = packet_get_string(&alen);
- pkblob = packet_get_string(&blen);
- }
- pktype = key_type_from_name(pkalg);
- if (pktype == KEY_UNSPEC) {
- /* this is perfectly legal */
- log("userauth_pubkey: unsupported public key algorithm: %s",
- pkalg);
- goto done;
- }
- key = key_from_blob(pkblob, blen);
- if (key == NULL) {
- error("userauth_pubkey: cannot decode key: %s", pkalg);
- goto done;
- }
- if (key->type != pktype) {
- error("userauth_pubkey: type mismatch for decoded key "
- "(received %d, expected %d)", key->type, pktype);
- goto done;
- }
-
- /* Detect and count abandonment */
- if (authctxt->method->method_data) {
- Key *prev_key;
- unsigned char *prev_pkblob;
- int prev_blen;
-
- /*
- * Check for earlier test of a key that was allowed but
- * not followed up with a pubkey req for the same pubkey
- * and with a signature.
- */
- prev_key = authctxt->method->method_data;
- if ((prev_blen = key_to_blob(prev_key,
- &prev_pkblob, NULL))) {
- if (prev_blen != blen ||
- memcmp(prev_pkblob, pkblob, blen) != 0) {
- authctxt->method->abandons++;
- authctxt->method->attempts++;
- }
- }
- key_free(prev_key);
- authctxt->method->method_data = NULL;
- }
-
- if (have_sig) {
- sig = packet_get_string(&slen);
- packet_check_eom();
- buffer_init(&b);
- if (datafellows & SSH_OLD_SESSIONID) {
- buffer_append(&b, session_id2, session_id2_len);
- } else {
- buffer_put_string(&b, session_id2, session_id2_len);
- }
- /* reconstruct packet */
- buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
- buffer_put_cstring(&b, authctxt->user);
- buffer_put_cstring(&b,
- datafellows & SSH_BUG_PKSERVICE ?
- "ssh-userauth" :
- authctxt->service);
- if (datafellows & SSH_BUG_PKAUTH) {
- buffer_put_char(&b, have_sig);
- } else {
- buffer_put_cstring(&b, "publickey");
- buffer_put_char(&b, have_sig);
- buffer_put_cstring(&b, pkalg);
- }
- buffer_put_string(&b, pkblob, blen);
-#ifdef DEBUG_PK
- buffer_dump(&b);
-#endif
- /* test for correct signature */
- if (user_key_allowed(authctxt->pw, key) &&
- key_verify(key, sig, slen, buffer_ptr(&b),
- buffer_len(&b)) == 1) {
- authenticated = 1;
- }
- authctxt->method->postponed = 0;
- buffer_free(&b);
- xfree(sig);
- } else {
- debug("test whether pkalg/pkblob are acceptable");
- packet_check_eom();
-
- /* XXX fake reply and always send PK_OK ? */
- /*
- * XXX this allows testing whether a user is allowed
- * to login: if you happen to have a valid pubkey this
- * message is sent. the message is NEVER sent at all
- * if a user is not allowed to login. is this an
- * issue? -markus
- */
- if (user_key_allowed(authctxt->pw, key)) {
- packet_start(SSH2_MSG_USERAUTH_PK_OK);
- packet_put_string(pkalg, alen);
- packet_put_string(pkblob, blen);
- packet_send();
- packet_write_wait();
- authctxt->method->postponed = 1;
- /*
- * Remember key that was tried so we can
- * correctly detect abandonment. See above.
- */
- authctxt->method->method_data = (void *) key;
- key = NULL;
- }
- }
- if (authenticated != 1)
- auth_clear_options();
-
-done:
- /*
- * XXX TODO: add config options for specifying users for whom
- * this userauth is insufficient and what userauths may
- * continue.
- */
-#ifdef USE_PAM
- if (authenticated) {
- if (!do_pam_non_initial_userauth(authctxt))
- authenticated = 0;
- }
-#endif /* USE_PAM */
-
- debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
- if (key != NULL)
- key_free(key);
- xfree(pkalg);
- xfree(pkblob);
-#ifdef HAVE_CYGWIN
- if (check_nt_auth(0, authctxt->pw) == 0)
- return;
-#endif
- if (authenticated)
- authctxt->method->authenticated = 1;
-}
-
-/* return 1 if user allows given key */
-static int
-user_key_allowed2(struct passwd *pw, Key *key, char *file)
-{
- char line[8192];
- int found_key = 0;
- FILE *f;
- u_long linenum = 0;
- struct stat st;
- Key *found;
- char *fp;
-
- if (pw == NULL)
- return 0;
-
- /* Temporarily use the user's uid. */
- temporarily_use_uid(pw);
-
- debug("trying public key file %s", file);
-
- /* Fail quietly if file does not exist */
- if (stat(file, &st) < 0) {
- /* Restore the privileged uid. */
- restore_uid();
- return 0;
- }
- /* Open the file containing the authorized keys. */
- f = fopen(file, "r");
- if (!f) {
- /* Restore the privileged uid. */
- restore_uid();
- return 0;
- }
- if (options.strict_modes &&
- secure_filename(f, file, pw, line, sizeof(line)) != 0) {
- (void) fclose(f);
- log("Authentication refused: %s", line);
- restore_uid();
- return 0;
- }
-
- found_key = 0;
- found = key_new(key->type);
-
- while (fgets(line, sizeof(line), f)) {
- char *cp, *options = NULL;
- linenum++;
- /* Skip leading whitespace, empty and comment lines. */
- for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (!*cp || *cp == '\n' || *cp == '#')
- continue;
-
- if (key_read(found, &cp) != 1) {
- /* no key? check if there are options for this key */
- int quoted = 0;
- debug2("user_key_allowed: check options: '%s'", cp);
- options = cp;
- for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
- if (*cp == '\\' && cp[1] == '"')
- cp++; /* Skip both */
- else if (*cp == '"')
- quoted = !quoted;
- }
- /* Skip remaining whitespace. */
- for (; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (key_read(found, &cp) != 1) {
- debug2("user_key_allowed: advance: '%s'", cp);
- /* still no key? advance to next line*/
- continue;
- }
- }
- if (key_equal(found, key) &&
- auth_parse_options(pw, options, file, linenum) == 1) {
- found_key = 1;
- debug("matching key found: file %s, line %lu",
- file, linenum);
- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
- verbose("Found matching %s key: %s",
- key_type(found), fp);
- xfree(fp);
- break;
- }
- }
- restore_uid();
- (void) fclose(f);
- key_free(found);
- if (!found_key)
- debug2("key not found");
- return found_key;
-}
-
-/* check whether given key is in .ssh/authorized_keys* */
-int
-user_key_allowed(struct passwd *pw, Key *key)
-{
- int success;
- char *file;
-
- if (pw == NULL)
- return 0;
-
- file = authorized_keys_file(pw);
- success = user_key_allowed2(pw, key, file);
- xfree(file);
- if (success)
- return success;
-
- /* try suffix "2" for backward compat, too */
- file = authorized_keys_file2(pw);
- success = user_key_allowed2(pw, key, file);
- xfree(file);
- return success;
-}
-
-static
-void
-userauth_pubkey_abandon(Authctxt *authctxt, Authmethod *method)
-{
- if (!authctxt || !method)
- return;
-
- if (method->method_data) {
- method->abandons++;
- method->attempts++;
- key_free((Key *) method->method_data);
- method->method_data = NULL;
- }
-}
-
-Authmethod method_pubkey = {
- "publickey",
- &options.pubkey_authentication,
- userauth_pubkey,
- userauth_pubkey_abandon,
- NULL, NULL, /* method data and hist data */
- 0, /* not initial userauth */
- 0, 0, 0, /* counters */
- 0, 0, 0, 0, 0, 0 /* state */
-};
diff --git a/usr/src/cmd/ssh/sshd/auth2.c b/usr/src/cmd/ssh/sshd/auth2.c
deleted file mode 100644
index bc3f4284f3..0000000000
--- a/usr/src/cmd/ssh/sshd/auth2.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/*
- * Copyright (c) 2000 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.95 2002/08/22 21:33:58 markus Exp $");
-
-#include "ssh2.h"
-#include "xmalloc.h"
-#include "packet.h"
-#include "log.h"
-#include "servconf.h"
-#include "compat.h"
-#include "misc.h"
-#include "auth.h"
-#include "dispatch.h"
-#include "sshlogin.h"
-#include "pathnames.h"
-
-#ifdef HAVE_BSM
-#include "bsmaudit.h"
-extern adt_session_data_t *ah;
-#endif /* HAVE_BSM */
-
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif
-
-/* import */
-extern ServerOptions options;
-extern u_char *session_id2;
-extern int session_id2_len;
-
-Authctxt *x_authctxt = NULL;
-
-/* methods */
-
-extern Authmethod method_none;
-extern Authmethod method_pubkey;
-extern Authmethod method_passwd;
-extern Authmethod method_kbdint;
-extern Authmethod method_hostbased;
-extern Authmethod method_external;
-extern Authmethod method_gssapi;
-
-static Authmethod *authmethods[] = {
- &method_none,
-#ifdef GSSAPI
- &method_external,
- &method_gssapi,
-#endif
- &method_pubkey,
- &method_passwd,
- &method_kbdint,
- &method_hostbased,
- NULL
-};
-
-/* protocol */
-
-static void input_service_request(int, u_int32_t, void *);
-static void input_userauth_request(int, u_int32_t, void *);
-
-/* helper */
-static Authmethod *authmethod_lookup(const char *);
-static char *authmethods_get(void);
-static char *authmethods_check_abandonment(Authctxt *authctxt,
- Authmethod *method);
-static void authmethod_count_attempt(Authmethod *method);
-/*static char *authmethods_get_kbdint(void);*/
-int user_key_allowed(struct passwd *, Key *);
-int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
-static int userauth_method_can_run(Authmethod *method);
-static void userauth_reset_methods(void);
-
-/*
- * loop until authctxt->success == TRUE
- */
-
-Authctxt *
-do_authentication2(void)
-{
- Authctxt *authctxt = authctxt_new();
-
- x_authctxt = authctxt; /*XXX*/
-
-#ifdef HAVE_BSM
- fatal_add_cleanup(audit_failed_login_cleanup, authctxt);
-#endif /* HAVE_BSM */
-
- dispatch_init(&dispatch_protocol_error);
- dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
- dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
-
- return (authctxt);
-}
-
-static void
-input_service_request(int type, u_int32_t seq, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- u_int len;
- int acceptit = 0;
- char *service = packet_get_string(&len);
- packet_check_eom();
-
- if (authctxt == NULL)
- fatal("input_service_request: no authctxt");
-
- if (strcmp(service, "ssh-userauth") == 0) {
- if (!authctxt->success) {
- acceptit = 1;
- /* now we can handle user-auth requests */
- dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
- }
- }
- /* XXX all other service requests are denied */
-
- if (acceptit) {
- packet_start(SSH2_MSG_SERVICE_ACCEPT);
- packet_put_cstring(service);
- packet_send();
- packet_write_wait();
- } else {
- debug("bad service request %s", service);
- packet_disconnect("bad service request %s", service);
- }
- xfree(service);
-}
-
-static void
-input_userauth_request(int type, u_int32_t seq, void *ctxt)
-{
- Authctxt *authctxt = ctxt;
- Authmethod *m = NULL;
- char *user, *service, *method, *style = NULL;
- int valid_attempt;
-
- if (authctxt == NULL)
- fatal("input_userauth_request: no authctxt");
-
- user = packet_get_string(NULL);
- service = packet_get_string(NULL);
- method = packet_get_string(NULL);
- debug("userauth-request for user %s service %s method %s", user,
- service, method);
- debug("attempt %d initial attempt %d failures %d initial failures %d",
- authctxt->attempt, authctxt->init_attempt,
- authctxt->failures, authctxt->init_failures);
-
- m = authmethod_lookup(method);
-
- if ((style = strchr(user, ':')) != NULL)
- *style++ = 0;
-
- authctxt->attempt++;
- if (m != NULL && m->is_initial)
- authctxt->init_attempt++;
-
- if (options.pre_userauth_hook != NULL &&
- run_auth_hook(options.pre_userauth_hook, user, m->name) != 0) {
- valid_attempt = 0;
- } else {
- valid_attempt = 1;
- }
-
- if (authctxt->attempt == 1) {
- /* setup auth context */
- authctxt->pw = getpwnamallow(user);
- /* May want to abstract SSHv2 services someday */
- if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
- /* enforced in userauth_finish() below */
- if (valid_attempt) {
- authctxt->valid = 1;
- }
- debug2("input_userauth_request: setting up authctxt for %s", user);
- } else {
- log("input_userauth_request: illegal user %s", user);
- }
- setproctitle("%s", authctxt->pw ? user : "unknown");
- authctxt->user = xstrdup(user);
- authctxt->service = xstrdup(service);
- authctxt->style = style ? xstrdup(style) : NULL;
- userauth_reset_methods();
- } else {
- char *abandoned;
-
- /*
- * Check for abandoned [multi-round-trip] userauths
- * methods (e.g., kbdint). Userauth method abandonment
- * should be treated as userauth method failure and
- * counted against max_auth_tries.
- */
- abandoned = authmethods_check_abandonment(authctxt, m);
-
- if (abandoned != NULL &&
- authctxt->failures > options.max_auth_tries) {
- /* userauth_finish() will now packet_disconnect() */
- userauth_finish(authctxt, abandoned);
- /* NOTREACHED */
- }
-
- /* Handle user|service changes, possibly packet_disconnect() */
- userauth_user_svc_change(authctxt, user, service);
- }
-
- authctxt->method = m;
-
- /* run userauth method, try to authenticate user */
- if (m != NULL && userauth_method_can_run(m)) {
- debug2("input_userauth_request: try method %s", method);
-
- m->postponed = 0;
- m->abandoned = 0;
- m->authenticated = 0;
-
- if (!m->is_initial ||
- authctxt->init_failures < options.max_init_auth_tries)
- m->userauth(authctxt);
-
- authmethod_count_attempt(m);
-
- if (authctxt->unwind_dispatch_loop) {
- /*
- * Method ran nested dispatch loop but was
- * abandoned. Cleanup and return without doing
- * anything else; we're just unwinding the stack.
- */
- authctxt->unwind_dispatch_loop = 0;
- goto done;
- }
-
- if (m->postponed)
- goto done; /* multi-round trip userauth not finished */
-
- if (m->abandoned) {
- /* multi-round trip userauth abandoned, log failure */
- auth_log(authctxt, 0, method, " ssh2");
- goto done;
- }
- }
-
- userauth_finish(authctxt, method);
-
-done:
- xfree(service);
- xfree(user);
- xfree(method);
-}
-
-void
-userauth_finish(Authctxt *authctxt, char *method)
-{
- int authenticated, partial;
-
- if (authctxt == NULL)
- fatal("%s: missing context", __func__);
-
- /* unknown method handling -- must elicit userauth failure msg */
- if (authctxt->method == NULL) {
- authenticated = 0;
- partial = 0;
- goto done_checking;
- }
-
-#ifndef USE_PAM
- /* Special handling for root (done elsewhere for PAM) */
- if (authctxt->method->authenticated &&
- authctxt->pw != NULL && authctxt->pw->pw_uid == 0 &&
- !auth_root_allowed(method))
- authctxt->method->authenticated = 0;
-#endif /* USE_PAM */
-
-#ifdef _UNICOS
- if (authctxt->method->authenticated &&
- cray_access_denied(authctxt->user)) {
- authctxt->method->authenticated = 0;
- fatal("Access denied for user %s.",authctxt->user);
- }
-#endif /* _UNICOS */
-
- partial = userauth_check_partial_failure(authctxt);
- authenticated = authctxt->method->authenticated;
-
-#ifdef USE_PAM
- /*
- * If the userauth method failed to complete PAM work then force
- * partial failure.
- */
- if (authenticated && !AUTHPAM_DONE(authctxt))
- partial = 1;
-#endif /* USE_PAM */
-
- /*
- * To properly support invalid userauth method names we set
- * authenticated=0, partial=0 above and know that
- * authctxt->method == NULL.
- *
- * No unguarded reference to authctxt->method allowed from here.
- * Checking authenticated != 0 is a valid guard; authctxt->method
- * MUST NOT be NULL if authenticated.
- */
-done_checking:
- if (!authctxt->valid && authenticated) {
- /*
- * We get here if the PreUserauthHook fails but the
- * user is otherwise valid.
- * An error in the PAM handling could also get us here
- * but we need not panic, just treat as a failure.
- */
- authctxt->method->authenticated = 0;
- authenticated = 0;
- log("Ignoring authenticated invalid user %s",
- authctxt->user);
- auth_log(authctxt, 0, method, " ssh2");
- }
-
- /* Log before sending the reply */
- auth_log(authctxt, authenticated, method, " ssh2");
-
- if (authenticated && !partial) {
-
- /* turn off userauth */
- dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
- packet_start(SSH2_MSG_USERAUTH_SUCCESS);
- packet_send();
- packet_write_wait();
- /* now we can break out */
- authctxt->success = 1;
- } else {
- char *methods;
-
- if (authctxt->method && authctxt->method->is_initial)
- authctxt->init_failures++;
-
- authctxt->method = NULL;
-
-#ifdef USE_PAM
- /*
- * Keep track of last PAM error (or PERM_DENIED) for BSM
- * login failure auditing, which may run after the PAM
- * state has been cleaned up.
- */
- authctxt->pam_retval = AUTHPAM_ERROR(authctxt, PAM_PERM_DENIED);
-#endif /* USE_PAM */
-
- if (authctxt->failures++ > options.max_auth_tries) {
-#ifdef HAVE_BSM
- fatal_remove_cleanup(audit_failed_login_cleanup,
- authctxt);
- audit_sshd_login_failure(&ah, PAM_MAXTRIES,
- authctxt->user);
-#endif /* HAVE_BSM */
- packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
- }
-
-#ifdef _UNICOS
- if (strcmp(method, "password") == 0)
- cray_login_failure(authctxt->user, IA_UDBERR);
-#endif /* _UNICOS */
- packet_start(SSH2_MSG_USERAUTH_FAILURE);
-
- /*
- * If (partial) then authmethods_get() will return only
- * required methods, likely only "keyboard-interactive;"
- * (methods == NULL) implies failure, even if (partial == 1)
- */
- methods = authmethods_get();
- packet_put_cstring(methods);
- packet_put_char((authenticated && partial && methods) ? 1 : 0);
- if (methods)
- xfree(methods);
- packet_send();
- packet_write_wait();
- }
-}
-
-/* get current user */
-
-struct passwd*
-auth_get_user(void)
-{
- return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
-}
-
-#define DELIM ","
-
-#if 0
-static char *
-authmethods_get_kbdint(void)
-{
- Buffer b;
- int i;
-
- for (i = 0; authmethods[i] != NULL; i++) {
- if (strcmp(authmethods[i]->name, "keyboard-interactive") != 0)
- continue;
- return xstrdup(authmethods[i]->name);
- }
- return NULL;
-}
-#endif
-
-void
-userauth_user_svc_change(Authctxt *authctxt, char *user, char *service)
-{
- /*
- * NOTE:
- *
- * SSHv2 services should be abstracted and service changes during
- * userauth should be supported as per the userauth draft. In the PAM
- * case, support for multiple SSHv2 services means that we have to
- * format the PAM service name according to the SSHv2 service *and* the
- * SSHv2 userauth being attempted ("passwd", "kbdint" and "other").
- *
- * We'll cross that bridge when we come to it. For now disallow service
- * changes during userauth if using PAM, but allow username changes.
- */
-
- /* authctxt->service must == ssh-connection here */
- if (service != NULL && strcmp(service, authctxt->service) != 0) {
- packet_disconnect("Change of service not "
- "allowed: %s and %s",
- authctxt->service, service);
- }
- if (user != NULL && authctxt->user != NULL &&
- strcmp(user, authctxt->user) == 0)
- return;
-
- /* All good; update authctxt */
- xfree(authctxt->user);
- authctxt->user = xstrdup(user);
- pwfree(&authctxt->pw);
- authctxt->pw = getpwnamallow(user);
- authctxt->valid = (authctxt->pw != NULL);
-
- /* Forget method state; abandon postponed userauths */
- userauth_reset_methods();
-}
-
-int
-userauth_check_partial_failure(Authctxt *authctxt)
-{
- int i;
- int required = 0;
- int sufficient = 0;
-
- /*
- * v1 does not set authctxt->method
- * partial userauth failure is a v2 concept
- */
- if (authctxt->method == NULL)
- return 0;
-
- for (i = 0; authmethods[i] != NULL; i++) {
- if (authmethods[i]->required)
- required++;
- if (authmethods[i]->sufficient)
- sufficient++;
- }
-
- if (required == 0 && sufficient == 0)
- return !authctxt->method->authenticated;
-
- if (required == 1 && authctxt->method->required)
- return !authctxt->method->authenticated;
-
- if (sufficient && authctxt->method->sufficient)
- return !authctxt->method->authenticated;
-
- return 1;
-}
-
-int
-userauth_method_can_run(Authmethod *method)
-{
- if (method->not_again)
- return 0;
-
- return 1;
-}
-
-static
-void
-userauth_reset_methods(void)
-{
- int i;
-
- for (i = 0; authmethods[i] != NULL; i++) {
- /* note: counters not reset */
- authmethods[i]->required = 0;
- authmethods[i]->sufficient = 0;
- authmethods[i]->authenticated = 0;
- authmethods[i]->not_again = 0;
- authmethods[i]->postponed = 0;
- authmethods[i]->abandoned = 0;
- }
-}
-
-void
-userauth_force_kbdint(void)
-{
- int i;
-
- for (i = 0; authmethods[i] != NULL; i++) {
- authmethods[i]->required = 0;
- authmethods[i]->sufficient = 0;
- }
- method_kbdint.required = 1;
-}
-
-/*
- * Check to see if a previously run multi-round trip userauth method has
- * been abandoned and call its cleanup function.
- *
- * Abandoned userauth method invocations are counted as userauth failures.
- */
-static
-char *
-authmethods_check_abandonment(Authctxt *authctxt, Authmethod *method)
-{
- int i;
-
- /* optimization: check current method first */
- if (method && method->postponed) {
- method->postponed = 0;
- if (method->abandon)
- method->abandon(authctxt, method);
- else
- method->abandons++;
- authctxt->failures++; /* abandonment -> failure */
- if (method->is_initial)
- authctxt->init_failures++;
-
- /*
- * Since we check for abandonment whenever a userauth is
- * requested we know only one method could have been
- * in postponed state, so we can return now.
- */
- return (method->name);
- }
- for (i = 0; authmethods[i] != NULL; i++) {
- if (!authmethods[i]->postponed)
- continue;
-
- /* some method was postponed and a diff one is being started */
- if (method != authmethods[i]) {
- authmethods[i]->postponed = 0;
- if (authmethods[i]->abandon)
- authmethods[i]->abandon(authctxt,
- authmethods[i]);
- else
- authmethods[i]->abandons++;
- authctxt->failures++;
- if (authmethods[i]->is_initial)
- authctxt->init_failures++;
- return (authmethods[i]->name); /* see above */
- }
- }
-
- return NULL;
-}
-
-static char *
-authmethods_get(void)
-{
- Buffer b;
- char *list;
- int i;
- int sufficient = 0;
- int required = 0;
- int authenticated = 0;
- int partial = 0;
-
- /*
- * If at least one method succeeded partially then at least one
- * authmethod will be required and only required methods should
- * continue.
- */
- for (i = 0; authmethods[i] != NULL; i++) {
- if (authmethods[i]->authenticated)
- authenticated++;
- if (authmethods[i]->required)
- required++;
- if (authmethods[i]->sufficient)
- sufficient++;
- }
-
- partial = (required + sufficient) > 0;
-
- buffer_init(&b);
- for (i = 0; authmethods[i] != NULL; i++) {
- if (strcmp(authmethods[i]->name, "none") == 0)
- continue;
- if (required && !authmethods[i]->required)
- continue;
- if (sufficient && !required && !authmethods[i]->sufficient)
- continue;
- if (authmethods[i]->not_again)
- continue;
-
- if (authmethods[i]->required) {
- if (buffer_len(&b) > 0)
- buffer_append(&b, ",", 1);
- buffer_append(&b, authmethods[i]->name,
- strlen(authmethods[i]->name));
- continue;
- }
-
- /*
- * A method can be enabled (marked sufficient)
- * dynamically provided that at least one other method
- * has succeeded partially.
- */
- if ((partial && authmethods[i]->sufficient) ||
- (authmethods[i]->enabled != NULL &&
- *(authmethods[i]->enabled) != 0)) {
- if (buffer_len(&b) > 0)
- buffer_append(&b, ",", 1);
- buffer_append(&b, authmethods[i]->name,
- strlen(authmethods[i]->name));
- }
- }
- buffer_append(&b, "\0", 1);
- list = xstrdup(buffer_ptr(&b));
- buffer_free(&b);
- return list;
-}
-
-static Authmethod *
-authmethod_lookup(const char *name)
-{
- int i;
-
- /*
- * Method must be sufficient, required or enabled and must not
- * be marked as not able to run again
- */
- if (name != NULL)
- for (i = 0; authmethods[i] != NULL; i++)
- if (((authmethods[i]->sufficient ||
- authmethods[i]->required) ||
- (authmethods[i]->enabled != NULL &&
- *(authmethods[i]->enabled) != 0)) &&
- !authmethods[i]->not_again &&
- strcmp(name, authmethods[i]->name) == 0)
- return authmethods[i];
- debug2("Unrecognized authentication method name: %s",
- name ? name : "NULL");
- return NULL;
-}
-
-static void
-authmethod_count_attempt(Authmethod *method)
-{
- if (!method)
- fatal("Internal error in authmethod_count_attempt()");
-
- if (method->postponed)
- return;
-
- method->attempts++;
-
- if (method->abandoned)
- method->abandons++;
- else if (method->authenticated)
- method->successes++;
- else
- method->failures++;
-
- return;
-}
diff --git a/usr/src/cmd/ssh/sshd/bsmaudit.c b/usr/src/cmd/ssh/sshd/bsmaudit.c
deleted file mode 100644
index c46d295972..0000000000
--- a/usr/src/cmd/ssh/sshd/bsmaudit.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- *
- * usr/src/cmd/ssh/sshd/bsmaudit.c
- *
- * Taken from the on81 usr/src/lib/libbsm/common/audit_login.c
- */
-#include "includes.h"
-
-#include <sys/systeminfo.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/systeminfo.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <signal.h>
-
-#include <stdarg.h>
-#include <pwd.h>
-#include <shadow.h>
-#include <utmpx.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <locale.h>
-
-#include "log.h"
-#include "packet.h"
-#include "canohost.h"
-#include "servconf.h"
-#include "xmalloc.h"
-#include <errno.h>
-#include <bsm/adt.h>
-#include <bsm/adt_event.h>
-
-extern uint_t utmp_len; /* XXX - Yuck; we'll keep this for now */
-extern ServerOptions options;
- /*
- * XXX - Yuck; we should have a
- * get_client_name_or_ip that does the
- * right thing wrt reverse lookups
- */
-
-void
-audit_sshd_chauthtok(int pam_retval, uid_t uid, gid_t gid)
-{
- adt_session_data_t *ah = NULL;
- adt_event_data_t *event = NULL;
- const char *how = "couldn't start adt session";
- int saved_errno = 0;
-
- if (adt_start_session(&ah, NULL, 0) != 0) {
- saved_errno = errno;
- goto fail;
- }
- if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW) != 0) {
- saved_errno = errno;
- how = "couldn't set adt user";
- goto fail;
- }
-
- if ((event = adt_alloc_event(ah, ADT_passwd)) == NULL) {
- saved_errno = errno;
- how = "couldn't allocate adt event";
- goto fail;
- }
-
- if (pam_retval == PAM_SUCCESS) {
- if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
- saved_errno = errno;
- how = "couldn't put adt event";
- goto fail;
- }
- } else if (adt_put_event(event, ADT_FAILURE,
- ADT_FAIL_PAM + pam_retval) != 0) {
- saved_errno = errno;
- how = "couldn't put adt event";
- goto fail;
- }
-
- adt_free_event(event);
- (void) adt_end_session(ah);
- return;
-
-fail:
- adt_free_event(event);
- (void) adt_end_session(ah);
-
- fatal("Auditing of password change failed: %s (%s)",
- strerror(saved_errno), how);
-}
-
-void
-audit_sshd_login(adt_session_data_t **ah, pid_t pid)
-{
- adt_event_data_t *event = NULL;
- const char *how;
- int saved_errno = 0;
- ucred_t *ucred = NULL;
-
- if (ah == NULL) {
- how = "programmer error";
- saved_errno = EINVAL;
- goto fail;
- }
-
- if (adt_start_session(ah, NULL, 0) != 0) {
- saved_errno = errno;
- how = "couldn't start adt session";
- goto fail;
- }
-
- if ((ucred = ucred_get(pid)) == NULL) {
- saved_errno = errno;
- how = "ucred_get() failed to obtain user credential";
- goto fail;
- }
-
- if (adt_set_from_ucred(*ah, ucred, ADT_NEW)) {
- saved_errno = errno;
- how = "adt_set_from_ucred() failed to set user credential";
- goto fail;
- }
-
- if ((event = adt_alloc_event(*ah, ADT_ssh)) == NULL) {
- saved_errno = errno;
- how = "couldn't allocate adt event";
- goto fail;
- }
-
- if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
- saved_errno = errno;
- how = "couldn't put adt event";
- goto fail;
- }
-
- adt_free_event(event);
- ucred_free(ucred);
- /* Don't end adt session - leave for when logging out */
- return;
-
-fail:
- if (ucred != NULL)
- ucred_free(ucred);
- adt_free_event(event);
- (void) adt_end_session(*ah);
-
- fatal("Auditing of login failed: %s (%s)",
- strerror(saved_errno), how);
-}
-
-void
-audit_sshd_login_failure(adt_session_data_t **ah, int pam_retval, char *user)
-{
- adt_event_data_t *event = NULL;
- const char *how;
- int saved_errno = 0;
- struct passwd pwd;
- char *pwdbuf = NULL;
- size_t pwdbuf_len;
- long pwdbuf_len_max;
- uid_t uid = ADT_NO_ATTRIB;
- gid_t gid = ADT_NO_ATTRIB;
-
- if (ah == NULL) {
- how = "programmer error";
- saved_errno = EINVAL;
- goto fail;
- }
-
- if ((pwdbuf_len_max = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
- saved_errno = errno;
- how = "couldn't determine maximum size of password buffer";
- goto fail;
- }
-
- pwdbuf_len = (size_t)pwdbuf_len_max;
- pwdbuf = xmalloc(pwdbuf_len);
-
- if (adt_start_session(ah, NULL, ADT_USE_PROC_DATA) != 0) {
- saved_errno = errno;
- how = "couldn't start adt session";
- goto fail;
- }
-
- /*
- * Its possible to reach this point with user being invalid so
- * we check here to make sure that the user in question has a valid
- * password entry.
- */
- if ((user != NULL) &&
- (getpwnam_r(user, &pwd, pwdbuf, pwdbuf_len) != NULL)) {
- uid = pwd.pw_uid;
- gid = pwd.pw_gid;
- }
-
- if (adt_set_user(*ah, uid, gid, uid, gid, NULL, ADT_NEW) != 0) {
- saved_errno = errno;
- how = "couldn't set adt user";
- goto fail;
- }
-
- if ((event = adt_alloc_event(*ah, ADT_ssh)) == NULL) {
- saved_errno = errno;
- how = "couldn't allocate adt event";
- goto fail;
- }
-
- if (adt_put_event(event, ADT_FAILURE, ADT_FAIL_PAM + pam_retval) != 0) {
- saved_errno = errno;
- how = "couldn't put adt event";
- goto fail;
- }
-
- xfree(pwdbuf);
- adt_free_event(event);
- (void) adt_end_session(*ah);
- *ah = NULL;
- return;
-
-fail:
- if (pwdbuf != NULL)
- xfree(pwdbuf);
- adt_free_event(event);
- (void) adt_end_session(*ah);
-
- fatal("Auditing of login failed: %s (%s)",
- strerror(saved_errno), how);
-}
-
-void
-audit_sshd_logout(adt_session_data_t **ah)
-{
- adt_event_data_t *event = NULL;
- const char *how = "programmer error";
- int saved_errno = 0;
-
- if (!ah) {
- saved_errno = EINVAL;
- goto fail;
- }
-
- if ((event = adt_alloc_event(*ah, ADT_logout)) == NULL) {
- saved_errno = errno;
- how = "couldn't allocate adt event";
- goto fail;
- }
-
- if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
- saved_errno = errno;
- how = "couldn't put adt event";
- goto fail;
- }
-
- adt_free_event(event);
- (void) adt_end_session(*ah);
- *ah = NULL;
- return;
-
-fail:
- adt_free_event(event);
- (void) adt_end_session(*ah);
-
- fatal("Auditing of logout failed: %s (%s)",
- how, strerror(saved_errno));
-}
-
-/*
- * audit_sshd_settid stores the terminal id while it is still
- * available.
- *
- * The failure cases are lack of resources or incorrect permissions.
- * libbsm generates syslog messages, so there's no value doing more
- * here. ADT_NO_AUDIT leaves the auid at AU_NOAUDITID and will be
- * replaced when one of the above functions is called.
- */
-void
-audit_sshd_settid(int sock)
-{
- adt_session_data_t *ah;
- adt_termid_t *termid;
-
- if (adt_start_session(&ah, NULL, 0) == 0) {
- if (adt_load_termid(sock, &termid) == 0) {
- if (adt_set_user(ah, ADT_NO_AUDIT,
- ADT_NO_AUDIT, 0, ADT_NO_AUDIT,
- termid, ADT_SETTID) == 0)
- (void) adt_set_proc(ah);
- free(termid);
- }
- (void) adt_end_session(ah);
- }
-}
diff --git a/usr/src/cmd/ssh/sshd/bsmaudit.h b/usr/src/cmd/ssh/sshd/bsmaudit.h
deleted file mode 100644
index 72f599a240..0000000000
--- a/usr/src/cmd/ssh/sshd/bsmaudit.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-
-#ifndef _BSMAUDIT_H
-#define _BSMAUDIT_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <bsm/adt.h>
-#include <bsm/adt_event.h>
-#include <pwd.h>
-
-void audit_sshd_chauthtok(int pam_retval, uid_t uid, gid_t gid);
-void audit_sshd_login(adt_session_data_t **ah, pid_t pid);
-void audit_sshd_login_failure(adt_session_data_t **ah, int pam_retval,
- char *user);
-void audit_sshd_logout(adt_session_data_t **ah);
-void audit_sshd_settid(int);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _BSMAUDIT_H */
diff --git a/usr/src/cmd/ssh/sshd/groupaccess.c b/usr/src/cmd/ssh/sshd/groupaccess.c
deleted file mode 100644
index 2239832e1b..0000000000
--- a/usr/src/cmd/ssh/sshd/groupaccess.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-/*
- * Copyright (c) 2001 Kevin Steves. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: groupaccess.c,v 1.5 2002/03/04 17:27:39 stevesk Exp $");
-
-#include "groupaccess.h"
-#include "xmalloc.h"
-#include "match.h"
-#include "log.h"
-#include <alloca.h>
-
-static int ngroups, ngroups_lim;
-static char **groups_byname;
-
-/*
- * Initialize group access list for user with primary (base) and
- * supplementary groups. Return the number of groups in the list.
- */
-int
-ga_init(const char *user, gid_t base)
-{
- gid_t *groups_bygid;
- int i, j;
- struct group *gr;
-
- if (ngroups_lim == 0) {
- /* Add one for the base gid */
- ngroups_lim = sysconf(_SC_NGROUPS_MAX) + 1;
- groups_byname = malloc(sizeof (char *) * ngroups_lim);
- } else if (ngroups > 0)
- ga_free();
-
- groups_bygid = alloca(ngroups_lim * sizeof (gid_t));
-
- ngroups = ngroups_lim;
- if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
- log("getgrouplist: groups list too small");
- for (i = 0, j = 0; i < ngroups; i++)
- if ((gr = getgrgid(groups_bygid[i])) != NULL)
- groups_byname[j++] = xstrdup(gr->gr_name);
- return (ngroups = j);
-}
-
-/*
- * Return 1 if one of user's groups is contained in groups.
- * Return 0 otherwise. Use match_pattern() for string comparison.
- */
-int
-ga_match(char * const *groups, int n)
-{
- int i, j;
-
- for (i = 0; i < ngroups; i++)
- for (j = 0; j < n; j++)
- if (match_pattern(groups_byname[i], groups[j]))
- return (1);
- return (0);
-}
-
-/*
- * Return 1 if one of user's groups matches group_pattern list.
- * Return 0 on negated or no match.
- */
-int
-ga_match_pattern_list(const char *group_pattern)
-{
- int i, found = 0;
- size_t len = strlen(group_pattern);
-
- for (i = 0; i < ngroups; i++) {
- switch (match_pattern_list(groups_byname[i],
- group_pattern, len, 0)) {
- case -1:
- return (0); /* Negated match wins */
- case 0:
- continue;
- case 1:
- found = 1;
- }
- }
- return (found);
-}
-
-/*
- * Free memory allocated for group access list.
- */
-void
-ga_free(void)
-{
- int i;
-
- if (ngroups > 0) {
- for (i = 0; i < ngroups; i++)
- xfree(groups_byname[i]);
- ngroups = 0;
- }
-}
diff --git a/usr/src/cmd/ssh/sshd/gss-serv.c b/usr/src/cmd/ssh/sshd/gss-serv.c
deleted file mode 100644
index 7ff525c306..0000000000
--- a/usr/src/cmd/ssh/sshd/gss-serv.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright (c) 2001-2003 Simon Wilkinson. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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.
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-
-#ifdef GSSAPI
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "includes.h"
-#include "ssh.h"
-#include "ssh2.h"
-#include "xmalloc.h"
-#include "buffer.h"
-#include "bufaux.h"
-#include "packet.h"
-#include "compat.h"
-#include <openssl/evp.h>
-#include "cipher.h"
-#include "kex.h"
-#include "auth.h"
-#include "log.h"
-#include "channels.h"
-#include "session.h"
-#include "dispatch.h"
-#include "servconf.h"
-#include "uidswap.h"
-#include "compat.h"
-#include <pwd.h>
-
-#include "ssh-gss.h"
-
-extern char **environ;
-
-extern ServerOptions options;
-extern uchar_t *session_id2;
-extern int session_id2_len;
-
-Gssctxt *xxx_gssctxt;
-
-void
-ssh_gssapi_server_kex_hook(Kex *kex, char **proposal)
-{
- gss_OID_set mechs = GSS_C_NULL_OID_SET;
-
- if (kex == NULL || !kex->server)
- fatal("INTERNAL ERROR (%s)", __func__);
-
- ssh_gssapi_server_mechs(&mechs);
- ssh_gssapi_modify_kex(kex, mechs, proposal);
-}
-
-void
-ssh_gssapi_server_mechs(gss_OID_set *mechs)
-{
- static gss_OID_set supported = GSS_C_NULL_OID_SET;
- gss_OID_set s, acquired, indicated = GSS_C_NULL_OID_SET;
- gss_cred_id_t creds;
- OM_uint32 maj, min;
- int i;
-
- if (!mechs) {
- (void) gss_release_oid_set(&min, &supported);
- return;
- }
-
- if (supported != GSS_C_NULL_OID_SET) {
- *mechs = supported;
- return;
- }
-
- *mechs = GSS_C_NULL_OID_SET;
-
- maj = gss_create_empty_oid_set(&min, &s);
- if (GSS_ERROR(maj)) {
- debug("Could not allocate GSS-API resources (%s)",
- ssh_gssapi_last_error(NULL, &maj, &min));
- return;
- }
-
- maj = gss_indicate_mechs(&min, &indicated);
- if (GSS_ERROR(maj)) {
- debug("No GSS-API mechanisms are installed");
- return;
- }
-
- maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated,
- GSS_C_ACCEPT, &creds, &acquired, NULL);
-
- if (GSS_ERROR(maj))
- debug("Failed to acquire GSS-API credentials for any "
- "mechanisms (%s)", ssh_gssapi_last_error(NULL, &maj, &min));
-
- (void) gss_release_oid_set(&min, &indicated);
- (void) gss_release_cred(&min, &creds);
-
- if (acquired == GSS_C_NULL_OID_SET || acquired->count == 0)
- return;
-
- for (i = 0; i < acquired->count; i++) {
- if (ssh_gssapi_is_spnego(&acquired->elements[i]))
- continue;
-
- maj = gss_add_oid_set_member(&min, &acquired->elements[i], &s);
- if (GSS_ERROR(maj)) {
- debug("Could not allocate GSS-API resources (%s)",
- ssh_gssapi_last_error(NULL, &maj, &min));
- return;
- }
- }
- (void) gss_release_oid_set(&min, &acquired);
-
- if (s->count) {
- supported = s;
- *mechs = s;
- }
-}
-
-/*
- * Wrapper around accept_sec_context. Requires that the context contains:
- *
- * oid
- * credentials (from ssh_gssapi_acquire_cred)
- */
-/* Priviledged */
-OM_uint32
-ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_t recv_tok,
- gss_buffer_t send_tok)
-{
- /*
- * Acquiring a cred for the ctx->desired_mech for GSS_C_NO_NAME
- * may well be probably better than using GSS_C_NO_CREDENTIAL
- * and then checking that ctx->desired_mech agrees with
- * ctx->actual_mech...
- */
- ctx->major = gss_accept_sec_context(&ctx->minor, &ctx->context,
- GSS_C_NO_CREDENTIAL, recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
- &ctx->src_name, &ctx->actual_mech, send_tok, &ctx->flags,
- NULL, &ctx->deleg_creds);
-
- if (GSS_ERROR(ctx->major))
- ssh_gssapi_error(ctx, "accepting security context");
-
- if (ctx->major == GSS_S_CONTINUE_NEEDED && send_tok->length == 0)
- fatal("Zero length GSS context token output when "
- "continue needed");
- else if (GSS_ERROR(ctx->major) && send_tok->length == 0)
- debug2("Zero length GSS context error token output");
-
- if (ctx->major == GSS_S_COMPLETE &&
- ctx->desired_mech != GSS_C_NULL_OID &&
- (ctx->desired_mech->length != ctx->actual_mech->length ||
- memcmp(ctx->desired_mech->elements, ctx->actual_mech->elements,
- ctx->desired_mech->length) != 0)) {
-
- gss_OID_set supported;
- OM_uint32 min;
- int present = 0;
-
- debug("The client did not use the GSS-API mechanism it "
- "asked for");
-
- /* Let it slide as long as the mech is supported */
- ssh_gssapi_server_mechs(&supported);
- if (supported != GSS_C_NULL_OID_SET) {
- (void) gss_test_oid_set_member(&min, ctx->actual_mech,
- supported, &present);
- }
- if (!present)
- ctx->major = GSS_S_BAD_MECH;
- }
-
- if (ctx->deleg_creds)
- debug("Received delegated GSS credentials");
-
- if (ctx->major == GSS_S_COMPLETE) {
- ctx->major = gss_inquire_context(&ctx->minor, ctx->context,
- NULL, &ctx->dst_name, NULL, NULL, NULL, NULL,
- &ctx->established);
-
- if (GSS_ERROR(ctx->major)) {
- ssh_gssapi_error(ctx,
- "inquiring established sec context");
- return (ctx->major);
- }
-
- xxx_gssctxt = ctx;
- }
-
- return (ctx->major);
-}
-
-
-/* As user - called through fatal cleanup hook */
-void
-ssh_gssapi_cleanup_creds(Gssctxt *ctx)
-{
-#ifdef HAVE_GSS_STORE_CRED
- /* pam_setcred() will take care of this */
- return;
-#else
- return;
-/* #error "Portability broken in cleanup of stored creds" */
-#endif /* HAVE_GSS_STORE_CRED */
-}
-
-void
-ssh_gssapi_storecreds(Gssctxt *ctx, Authctxt *authctxt)
-{
-#ifdef USE_PAM
- char **penv, **tmp_env;
-#endif /* USE_PAM */
-
- if (authctxt == NULL) {
- error("Missing context while storing GSS-API credentials");
- return;
- }
-
- if (ctx == NULL && xxx_gssctxt == NULL)
- return;
-
- if (ctx == NULL)
- ctx = xxx_gssctxt;
-
- if (!options.gss_cleanup_creds ||
- ctx->deleg_creds == GSS_C_NO_CREDENTIAL) {
- debug3("Not storing delegated GSS credentials"
- " (none delegated)");
- return;
- }
-
- if (!authctxt->valid || authctxt->pw == NULL) {
- debug3("Not storing delegated GSS credentials"
- " for invalid user");
- return;
- }
-
- debug("Storing delegated GSS-API credentials");
-
- /*
- * The GSS-API has a flaw in that it does not provide a
- * mechanism by which delegated credentials can be made
- * available for acquisition by GSS_Acquire_cred() et. al.;
- * gss_store_cred() is the proposed GSS-API extension for
- * generically storing delegated credentials.
- *
- * gss_store_cred() does not speak to how credential stores are
- * referenced. Generically this may be done by switching to the
- * user context of the user in whose default credential store we
- * wish to place delegated credentials. But environment
- * variables could conceivably affect the choice of credential
- * store as well, and perhaps in a mechanism-specific manner.
- *
- * SUNW -- On Solaris the euid selects the current credential
- * store, but PAM modules could select alternate stores by
- * setting, for example, KRB5CCNAME, so we also use the PAM
- * environment temporarily.
- */
-
-#ifdef HAVE_GSS_STORE_CRED
-#ifdef USE_PAM
- /*
- * PAM may have set mechanism-specific variables (e.g.,
- * KRB5CCNAME). fetch_pam_environment() protects against LD_*
- * and other environment variables.
- */
- penv = fetch_pam_environment(authctxt);
- tmp_env = environ;
- environ = penv;
-#endif /* USE_PAM */
- if (authctxt->pw->pw_uid != geteuid()) {
- temporarily_use_uid(authctxt->pw);
- ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds,
- GSS_C_INITIATE, GSS_C_NULL_OID, 0, ctx->default_creds,
- NULL, NULL);
- restore_uid();
- } else {
- /* only when logging in as the privileged user used by sshd */
- ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds,
- GSS_C_INITIATE, GSS_C_NULL_OID, 0, ctx->default_creds,
- NULL, NULL);
- }
-#ifdef USE_PAM
- environ = tmp_env;
- free_pam_environment(penv);
-#endif /* USE_PAM */
- if (GSS_ERROR(ctx->major))
- ssh_gssapi_error(ctx, "storing delegated credentials");
-
-#else
-#ifdef KRB5_GSS
-#error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()"
- if (ssh_gssapi_is_krb5(ctx->mech))
- ssh_gssapi_krb5_storecreds(ctx);
-#endif /* KRB5_GSS */
-#ifdef GSI_GSS
-#error "GSI krb5-specific code missing in ssh_gssapi_storecreds()"
- if (ssh_gssapi_is_gsi(ctx->mech))
- ssh_gssapi_krb5_storecreds(ctx);
-#endif /* GSI_GSS */
-/* #error "Mechanism-specific code missing in ssh_gssapi_storecreds()" */
- return;
-#endif /* HAVE_GSS_STORE_CRED */
-}
-
-void
-ssh_gssapi_do_child(Gssctxt *ctx, char ***envp, uint_t *envsizep)
-{
- /*
- * MIT/Heimdal/GSI specific code goes here.
- *
- * On Solaris there's nothing to do here as the GSS store and
- * related environment variables are to be set by PAM, if at all
- * (no environment variables are needed to address the default
- * credential store -- the euid does that).
- */
-#ifdef KRB5_GSS
-#error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()"
-#endif /* KRB5_GSS */
-#ifdef GSI_GSS
-#error "GSI krb5-specific code missing in ssh_gssapi_storecreds()"
-#endif /* GSI_GSS */
-}
-
-int
-ssh_gssapi_userok(Gssctxt *ctx, char *user)
-{
- if (ctx == NULL) {
- debug3("INTERNAL ERROR: %s", __func__);
- return (0);
- }
-
- if (user == NULL || *user == '\0')
- return (0);
-
-#ifdef HAVE___GSS_USEROK
- {
- int user_ok = 0;
-
- ctx->major = __gss_userok(&ctx->minor, ctx->src_name, user,
- &user_ok);
- if (GSS_ERROR(ctx->major)) {
- debug2("__GSS_userok() failed");
- return (0);
- }
-
- if (user_ok)
- return (1);
-
- /* fall through */
- }
-#else
-#ifdef GSSAPI_SIMPLE_USEROK
- {
- /* Mechanism-generic */
- OM_uint32 min;
- gss_buffer_desc buf, ename1, ename2;
- gss_name_t iname, cname;
- int eql;
-
- buf.value = user;
- buf.length = strlen(user);
- ctx->major = gss_import_name(&ctx->minor, &buf,
- GSS_C_NULL_OID, &iname);
- if (GSS_ERROR(ctx->major)) {
- ssh_gssapi_error(ctx,
- "importing name for authorizing initiator");
- goto failed_simple_userok;
- }
-
- ctx->major = gss_canonicalize_name(&ctx->minor, iname,
- ctx->actual_mech, &cname);
- (void) gss_release_name(&min, &iname);
- if (GSS_ERROR(ctx->major)) {
- ssh_gssapi_error(ctx, "canonicalizing name");
- goto failed_simple_userok;
- }
-
- ctx->major = gss_export_name(&ctx->minor, cname, &ename1);
- (void) gss_release_name(&min, &cname);
- if (GSS_ERROR(ctx->major)) {
- ssh_gssapi_error(ctx, "exporting name");
- goto failed_simple_userok;
- }
-
- ctx->major = gss_export_name(&ctx->minor, ctx->src_name,
- &ename2);
- if (GSS_ERROR(ctx->major)) {
- ssh_gssapi_error(ctx,
- "exporting client principal name");
- (void) gss_release_buffer(&min, &ename1);
- goto failed_simple_userok;
- }
-
- eql = (ename1.length == ename2.length &&
- memcmp(ename1.value, ename2.value, ename1.length) == 0);
-
- (void) gss_release_buffer(&min, &ename1);
- (void) gss_release_buffer(&min, &ename2);
-
- if (eql)
- return (1);
- /* fall through */
- }
-failed_simple_userok:
-#endif /* GSSAPI_SIMPLE_USEROK */
-#ifdef HAVE_GSSCRED_API
- {
- /* Mechanism-generic, Solaris-specific */
- OM_uint32 maj;
- uid_t uid;
- struct passwd *pw;
-
- maj = gsscred_name_to_unix_cred(ctx->src_name,
- ctx->actual_mech, &uid, NULL, NULL, NULL);
-
- if (GSS_ERROR(maj))
- goto failed_simple_gsscred_userok;
-
- if ((pw = getpwnam(user)) == NULL)
- goto failed_simple_gsscred_userok;
-
- if (pw->pw_uid == uid)
- return (1);
- /* fall through */
- }
-
-failed_simple_gsscred_userok:
-#endif /* HAVE_GSSCRED_API */
-#ifdef KRB5_GSS
- if (ssh_gssapi_is_krb5(ctx->mech))
- if (ssh_gssapi_krb5_userok(ctx->src_name, user))
- return (1);
-#endif /* KRB5_GSS */
-#ifdef GSI_GSS
- if (ssh_gssapi_is_gsi(ctx->mech))
- if (ssh_gssapi_gsi_userok(ctx->src_name, user))
- return (1);
-#endif /* GSI_GSS */
-#endif /* HAVE___GSS_USEROK */
-
- /* default to not authorized */
- return (0);
-}
-
-char *
-ssh_gssapi_localname(Gssctxt *ctx)
-{
- if (ctx == NULL) {
- debug3("INTERNAL ERROR: %s", __func__);
- return (NULL);
- }
-
- debug2("Mapping initiator GSS-API principal to local username");
-#ifdef HAVE_GSSCRED_API
- {
- /* Mechanism-generic, Solaris-specific */
- OM_uint32 maj;
- uid_t uid;
- struct passwd *pw;
-
- if (ctx->src_name == GSS_C_NO_NAME)
- goto failed_gsscred_localname;
-
- maj = gsscred_name_to_unix_cred(ctx->src_name,
- ctx->actual_mech, &uid, NULL, NULL, NULL);
-
- if (GSS_ERROR(maj))
- goto failed_gsscred_localname;
-
- if ((pw = getpwuid(uid)) == NULL)
- goto failed_gsscred_localname;
-
- debug2("Mapped the initiator to: %s", pw->pw_name);
- return (xstrdup(pw->pw_name));
- }
-failed_gsscred_localname:
-#endif /* HAVE_GSSCRED_API */
-#ifdef KRB5_GSS
-#error "ssh_gssapi_krb5_localname() not implemented"
- if (ssh_gssapi_is_krb5(ctx->mech))
- return (ssh_gssapi_krb5_localname(ctx->src_name));
-#endif /* KRB5_GSS */
-#ifdef GSI_GSS
-#error "ssh_gssapi_gsi_localname() not implemented"
- if (ssh_gssapi_is_gsi(ctx->mech))
- return (ssh_gssapi_gsi_localname(ctx->src_name));
-#endif /* GSI_GSS */
- return (NULL);
-}
-#endif /* GSSAPI */
diff --git a/usr/src/cmd/ssh/sshd/loginrec.c b/usr/src/cmd/ssh/sshd/loginrec.c
deleted file mode 100644
index 33998b02b9..0000000000
--- a/usr/src/cmd/ssh/sshd/loginrec.c
+++ /dev/null
@@ -1,1533 +0,0 @@
-/*
- * Copyright (c) 2000 Andre Lucas. All rights reserved.
- * Portions copyright (c) 1998 Todd C. Miller
- * Portions copyright (c) 1996 Jason Downs
- * Portions copyright (c) 1996 Theo de Raadt
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Markus Friedl.
- * 4. 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 ``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.
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/**
- ** loginrec.c: platform-independent login recording and lastlog retrieval
- **/
-
-/*
- The new login code explained
- ============================
-
- This code attempts to provide a common interface to login recording
- (utmp and friends) and last login time retrieval.
-
- Its primary means of achieving this is to use 'struct logininfo', a
- union of all the useful fields in the various different types of
- system login record structures one finds on UNIX variants.
-
- We depend on autoconf to define which recording methods are to be
- used, and which fields are contained in the relevant data structures
- on the local system. Many C preprocessor symbols affect which code
- gets compiled here.
-
- The code is designed to make it easy to modify a particular
- recording method, without affecting other methods nor requiring so
- many nested conditional compilation blocks as were commonplace in
- the old code.
-
- For login recording, we try to use the local system's libraries as
- these are clearly most likely to work correctly. For utmp systems
- this usually means login() and logout() or setutent() etc., probably
- in libutil, along with logwtmp() etc. On these systems, we fall back
- to writing the files directly if we have to, though this method
- requires very thorough testing so we do not corrupt local auditing
- information. These files and their access methods are very system
- specific indeed.
-
- For utmpx systems, the corresponding library functions are
- setutxent() etc. To the author's knowledge, all utmpx systems have
- these library functions and so no direct write is attempted. If such
- a system exists and needs support, direct analogues of the [uw]tmp
- code should suffice.
-
- Retrieving the time of last login ('lastlog') is in some ways even
- more problemmatic than login recording. Some systems provide a
- simple table of all users which we seek based on uid and retrieve a
- relatively standard structure. Others record the same information in
- a directory with a separate file, and others don't record the
- information separately at all. For systems in the latter category,
- we look backwards in the wtmp or wtmpx file for the last login entry
- for our user. Naturally this is slower and on busy systems could
- incur a significant performance penalty.
-
- Calling the new code
- --------------------
-
- In OpenSSH all login recording and retrieval is performed in
- login.c. Here you'll find working examples. Also, in the logintest.c
- program there are more examples.
-
- Internal handler calling method
- -------------------------------
-
- When a call is made to login_login() or login_logout(), both
- routines set a struct logininfo flag defining which action (log in,
- or log out) is to be taken. They both then call login_write(), which
- calls whichever of the many structure-specific handlers autoconf
- selects for the local system.
-
- The handlers themselves handle system data structure specifics. Both
- struct utmp and struct utmpx have utility functions (see
- construct_utmp*()) to try to make it simpler to add extra systems
- that introduce new features to either structure.
-
- While it may seem terribly wasteful to replicate so much similar
- code for each method, experience has shown that maintaining code to
- write both struct utmp and utmpx in one function, whilst maintaining
- support for all systems whether they have library support or not, is
- a difficult and time-consuming task.
-
- Lastlog support proceeds similarly. Functions login_get_lastlog()
- (and its OpenSSH-tuned friend login_get_lastlog_time()) call
- getlast_entry(), which tries one of three methods to find the last
- login time. It uses local system lastlog support if it can,
- otherwise it tries wtmp or wtmpx before giving up and returning 0,
- meaning "tilt".
-
- Maintenance
- -----------
-
- In many cases it's possible to tweak autoconf to select the correct
- methods for a particular platform, either by improving the detection
- code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
- symbols for the platform.
-
- Use logintest to check which symbols are defined before modifying
- configure.ac and loginrec.c. (You have to build logintest yourself
- with 'make logintest' as it's not built by default.)
-
- Otherwise, patches to the specific method(s) are very helpful!
-
-*/
-
-/**
- ** TODO:
- ** homegrown ttyslot()
- ** test, test, test
- **
- ** Platform status:
- ** ----------------
- **
- ** Known good:
- ** Linux (Redhat 6.2, Debian)
- ** Solaris
- ** HP-UX 10.20 (gcc only)
- ** IRIX
- ** NeXT - M68k/HPPA/Sparc (4.2/3.3)
- **
- ** Testing required: Please send reports!
- ** NetBSD
- ** HP-UX 11
- ** AIX
- **
- ** Platforms with known problems:
- ** Some variants of Slackware Linux
- **
- **/
-
-#include "includes.h"
-
-#include "ssh.h"
-#include "xmalloc.h"
-#include "loginrec.h"
-#include "log.h"
-#include "atomicio.h"
-
-RCSID("$Id: loginrec.c,v 1.44 2002/09/26 00:38:49 tim Exp $");
-
-#ifdef HAVE_UTIL_H
-# include <util.h>
-#endif
-
-#ifdef HAVE_LIBUTIL_H
-# include <libutil.h>
-#endif
-
-/**
- ** prototypes for helper functions in this file
- **/
-
-#if HAVE_UTMP_H
-void set_utmp_time(struct logininfo *li, struct utmp *ut);
-void construct_utmp(struct logininfo *li, struct utmp *ut);
-#endif
-
-#ifdef HAVE_UTMPX_H
-void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
-void construct_utmpx(struct logininfo *li, struct utmpx *ut);
-#endif
-
-int utmp_write_entry(struct logininfo *li);
-int utmpx_write_entry(struct logininfo *li);
-int wtmp_write_entry(struct logininfo *li);
-int wtmpx_write_entry(struct logininfo *li);
-int lastlog_write_entry(struct logininfo *li);
-int syslogin_write_entry(struct logininfo *li);
-
-int getlast_entry(struct logininfo *li);
-int lastlog_get_entry(struct logininfo *li);
-int wtmp_get_entry(struct logininfo *li);
-int wtmpx_get_entry(struct logininfo *li);
-
-/* pick the shortest string */
-#define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
-
-/**
- ** platform-independent login functions
- **/
-
-/* login_login(struct logininfo *) -Record a login
- *
- * Call with a pointer to a struct logininfo initialised with
- * login_init_entry() or login_alloc_entry()
- *
- * Returns:
- * >0 if successful
- * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
- */
-int
-login_login (struct logininfo *li)
-{
- li->type = LTYPE_LOGIN;
- return login_write(li);
-}
-
-
-/* login_logout(struct logininfo *) - Record a logout
- *
- * Call as with login_login()
- *
- * Returns:
- * >0 if successful
- * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
- */
-int
-login_logout(struct logininfo *li)
-{
- li->type = LTYPE_LOGOUT;
- return login_write(li);
-}
-
-/* login_get_lastlog_time(int) - Retrieve the last login time
- *
- * Retrieve the last login time for the given uid. Will try to use the
- * system lastlog facilities if they are available, but will fall back
- * to looking in wtmp/wtmpx if necessary
- *
- * Returns:
- * 0 on failure, or if user has never logged in
- * Time in seconds from the epoch if successful
- *
- * Useful preprocessor symbols:
- * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
- * info
- * USE_LASTLOG: If set, indicates the presence of system lastlog
- * facilities. If this and DISABLE_LASTLOG are not set,
- * try to retrieve lastlog information from wtmp/wtmpx.
- */
-#if 0
-unsigned int
-login_get_lastlog_time(const int uid)
-{
- struct logininfo li;
-
- if (login_get_lastlog(&li, uid))
- return li.tv_sec;
- else
- return 0;
-}
-#endif
-
-/* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry
- *
- * Retrieve a logininfo structure populated (only partially) with
- * information from the system lastlog data, or from wtmp/wtmpx if no
- * system lastlog information exists.
- *
- * Note this routine must be given a pre-allocated logininfo.
- *
- * Returns:
- * >0: A pointer to your struct logininfo if successful
- * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
- *
- */
-struct logininfo *
-login_get_lastlog(struct logininfo *li, const int uid)
-{
- struct passwd *pw;
-
- (void) memset(li, '\0', sizeof(*li));
- li->uid = uid;
-
- /*
- * If we don't have a 'real' lastlog, we need the username to
- * reliably search wtmp(x) for the last login (see
- * wtmp_get_entry().)
- */
- pw = getpwuid(uid);
- if (pw == NULL)
- fatal("login_get_lastlog: Cannot find account for uid %i", uid);
-
- /* No MIN_SIZEOF here - we absolutely *must not* truncate the
- * username */
- (void) strlcpy(li->username, pw->pw_name, sizeof(li->username));
-
- if (getlast_entry(li))
- return li;
- else
- return NULL;
-}
-
-
-/* login_alloc_entry() - Allocate and initialise a logininfo
- * structure
- *
- * This function creates a new struct logininfo, a data structure
- * meant to carry the information required to portably record login info.
- *
- * Returns a pointer to a newly created struct logininfo. If memory
- * allocation fails, the program halts.
- */
-struct
-logininfo *login_alloc_entry(int pid, const char *username,
- const char *hostname, const char *line,
- const char *progname)
-{
- struct logininfo *newli;
-
- newli = (struct logininfo *) xmalloc (sizeof(*newli));
- (void)login_init_entry(newli, pid, username, hostname, line, progname);
- return newli;
-}
-
-
-/* login_free_entry(struct logininfo *) - free struct memory */
-void
-login_free_entry(struct logininfo *li)
-{
- xfree(li);
-}
-
-
-/* login_init_entry()
- * - initialise a struct logininfo
- *
- * Populates a new struct logininfo, a data structure meant to carry
- * the information required to portably record login info.
- *
- * Returns: 1
- */
-int
-login_init_entry(struct logininfo *li, int pid, const char *username,
- const char *hostname, const char *line, const char *progname)
-{
- struct passwd *pw;
-
- (void) memset(li, 0, sizeof(*li));
-
- li->pid = pid;
-
- /* set the line information */
- if (line)
- (void) line_fullname(li->line, line, sizeof(li->line));
- else
- li->line_null = 1;
-
- if (progname)
- (void) strlcpy(li->progname, progname, sizeof(li->progname));
- else
- li->progname_null = 1;
-
- if (username) {
- (void) strlcpy(li->username, username, sizeof(li->username));
- pw = getpwnam(li->username);
- if (pw == NULL)
- fatal("login_init_entry: Cannot find user \"%s\"", li->username);
- li->uid = pw->pw_uid;
- }
-
- if (hostname)
- (void) strlcpy(li->hostname, hostname, sizeof(li->hostname));
-
- return 1;
-}
-
-/* login_set_current_time(struct logininfo *) - set the current time
- *
- * Set the current time in a logininfo structure. This function is
- * meant to eliminate the need to deal with system dependencies for
- * time handling.
- */
-void
-login_set_current_time(struct logininfo *li)
-{
- struct timeval tv;
-
- (void) gettimeofday(&tv, NULL);
-
- li->tv_sec = tv.tv_sec;
- li->tv_usec = tv.tv_usec;
-}
-
-/* copy a sockaddr_* into our logininfo */
-void
-login_set_addr(struct logininfo *li, const struct sockaddr *sa,
- const unsigned int sa_size)
-{
- unsigned int bufsize = sa_size;
-
- /* make sure we don't overrun our union */
- if (sizeof(li->hostaddr) < sa_size)
- bufsize = sizeof(li->hostaddr);
-
- (void) memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
-}
-
-
-/**
- ** login_write: Call low-level recording functions based on autoconf
- ** results
- **/
-int
-login_write (struct logininfo *li)
-{
-#ifndef HAVE_CYGWIN
- if ((int)geteuid() != 0) {
- log("Attempt to write login records by non-root user (aborting)");
- return 1;
- }
-#endif
-
- /* set the timestamp */
- login_set_current_time(li);
-#ifdef USE_LOGIN
- syslogin_write_entry(li);
-#endif
-#ifdef USE_LASTLOG
- if (li->type == LTYPE_LOGIN) {
- (void) lastlog_write_entry(li);
- }
-#endif
-#ifdef USE_UTMP
- utmp_write_entry(li);
-#endif
-#ifdef USE_WTMP
- wtmp_write_entry(li);
-#endif
-#ifdef USE_UTMPX
- (void) utmpx_write_entry(li);
-#endif
-#ifdef USE_WTMPX
- (void) wtmpx_write_entry(li);
-#endif
- return 0;
-}
-
-/**
- ** getlast_entry: Call low-level functions to retrieve the last login
- ** time.
- **/
-
-/* take the uid in li and return the last login time */
-int
-getlast_entry(struct logininfo *li)
-{
-#ifdef USE_LASTLOG
- return(lastlog_get_entry(li));
-#else /* !USE_LASTLOG */
-
-#ifdef DISABLE_LASTLOG
- /* On some systems we shouldn't even try to obtain last login
- * time, e.g. AIX */
- return 0;
-# else /* DISABLE_LASTLOG */
- /* Try to retrieve the last login time from wtmp */
-# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
- /* retrieve last login time from utmp */
- return (wtmp_get_entry(li));
-# else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
- /* If wtmp isn't available, try wtmpx */
-# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
- /* retrieve last login time from utmpx */
- return (wtmpx_get_entry(li));
-# else
- /* Give up: No means of retrieving last login time */
- return 0;
-# endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
-# endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
-# endif /* DISABLE_LASTLOG */
-#endif /* USE_LASTLOG */
-}
-
-
-
-/*
- * 'line' string utility functions
- *
- * These functions process the 'line' string into one of three forms:
- *
- * 1. The full filename (including '/dev')
- * 2. The stripped name (excluding '/dev')
- * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
- * /dev/pts/1 -> ts/1 )
- *
- * Form 3 is used on some systems to identify a .tmp.? entry when
- * attempting to remove it. Typically both addition and removal is
- * performed by one application - say, sshd - so as long as the choice
- * uniquely identifies a terminal it's ok.
- */
-
-
-/* line_fullname(): add the leading '/dev/' if it doesn't exist make
- * sure dst has enough space, if not just copy src (ugh) */
-char *
-line_fullname(char *dst, const char *src, int dstsize)
-{
- (void) memset(dst, '\0', dstsize);
- /* "sshd" is special, like "ftp" */
- if (strcmp(src, "sshd") ||
- ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))) {
- (void) strlcpy(dst, src, dstsize);
- } else {
- (void) strlcpy(dst, "/dev/", dstsize);
- (void) strlcat(dst, src, dstsize);
- }
- return dst;
-}
-
-/* line_stripname(): strip the leading '/dev' if it exists, return dst */
-char *
-line_stripname(char *dst, const char *src, int dstsize)
-{
- (void) memset(dst, '\0', dstsize);
- if (strncmp(src, "/dev/", 5) == 0)
- (void) strlcpy(dst, src + 5, dstsize);
- else
- (void) strlcpy(dst, src, dstsize);
- return dst;
-}
-
-/* line_abbrevname(): Return the abbreviated (usually four-character)
- * form of the line (Just use the last <dstsize> characters of the
- * full name.)
- *
- * NOTE: use strncpy because we do NOT necessarily want zero
- * termination */
-char *
-line_abbrevname(char *dst, const char *src, int dstsize)
-{
- size_t len;
-
- (void) memset(dst, '\0', dstsize);
-
- /* Always skip prefix if present */
- if (strncmp(src, "/dev/", 5) == 0)
- src += 5;
-
-#ifdef WITH_ABBREV_NO_TTY
- if (strncmp(src, "tty", 3) == 0)
- src += 3;
-#endif
-
- len = strlen(src);
-
- if (len > 0) {
- if (((int)len - dstsize) > 0)
- src += ((int)len - dstsize);
-
- /* note: _don't_ change this to strlcpy */
- (void) strncpy(dst, src, (size_t)dstsize);
- }
-
- return dst;
-}
-
-/**
- ** utmp utility functions
- **
- ** These functions manipulate struct utmp, taking system differences
- ** into account.
- **/
-
-#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
-
-/* build the utmp structure */
-void
-set_utmp_time(struct logininfo *li, struct utmp *ut)
-{
-# ifdef HAVE_TV_IN_UTMP
- ut->ut_tv.tv_sec = li->tv_sec;
- ut->ut_tv.tv_usec = li->tv_usec;
-# else
-# ifdef HAVE_TIME_IN_UTMP
- ut->ut_time = li->tv_sec;
-# endif
-# endif
-}
-
-void
-construct_utmp(struct logininfo *li,
- struct utmp *ut)
-{
- (void) memset(ut, '\0', sizeof(*ut));
-
- /* First fill out fields used for both logins and logouts */
-
-# ifdef HAVE_ID_IN_UTMP
- (void) line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
-# endif
-
-# ifdef HAVE_TYPE_IN_UTMP
- /* This is done here to keep utmp constants out of struct logininfo */
- switch (li->type) {
- case LTYPE_LOGIN:
- ut->ut_type = USER_PROCESS;
-#ifdef _UNICOS
- cray_set_tmpdir(ut);
-#endif
- break;
- case LTYPE_LOGOUT:
- ut->ut_type = DEAD_PROCESS;
-#ifdef _UNICOS
- cray_retain_utmp(ut, li->pid);
-#endif
- break;
- }
-# endif
- set_utmp_time(li, ut);
-
- (void) line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
-
-# ifdef HAVE_PID_IN_UTMP
- ut->ut_pid = li->pid;
-# endif
-
- /* If we're logging out, leave all other fields blank */
- if (li->type == LTYPE_LOGOUT)
- return;
-
- /*
- * These fields are only used when logging in, and are blank
- * for logouts.
- */
-
- /* Use strncpy because we don't necessarily want null termination */
- (void) strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));
-# ifdef HAVE_HOST_IN_UTMP
- (void) strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));
-# endif
-# ifdef HAVE_ADDR_IN_UTMP
- /* this is just a 32-bit IP address */
- if (li->hostaddr.sa.sa_family == AF_INET)
- ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
-# endif
-}
-#endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
-
-/**
- ** utmpx utility functions
- **
- ** These functions manipulate struct utmpx, accounting for system
- ** variations.
- **/
-
-#if defined(USE_UTMPX) || defined (USE_WTMPX)
-/* build the utmpx structure */
-void
-set_utmpx_time(struct logininfo *li, struct utmpx *utx)
-{
-# ifdef HAVE_TV_IN_UTMPX
- utx->ut_tv.tv_sec = li->tv_sec;
- utx->ut_tv.tv_usec = li->tv_usec;
-# else /* HAVE_TV_IN_UTMPX */
-# ifdef HAVE_TIME_IN_UTMPX
- utx->ut_time = li->tv_sec;
-# endif /* HAVE_TIME_IN_UTMPX */
-# endif /* HAVE_TV_IN_UTMPX */
-}
-
-void
-construct_utmpx(struct logininfo *li, struct utmpx *utx)
-{
- (void) memset(utx, '\0', sizeof(*utx));
-# ifdef HAVE_ID_IN_UTMPX
- (void) line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
-# endif
-
- /* this is done here to keep utmp constants out of loginrec.h */
- switch (li->type) {
- case LTYPE_LOGIN:
- utx->ut_type = USER_PROCESS;
- break;
- case LTYPE_LOGOUT:
- utx->ut_type = DEAD_PROCESS;
- break;
- }
- if (!li->line_null)
- (void) line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
- else if (!li->progname_null)
- (void) line_stripname(utx->ut_line, li->progname, sizeof(utx->ut_line));
-
- set_utmpx_time(li, utx);
- utx->ut_pid = li->pid;
- /* strncpy(): Don't necessarily want null termination */
- (void) strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
-
- if (li->type == LTYPE_LOGOUT)
- return;
-
- /*
- * These fields are only used when logging in, and are blank
- * for logouts.
- */
-
-# ifdef HAVE_HOST_IN_UTMPX
- (void) strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
-# endif
-# ifdef HAVE_ADDR_IN_UTMPX
- /* this is just a 32-bit IP address */
- if (li->hostaddr.sa.sa_family == AF_INET)
- utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
-# endif
-# ifdef HAVE_SYSLEN_IN_UTMPX
- /* ut_syslen is the length of the utx_host string */
- utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
-# endif
-}
-#endif /* USE_UTMPX || USE_WTMPX */
-
-/**
- ** Low-level utmp functions
- **/
-
-/* FIXME: (ATL) utmp_write_direct needs testing */
-#ifdef USE_UTMP
-
-/* if we can, use pututline() etc. */
-# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
- defined(HAVE_PUTUTLINE)
-# define UTMP_USE_LIBRARY
-# endif
-
-
-/* write a utmp entry with the system's help (pututline() and pals) */
-# ifdef UTMP_USE_LIBRARY
-static int
-utmp_write_library(struct logininfo *li, struct utmp *ut)
-{
- setutent();
- pututline(ut);
-
-# ifdef HAVE_ENDUTENT
- endutent();
-# endif
- return 1;
-}
-# else /* UTMP_USE_LIBRARY */
-
-/* write a utmp entry direct to the file */
-/* This is a slightly modification of code in OpenBSD's login.c */
-static int
-utmp_write_direct(struct logininfo *li, struct utmp *ut)
-{
- struct utmp old_ut;
- register int fd;
- int tty;
-
- /* FIXME: (ATL) ttyslot() needs local implementation */
-
-#if defined(HAVE_GETTTYENT)
- register struct ttyent *ty;
-
- tty=0;
-
- setttyent();
- while ((struct ttyent *)0 != (ty = getttyent())) {
- tty++;
- if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
- break;
- }
- endttyent();
-
- if((struct ttyent *)0 == ty) {
- log("utmp_write_entry: tty not found");
- return(1);
- }
-#else /* FIXME */
-
- tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
-
-#endif /* HAVE_GETTTYENT */
-
- if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
- (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
- /*
- * Prevent luser from zero'ing out ut_host.
- * If the new ut_line is empty but the old one is not
- * and ut_line and ut_name match, preserve the old ut_line.
- */
- if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
- (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
- (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
- (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
- (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
- }
-
- (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
- if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
- log("utmp_write_direct: error writing %s: %s",
- UTMP_FILE, strerror(errno));
-
- (void)close(fd);
- return 1;
- } else {
- return 0;
- }
-}
-# endif /* UTMP_USE_LIBRARY */
-
-static int
-utmp_perform_login(struct logininfo *li)
-{
- struct utmp ut;
-
- construct_utmp(li, &ut);
-# ifdef UTMP_USE_LIBRARY
- if (!utmp_write_library(li, &ut)) {
- log("utmp_perform_login: utmp_write_library() failed");
- return 0;
- }
-# else
- if (!utmp_write_direct(li, &ut)) {
- log("utmp_perform_login: utmp_write_direct() failed");
- return 0;
- }
-# endif
- return 1;
-}
-
-
-static int
-utmp_perform_logout(struct logininfo *li)
-{
- struct utmp ut;
-
- construct_utmp(li, &ut);
-# ifdef UTMP_USE_LIBRARY
- if (!utmp_write_library(li, &ut)) {
- log("utmp_perform_logout: utmp_write_library() failed");
- return 0;
- }
-# else
- if (!utmp_write_direct(li, &ut)) {
- log("utmp_perform_logout: utmp_write_direct() failed");
- return 0;
- }
-# endif
- return 1;
-}
-
-
-int
-utmp_write_entry(struct logininfo *li)
-{
- if (li->line_null) {
- debug3("not writing utmp entry");
- return 1;
- }
- debug3("writing utmp entry");
-
- switch(li->type) {
- case LTYPE_LOGIN:
- return utmp_perform_login(li);
-
- case LTYPE_LOGOUT:
- return utmp_perform_logout(li);
-
- default:
- log("utmp_write_entry: invalid type field");
- return 0;
- }
-}
-#endif /* USE_UTMP */
-
-
-/**
- ** Low-level utmpx functions
- **/
-
-/* not much point if we don't want utmpx entries */
-#ifdef USE_UTMPX
-
-/* if we have the wherewithall, use pututxline etc. */
-# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
- defined(HAVE_PUTUTXLINE)
-# define UTMPX_USE_LIBRARY
-# endif
-
-
-/* write a utmpx entry with the system's help (pututxline() and pals) */
-# ifdef UTMPX_USE_LIBRARY
-static int
-utmpx_write_library(struct logininfo *li, struct utmpx *utx)
-{
- setutxent();
- (void) pututxline(utx);
-
-# ifdef HAVE_ENDUTXENT
- endutxent();
-# endif
- return 1;
-}
-
-# else /* UTMPX_USE_LIBRARY */
-
-/* write a utmp entry direct to the file */
-static int
-utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
-{
- log("utmpx_write_direct: not implemented!");
- return 0;
-}
-# endif /* UTMPX_USE_LIBRARY */
-
-static int
-utmpx_perform_login(struct logininfo *li)
-{
- struct utmpx utx;
-
- construct_utmpx(li, &utx);
-# ifdef UTMPX_USE_LIBRARY
- if (!utmpx_write_library(li, &utx)) {
- log("tmpx_perform_login: utmp_write_library() failed");
- return 0;
- }
-# else
- if (!utmpx_write_direct(li, &ut)) {
- log("utmpx_perform_login: utmp_write_direct() failed");
- return 0;
- }
-# endif
- return 1;
-}
-
-
-static int
-utmpx_perform_logout(struct logininfo *li)
-{
- struct utmpx utx;
-
- construct_utmpx(li, &utx);
-# ifdef HAVE_ID_IN_UTMPX
- (void) line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
-# endif
-# ifdef HAVE_TYPE_IN_UTMPX
- utx.ut_type = DEAD_PROCESS;
-# endif
-
-# ifdef UTMPX_USE_LIBRARY
- (void) utmpx_write_library(li, &utx);
-# else
- utmpx_write_direct(li, &utx);
-# endif
- return 1;
-}
-
-int
-utmpx_write_entry(struct logininfo *li)
-{
- if (li->line_null) {
- debug3("not writing utmpx entry");
- return 1;
- }
- debug3("writing utmpx entry");
-
- switch(li->type) {
- case LTYPE_LOGIN:
- return utmpx_perform_login(li);
- case LTYPE_LOGOUT:
- return utmpx_perform_logout(li);
- default:
- log("utmpx_write_entry: invalid type field");
- return 0;
- }
-}
-#endif /* USE_UTMPX */
-
-
-/**
- ** Low-level wtmp functions
- **/
-
-#ifdef USE_WTMP
-
-/* write a wtmp entry direct to the end of the file */
-/* This is a slight modification of code in OpenBSD's logwtmp.c */
-static int
-wtmp_write(struct logininfo *li, struct utmp *ut)
-{
- struct stat buf;
- int fd, ret = 1;
-
- if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
- log("wtmp_write: problem writing %s: %s",
- WTMP_FILE, strerror(errno));
- return 0;
- }
- if (fstat(fd, &buf) == 0)
- if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
- (void) ftruncate(fd, buf.st_size);
- log("wtmp_write: problem writing %s: %s",
- WTMP_FILE, strerror(errno));
- ret = 0;
- }
- (void)close(fd);
- return ret;
-}
-
-static int
-wtmp_perform_login(struct logininfo *li)
-{
- struct utmp ut;
-
- construct_utmp(li, &ut);
- return wtmp_write(li, &ut);
-}
-
-
-static int
-wtmp_perform_logout(struct logininfo *li)
-{
- struct utmp ut;
-
- construct_utmp(li, &ut);
- return wtmp_write(li, &ut);
-}
-
-
-int
-wtmp_write_entry(struct logininfo *li)
-{
- switch(li->type) {
- case LTYPE_LOGIN:
- return wtmp_perform_login(li);
- case LTYPE_LOGOUT:
- return wtmp_perform_logout(li);
- default:
- log("wtmp_write_entry: invalid type field");
- return 0;
- }
-}
-
-
-/* Notes on fetching login data from wtmp/wtmpx
- *
- * Logouts are usually recorded with (amongst other things) a blank
- * username on a given tty line. However, some systems (HP-UX is one)
- * leave all fields set, but change the ut_type field to DEAD_PROCESS.
- *
- * Since we're only looking for logins here, we know that the username
- * must be set correctly. On systems that leave it in, we check for
- * ut_type==USER_PROCESS (indicating a login.)
- *
- * Portability: Some systems may set something other than USER_PROCESS
- * to indicate a login process. I don't know of any as I write. Also,
- * it's possible that some systems may both leave the username in
- * place and not have ut_type.
- */
-
-/* return true if this wtmp entry indicates a login */
-static int
-wtmp_islogin(struct logininfo *li, struct utmp *ut)
-{
- if (strncmp(li->username, ut->ut_name,
- MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
-# ifdef HAVE_TYPE_IN_UTMP
- if (ut->ut_type & USER_PROCESS)
- return 1;
-# else
- return 1;
-# endif
- }
- return 0;
-}
-
-int
-wtmp_get_entry(struct logininfo *li)
-{
- struct stat st;
- struct utmp ut;
- int fd, found=0;
-
- /* Clear the time entries in our logininfo */
- li->tv_sec = li->tv_usec = 0;
-
- if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
- log("wtmp_get_entry: problem opening %s: %s",
- WTMP_FILE, strerror(errno));
- return 0;
- }
- if (fstat(fd, &st) != 0) {
- log("wtmp_get_entry: couldn't stat %s: %s",
- WTMP_FILE, strerror(errno));
- (void) close(fd);
- return 0;
- }
-
- /* Seek to the start of the last struct utmp */
- if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
- /* Looks like we've got a fresh wtmp file */
- (void) close(fd);
- return 0;
- }
-
- while (!found) {
- if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
- log("wtmp_get_entry: read of %s failed: %s",
- WTMP_FILE, strerror(errno));
- (void) close (fd);
- return 0;
- }
- if ( wtmp_islogin(li, &ut) ) {
- found = 1;
- /* We've already checked for a time in struct
- * utmp, in login_getlast(). */
-# ifdef HAVE_TIME_IN_UTMP
- li->tv_sec = ut.ut_time;
-# else
-# if HAVE_TV_IN_UTMP
- li->tv_sec = ut.ut_tv.tv_sec;
-# endif
-# endif
- (void) line_fullname(li->line, ut.ut_line,
- MIN_SIZEOF(li->line, ut.ut_line));
-# ifdef HAVE_HOST_IN_UTMP
- (void) strlcpy(li->hostname, ut.ut_host,
- MIN_SIZEOF(li->hostname, ut.ut_host));
-# endif
- continue;
- }
- /* Seek back 2 x struct utmp */
- if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
- /* We've found the start of the file, so quit */
- (void) close (fd);
- return 0;
- }
- }
-
- /* We found an entry. Tidy up and return */
- (void) close(fd);
- return 1;
-}
-# endif /* USE_WTMP */
-
-
-/**
- ** Low-level wtmpx functions
- **/
-
-#ifdef USE_WTMPX
-/* write a wtmpx entry direct to the end of the file */
-/* This is a slight modification of code in OpenBSD's logwtmp.c */
-static int
-wtmpx_write(struct logininfo *li, struct utmpx *utx)
-{
- struct stat buf;
- int fd, ret = 1;
-
- if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
- log("wtmpx_write: problem opening %s: %s",
- WTMPX_FILE, strerror(errno));
- return 0;
- }
-
- if (fstat(fd, &buf) == 0)
- if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
- (void) ftruncate(fd, buf.st_size);
- log("wtmpx_write: problem writing %s: %s",
- WTMPX_FILE, strerror(errno));
- ret = 0;
- }
- (void)close(fd);
-
- return ret;
-}
-
-
-static int
-wtmpx_perform_login(struct logininfo *li)
-{
- struct utmpx utx;
-
- construct_utmpx(li, &utx);
- return wtmpx_write(li, &utx);
-}
-
-
-static int
-wtmpx_perform_logout(struct logininfo *li)
-{
- struct utmpx utx;
-
- construct_utmpx(li, &utx);
- return wtmpx_write(li, &utx);
-}
-
-
-int
-wtmpx_write_entry(struct logininfo *li)
-{
- switch(li->type) {
- case LTYPE_LOGIN:
- return wtmpx_perform_login(li);
- case LTYPE_LOGOUT:
- return wtmpx_perform_logout(li);
- default:
- log("wtmpx_write_entry: invalid type field");
- return 0;
- }
-}
-
-/* Please see the notes above wtmp_islogin() for information about the
- next two functions */
-
-/* Return true if this wtmpx entry indicates a login */
-static int
-wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
-{
- if ( strncmp(li->username, utx->ut_name,
- MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
-# ifdef HAVE_TYPE_IN_UTMPX
- if (utx->ut_type == USER_PROCESS)
- return 1;
-# else
- return 1;
-# endif
- }
- return 0;
-}
-
-
-#if 0
-int
-wtmpx_get_entry(struct logininfo *li)
-{
- struct stat st;
- struct utmpx utx;
- int fd, found=0;
-
- /* Clear the time entries */
- li->tv_sec = li->tv_usec = 0;
-
- if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
- log("wtmpx_get_entry: problem opening %s: %s",
- WTMPX_FILE, strerror(errno));
- return 0;
- }
- if (fstat(fd, &st) != 0) {
- log("wtmpx_get_entry: couldn't stat %s: %s",
- WTMPX_FILE, strerror(errno));
- (void) close(fd);
- return 0;
- }
-
- /* Seek to the start of the last struct utmpx */
- if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
- /* probably a newly rotated wtmpx file */
- (void) close(fd);
- return 0;
- }
-
- while (!found) {
- if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
- log("wtmpx_get_entry: read of %s failed: %s",
- WTMPX_FILE, strerror(errno));
- (void) close (fd);
- return 0;
- }
- /* Logouts are recorded as a blank username on a particular line.
- * So, we just need to find the username in struct utmpx */
- if ( wtmpx_islogin(li, &utx) ) {
- found = 1;
-# ifdef HAVE_TV_IN_UTMPX
- li->tv_sec = utx.ut_tv.tv_sec;
-# else
-# ifdef HAVE_TIME_IN_UTMPX
- li->tv_sec = utx.ut_time;
-# endif
-# endif
- (void) line_fullname(li->line, utx.ut_line, sizeof(li->line));
-# ifdef HAVE_HOST_IN_UTMPX
- (void) strlcpy(li->hostname, utx.ut_host,
- MIN_SIZEOF(li->hostname, utx.ut_host));
-# endif
- continue;
- }
- if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
- (void) close (fd);
- return 0;
- }
- }
-
- (void) close(fd);
- return 1;
-}
-#endif
-#endif /* USE_WTMPX */
-
-/**
- ** Low-level libutil login() functions
- **/
-
-#ifdef USE_LOGIN
-static int
-syslogin_perform_login(struct logininfo *li)
-{
- struct utmp *ut;
-
- if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) {
- log("syslogin_perform_login: couldn't malloc()");
- return 0;
- }
- construct_utmp(li, ut);
- login(ut);
-
- return 1;
-}
-
-static int
-syslogin_perform_logout(struct logininfo *li)
-{
-# ifdef HAVE_LOGOUT
- char line[8];
-
- (void)line_stripname(line, li->line, sizeof(line));
-
- if (!logout(line)) {
- log("syslogin_perform_logout: logout() returned an error");
-# ifdef HAVE_LOGWTMP
- } else {
- logwtmp(line, "", "");
-# endif
- }
- /* FIXME: (ATL - if the need arises) What to do if we have
- * login, but no logout? what if logout but no logwtmp? All
- * routines are in libutil so they should all be there,
- * but... */
-# endif
- return 1;
-}
-
-int
-syslogin_write_entry(struct logininfo *li)
-{
- switch (li->type) {
- case LTYPE_LOGIN:
- return syslogin_perform_login(li);
- case LTYPE_LOGOUT:
- return syslogin_perform_logout(li);
- default:
- log("syslogin_write_entry: Invalid type field");
- return 0;
- }
-}
-#endif /* USE_LOGIN */
-
-/* end of file log-syslogin.c */
-
-/**
- ** Low-level lastlog functions
- **/
-
-#ifdef USE_LASTLOG
-#define LL_FILE 1
-#define LL_DIR 2
-#define LL_OTHER 3
-
-static void
-lastlog_construct(struct logininfo *li, struct lastlog *last)
-{
- /* clear the structure */
- (void) memset(last, '\0', sizeof(*last));
-
- (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
- (void) strlcpy(last->ll_host, li->hostname,
- MIN_SIZEOF(last->ll_host, li->hostname));
- last->ll_time = li->tv_sec;
-}
-
-static int
-lastlog_filetype(char *filename)
-{
- struct stat st;
-
- if (stat(LASTLOG_FILE, &st) != 0) {
- log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
- strerror(errno));
- return 0;
- }
- if (S_ISDIR(st.st_mode))
- return LL_DIR;
- else if (S_ISREG(st.st_mode))
- return LL_FILE;
- else
- return LL_OTHER;
-}
-
-
-/* open the file (using filemode) and seek to the login entry */
-static int
-lastlog_openseek(struct logininfo *li, int *fd, int filemode)
-{
- off_t offset;
- int type;
- char lastlog_file[1024];
-
- type = lastlog_filetype(LASTLOG_FILE);
- switch (type) {
- case LL_FILE:
- (void) strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
- break;
- case LL_DIR:
- (void) snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
- LASTLOG_FILE, li->username);
- break;
- default:
- log("lastlog_openseek: %.100s is not a file or directory!",
- LASTLOG_FILE);
- return 0;
- }
-
- *fd = open(lastlog_file, filemode);
- if ( *fd < 0) {
- debug("lastlog_openseek: Couldn't open %s: %s",
- lastlog_file, strerror(errno));
- return 0;
- }
-
- if (type == LL_FILE) {
- /* find this uid's offset in the lastlog file */
- offset = (off_t) ((long)li->uid * sizeof(struct lastlog));
-
- if ( lseek(*fd, offset, SEEK_SET) != offset ) {
- log("lastlog_openseek: %s->lseek(): %s",
- lastlog_file, strerror(errno));
- return 0;
- }
- }
-
- return 1;
-}
-
-static int
-lastlog_perform_login(struct logininfo *li)
-{
- struct lastlog last;
- int fd;
-
- /* create our struct lastlog */
- lastlog_construct(li, &last);
-
- if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
- return(0);
-
- /* write the entry */
- if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
- (void) close(fd);
- log("lastlog_write_filemode: Error writing to %s: %s",
- LASTLOG_FILE, strerror(errno));
- return 0;
- }
-
- (void) close(fd);
- return 1;
-}
-
-int
-lastlog_write_entry(struct logininfo *li)
-{
- switch(li->type) {
- case LTYPE_LOGIN:
- return lastlog_perform_login(li);
- default:
- log("lastlog_write_entry: Invalid type field");
- return 0;
- }
-}
-
-static void
-lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
-{
- (void) line_fullname(li->line, last->ll_line, sizeof(li->line));
- (void) strlcpy(li->hostname, last->ll_host,
- MIN_SIZEOF(li->hostname, last->ll_host));
- li->tv_sec = last->ll_time;
-}
-
-int
-lastlog_get_entry(struct logininfo *li)
-{
- struct lastlog last;
- int fd, ret;
-
- if (!lastlog_openseek(li, &fd, O_RDONLY))
- return (0);
-
- ret = atomicio(read, fd, &last, sizeof(last));
- close(fd);
-
- switch (ret) {
- case 0:
- memset(&last, '\0', sizeof(last));
- /* FALLTHRU */
- case sizeof(last):
- lastlog_populate_entry(li, &last);
- return (1);
- case -1:
- error("%s: Error reading from %s: %s", __func__,
- LASTLOG_FILE, strerror(errno));
- return (0);
- default:
- error("%s: Error reading from %s: Expecting %d, got %d",
- __func__, LASTLOG_FILE, (int)sizeof(last), ret);
- return (0);
- }
-
- /* NOTREACHED */
- return (0);
-}
-#endif /* USE_LASTLOG */
diff --git a/usr/src/cmd/ssh/sshd/mapfile-intf b/usr/src/cmd/ssh/sshd/mapfile-intf
deleted file mode 100644
index 6981212730..0000000000
--- a/usr/src/cmd/ssh/sshd/mapfile-intf
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
-#
-# sshd defines its own log(), as do various other ssh utilities, thus their
-# symbols are reduced to locals via MAPFILE.NGB in Makefile-ssh.common. sshd
-# must export some symbols too, thus this mapfile augments the former.
-
-#
-# MAPFILE HEADER START
-#
-# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
-# Object versioning must comply with the rules detailed in
-#
-# usr/src/lib/README.mapfiles
-#
-# You should not be making modifications here until you've read the most current
-# copy of that file. If you need help, contact a gatekeeper for guidance.
-#
-# MAPFILE HEADER END
-#
-
-$mapfile_version 2
-
-SYMBOL_SCOPE {
- global:
- allow_severity; # required by libwrap
- deny_severity; # required by libwrap
-};
diff --git a/usr/src/cmd/ssh/sshd/servconf.c b/usr/src/cmd/ssh/sshd/servconf.c
deleted file mode 100644
index 516466bbc1..0000000000
--- a/usr/src/cmd/ssh/sshd/servconf.c
+++ /dev/null
@@ -1,1494 +0,0 @@
-/*
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Joyent, Inc. All rights reserved.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.115 2002/09/04 18:52:42 stevesk Exp $");
-
-#ifdef HAVE_DEFOPEN
-#include <deflt.h>
-#endif /* HAVE_DEFOPEN */
-
-#if defined(KRB4)
-#include <krb.h>
-#endif
-#if defined(KRB5)
-#ifdef HEIMDAL
-#include <krb.h>
-#else
-/* Bodge - but then, so is using the kerberos IV KEYFILE to get a Kerberos V
- * keytab */
-#define KEYFILE "/etc/krb5.keytab"
-#endif
-#endif
-#ifdef AFS
-#include <kafs.h>
-#endif
-
-#include "ssh.h"
-#include "log.h"
-#include "buffer.h"
-#include "servconf.h"
-#include "xmalloc.h"
-#include "compat.h"
-#include "pathnames.h"
-#include "tildexpand.h"
-#include "misc.h"
-#include "cipher.h"
-#include "kex.h"
-#include "mac.h"
-#include "auth.h"
-#include "match.h"
-#include "groupaccess.h"
-
-static void add_listen_addr(ServerOptions *, char *, u_short);
-static void add_one_listen_addr(ServerOptions *, char *, u_short);
-
-extern Buffer cfg;
-
-/* AF_UNSPEC or AF_INET or AF_INET6 */
-extern int IPv4or6;
-
-/*
- * Initializes the server options to their initial (unset) values. Some of those
- * that stay unset after the command line options and configuration files are
- * read are set to their default values in fill_default_server_options().
- */
-void
-initialize_server_options(ServerOptions *options)
-{
- (void) memset(options, 0, sizeof(*options));
-
- /* Standard Options */
- options->num_ports = 0;
- options->ports_from_cmdline = 0;
- options->listen_addrs = NULL;
- options->num_host_key_files = 0;
- options->pid_file = NULL;
- options->server_key_bits = -1;
- options->login_grace_time = -1;
- options->key_regeneration_time = -1;
- options->permit_root_login = PERMIT_NOT_SET;
- options->ignore_rhosts = -1;
- options->ignore_user_known_hosts = -1;
- options->print_motd = -1;
- options->print_lastlog = -1;
- options->x11_forwarding = -1;
- options->x11_display_offset = -1;
- options->x11_use_localhost = -1;
- options->xauth_location = NULL;
- options->strict_modes = -1;
- options->keepalives = -1;
- options->log_facility = SYSLOG_FACILITY_NOT_SET;
- options->log_level = SYSLOG_LEVEL_NOT_SET;
- options->rhosts_authentication = -1;
- options->rhosts_rsa_authentication = -1;
- options->hostbased_authentication = -1;
- options->hostbased_uses_name_from_packet_only = -1;
- options->rsa_authentication = -1;
- options->pubkey_authentication = -1;
-#ifdef GSSAPI
- options->gss_authentication = -1;
- options->gss_keyex = -1;
- options->gss_store_creds = -1;
- options->gss_use_session_ccache = -1;
- options->gss_cleanup_creds = -1;
-#endif
-#if defined(KRB4) || defined(KRB5)
- options->kerberos_authentication = -1;
- options->kerberos_or_local_passwd = -1;
- options->kerberos_ticket_cleanup = -1;
-#endif
-#if defined(AFS) || defined(KRB5)
- options->kerberos_tgt_passing = -1;
-#endif
-#ifdef AFS
- options->afs_token_passing = -1;
-#endif
- options->password_authentication = -1;
- options->kbd_interactive_authentication = -1;
- options->challenge_response_authentication = -1;
- options->pam_authentication_via_kbd_int = -1;
- options->permit_empty_passwd = -1;
- options->permit_user_env = -1;
- options->compression = -1;
- options->allow_tcp_forwarding = -1;
- options->num_allow_users = 0;
- options->num_deny_users = 0;
- options->num_allow_groups = 0;
- options->num_deny_groups = 0;
- options->ciphers = NULL;
- options->macs = NULL;
- options->protocol = SSH_PROTO_UNKNOWN;
- options->gateway_ports = -1;
- options->num_subsystems = 0;
- options->max_startups_begin = -1;
- options->max_startups_rate = -1;
- options->max_startups = -1;
- options->banner = NULL;
- options->verify_reverse_mapping = -1;
- options->client_alive_interval = -1;
- options->client_alive_count_max = -1;
- options->authorized_keys_file = NULL;
- options->authorized_keys_file2 = NULL;
-
- options->max_auth_tries = -1;
- options->max_auth_tries_log = -1;
-
- options->max_init_auth_tries = -1;
- options->max_init_auth_tries_log = -1;
-
- options->lookup_client_hostnames = -1;
- options->use_openssl_engine = -1;
- options->chroot_directory = NULL;
- options->pre_userauth_hook = NULL;
- options->pam_service_name = NULL;
- options->pam_service_prefix = NULL;
-}
-
-#ifdef HAVE_DEFOPEN
-/*
- * Reads /etc/default/login and defaults several ServerOptions:
- *
- * PermitRootLogin
- * PermitEmptyPasswords
- * LoginGraceTime
- *
- * CONSOLE=* -> PermitRootLogin=without-password
- * #CONSOLE=* -> PermitRootLogin=yes
- *
- * PASSREQ=YES -> PermitEmptyPasswords=no
- * PASSREQ=NO -> PermitEmptyPasswords=yes
- * #PASSREQ=* -> PermitEmptyPasswords=no
- *
- * TIMEOUT=<secs> -> LoginGraceTime=<secs>
- * #TIMEOUT=<secs> -> LoginGraceTime=300
- */
-static
-void
-deflt_fill_default_server_options(ServerOptions *options)
-{
- int flags;
- char *ptr;
-
- if (defopen(_PATH_DEFAULT_LOGIN))
- return;
-
- /* Ignore case */
- flags = defcntl(DC_GETFLAGS, 0);
- TURNOFF(flags, DC_CASE);
- (void) defcntl(DC_SETFLAGS, flags);
-
- if (options->permit_root_login == PERMIT_NOT_SET &&
- (ptr = defread("CONSOLE=")) != NULL)
- options->permit_root_login = PERMIT_NO_PASSWD;
-
- if (options->permit_empty_passwd == -1 &&
- (ptr = defread("PASSREQ=")) != NULL) {
- if (strcasecmp("YES", ptr) == 0)
- options->permit_empty_passwd = 0;
- else if (strcasecmp("NO", ptr) == 0)
- options->permit_empty_passwd = 1;
- }
-
- if (options->max_init_auth_tries == -1 &&
- (ptr = defread("RETRIES=")) != NULL) {
- options->max_init_auth_tries = atoi(ptr);
- }
-
- if (options->max_init_auth_tries_log == -1 &&
- (ptr = defread("SYSLOG_FAILED_LOGINS=")) != NULL) {
- options->max_init_auth_tries_log = atoi(ptr);
- }
-
- if (options->login_grace_time == -1) {
- if ((ptr = defread("TIMEOUT=")) != NULL)
- options->login_grace_time = (unsigned)atoi(ptr);
- else
- options->login_grace_time = 300;
- }
-
- (void) defopen((char *)NULL);
-}
-#endif /* HAVE_DEFOPEN */
-
-void
-fill_default_server_options(ServerOptions *options)
-{
-
-#ifdef HAVE_DEFOPEN
- deflt_fill_default_server_options(options);
-#endif /* HAVE_DEFOPEN */
-
- /* Standard Options */
- if (options->protocol == SSH_PROTO_UNKNOWN)
- options->protocol = SSH_PROTO_1|SSH_PROTO_2;
- if (options->num_host_key_files == 0) {
- /* fill default hostkeys for protocols */
- if (options->protocol & SSH_PROTO_1)
- options->host_key_files[options->num_host_key_files++] =
- _PATH_HOST_KEY_FILE;
-#ifndef GSSAPI
- /* With GSS keyex we can run v2 w/ no host keys */
- if (options->protocol & SSH_PROTO_2) {
- options->host_key_files[options->num_host_key_files++] =
- _PATH_HOST_RSA_KEY_FILE;
- options->host_key_files[options->num_host_key_files++] =
- _PATH_HOST_DSA_KEY_FILE;
- }
-#endif /* GSSAPI */
- }
- if (options->num_ports == 0)
- options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
- if (options->listen_addrs == NULL)
- add_listen_addr(options, NULL, 0);
- if (options->pid_file == NULL)
- options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
- if (options->server_key_bits == -1)
- options->server_key_bits = 768;
- if (options->login_grace_time == -1)
- options->login_grace_time = 120;
- if (options->key_regeneration_time == -1)
- options->key_regeneration_time = 3600;
- if (options->permit_root_login == PERMIT_NOT_SET)
- options->permit_root_login = PERMIT_YES;
- if (options->ignore_rhosts == -1)
- options->ignore_rhosts = 1;
- if (options->ignore_user_known_hosts == -1)
- options->ignore_user_known_hosts = 0;
- if (options->print_motd == -1)
- options->print_motd = 1;
- if (options->print_lastlog == -1)
- options->print_lastlog = 1;
- if (options->x11_forwarding == -1)
- options->x11_forwarding = 1;
- if (options->x11_display_offset == -1)
- options->x11_display_offset = 10;
- if (options->x11_use_localhost == -1)
- options->x11_use_localhost = 1;
- if (options->xauth_location == NULL)
- options->xauth_location = _PATH_XAUTH;
- if (options->strict_modes == -1)
- options->strict_modes = 1;
- if (options->keepalives == -1)
- options->keepalives = 1;
- if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
- options->log_facility = SYSLOG_FACILITY_AUTH;
- if (options->log_level == SYSLOG_LEVEL_NOT_SET)
- options->log_level = SYSLOG_LEVEL_INFO;
- if (options->rhosts_authentication == -1)
- options->rhosts_authentication = 0;
- if (options->rhosts_rsa_authentication == -1)
- options->rhosts_rsa_authentication = 0;
- if (options->hostbased_authentication == -1)
- options->hostbased_authentication = 0;
- if (options->hostbased_uses_name_from_packet_only == -1)
- options->hostbased_uses_name_from_packet_only = 0;
- if (options->rsa_authentication == -1)
- options->rsa_authentication = 1;
- if (options->pubkey_authentication == -1)
- options->pubkey_authentication = 1;
-#ifdef GSSAPI
- if (options->gss_authentication == -1)
- options->gss_authentication = 1;
- if (options->gss_keyex == -1)
- options->gss_keyex = 1;
- if (options->gss_store_creds == -1)
- options->gss_store_creds = 1;
- if (options->gss_use_session_ccache == -1)
- options->gss_use_session_ccache = 1;
- if (options->gss_cleanup_creds == -1)
- options->gss_cleanup_creds = 1;
-#endif
-#if defined(KRB4) || defined(KRB5)
- if (options->kerberos_authentication == -1)
- options->kerberos_authentication = 0;
- if (options->kerberos_or_local_passwd == -1)
- options->kerberos_or_local_passwd = 1;
- if (options->kerberos_ticket_cleanup == -1)
- options->kerberos_ticket_cleanup = 1;
-#endif
-#if defined(AFS) || defined(KRB5)
- if (options->kerberos_tgt_passing == -1)
- options->kerberos_tgt_passing = 0;
-#endif
-#ifdef AFS
- if (options->afs_token_passing == -1)
- options->afs_token_passing = 0;
-#endif
- if (options->password_authentication == -1)
- options->password_authentication = 1;
- /*
- * options->pam_authentication_via_kbd_int has intentionally no default
- * value since we do not need it.
- */
- if (options->kbd_interactive_authentication == -1)
- options->kbd_interactive_authentication = 1;
- if (options->challenge_response_authentication == -1)
- options->challenge_response_authentication = 1;
- if (options->permit_empty_passwd == -1)
- options->permit_empty_passwd = 0;
- if (options->permit_user_env == -1)
- options->permit_user_env = 0;
- if (options->compression == -1)
- options->compression = 1;
- if (options->allow_tcp_forwarding == -1)
- options->allow_tcp_forwarding = 1;
- if (options->gateway_ports == -1)
- options->gateway_ports = 0;
- if (options->max_startups == -1)
- options->max_startups = 10;
- if (options->max_startups_rate == -1)
- options->max_startups_rate = 100; /* 100% */
- if (options->max_startups_begin == -1)
- options->max_startups_begin = options->max_startups;
- if (options->verify_reverse_mapping == -1)
- options->verify_reverse_mapping = 0;
- if (options->client_alive_interval == -1)
- options->client_alive_interval = 0;
- if (options->client_alive_count_max == -1)
- options->client_alive_count_max = 3;
- if (options->authorized_keys_file2 == NULL) {
- /* authorized_keys_file2 falls back to authorized_keys_file */
- if (options->authorized_keys_file != NULL)
- options->authorized_keys_file2 = options->authorized_keys_file;
- else
- options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
- }
- if (options->authorized_keys_file == NULL)
- options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
-
- if (options->max_auth_tries == -1)
- options->max_auth_tries = AUTH_FAIL_MAX;
- if (options->max_auth_tries_log == -1)
- options->max_auth_tries_log = options->max_auth_tries / 2;
-
- if (options->max_init_auth_tries == -1)
- options->max_init_auth_tries = AUTH_FAIL_MAX;
- if (options->max_init_auth_tries_log == -1)
- options->max_init_auth_tries_log = options->max_init_auth_tries / 2;
-
- if (options->lookup_client_hostnames == -1)
- options->lookup_client_hostnames = 1;
- if (options->use_openssl_engine == -1)
- options->use_openssl_engine = 1;
- if (options->pam_service_prefix == NULL)
- options->pam_service_prefix = _SSH_PAM_SERVICE_PREFIX;
- if (options->pam_service_name == NULL)
- options->pam_service_name = NULL;
-}
-
-/* Keyword tokens. */
-typedef enum {
- sBadOption, /* == unknown option */
- /* Portable-specific options */
- sPAMAuthenticationViaKbdInt,
- /* Standard Options */
- sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
- sPermitRootLogin, sLogFacility, sLogLevel,
- sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
-#ifdef GSSAPI
- sGssAuthentication, sGssKeyEx, sGssStoreDelegCreds,
- sGssUseSessionCredCache, sGssCleanupCreds,
-#endif /* GSSAPI */
-#if defined(KRB4) || defined(KRB5)
- sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
-#endif
-#if defined(AFS) || defined(KRB5)
- sKerberosTgtPassing,
-#endif
-#ifdef AFS
- sAFSTokenPassing,
-#endif
- sChallengeResponseAuthentication,
- sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
- sPrintMotd, sPrintLastLog, sIgnoreRhosts,
- sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
- sStrictModes, sEmptyPasswd, sKeepAlives,
- sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
- sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
- sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
- sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
- sBanner, sVerifyReverseMapping, sHostbasedAuthentication,
- sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
- sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
- sMaxAuthTries, sMaxAuthTriesLog, sUsePrivilegeSeparation,
- sLookupClientHostnames, sUseOpenSSLEngine, sChrootDirectory,
- sPreUserauthHook, sMatch, sPAMServicePrefix, sPAMServiceName,
- sDeprecated
-} ServerOpCodes;
-
-#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */
-#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
-#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
-
-/* Textual representation of the tokens. */
-static struct {
- const char *name;
- ServerOpCodes opcode;
- u_int flags;
-} keywords[] = {
- /* Portable-specific options */
- { "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt, SSHCFG_GLOBAL },
- /* Standard Options */
- { "port", sPort, SSHCFG_GLOBAL },
- { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
- { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
- { "pidfile", sPidFile, SSHCFG_GLOBAL },
- { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
- { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
- { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
- { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
- { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
- { "loglevel", sLogLevel, SSHCFG_GLOBAL },
- { "rhostsauthentication", sRhostsAuthentication, SSHCFG_GLOBAL },
- { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
- { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
- { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
- { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
- { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
- { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
-#ifdef GSSAPI
- { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
- { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
- { "gssapistoredelegatedcredentials", sGssStoreDelegCreds, SSHCFG_GLOBAL },
- { "gssauthentication", sGssAuthentication, SSHCFG_GLOBAL }, /* alias */
- { "gsskeyex", sGssKeyEx, SSHCFG_GLOBAL }, /* alias */
- { "gssstoredelegcreds", sGssStoreDelegCreds, SSHCFG_GLOBAL }, /* alias */
-#ifndef SUNW_GSSAPI
- { "gssusesessionccache", sGssUseSessionCredCache, SSHCFG_GLOBAL },
- { "gssusesessioncredcache", sGssUseSessionCredCache, SSHCFG_GLOBAL },
- { "gsscleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
-#endif /* SUNW_GSSAPI */
-#endif
-#if defined(KRB4) || defined(KRB5)
- { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
- { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
- { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
-#endif
-#if defined(AFS) || defined(KRB5)
- { "kerberostgtpassing", sKerberosTgtPassing, SSHCFG_GLOBAL },
-#endif
-#ifdef AFS
- { "afstokenpassing", sAFSTokenPassing, SSHCFG_GLOBAL },
-#endif
- { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
- { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
- { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
- { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
- { "checkmail", sDeprecated, SSHCFG_GLOBAL },
- { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
- { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
- { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
- { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
- { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
- { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
- { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
- { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
- { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
- { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
- { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
- { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
- { "uselogin", sUseLogin, SSHCFG_GLOBAL },
- { "compression", sCompression, SSHCFG_GLOBAL },
- { "tcpkeepalive", sKeepAlives, SSHCFG_GLOBAL },
- { "keepalive", sKeepAlives, SSHCFG_GLOBAL }, /* obsolete */
- { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
- { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
- { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
- { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
- { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
- { "ciphers", sCiphers, SSHCFG_GLOBAL },
- { "macs", sMacs, SSHCFG_GLOBAL},
- { "protocol", sProtocol,SSHCFG_GLOBAL },
- { "gatewayports", sGatewayPorts, SSHCFG_ALL },
- { "subsystem", sSubsystem, SSHCFG_GLOBAL},
- { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
- { "banner", sBanner, SSHCFG_ALL },
- { "verifyreversemapping", sVerifyReverseMapping, SSHCFG_GLOBAL },
- { "reversemappingcheck", sVerifyReverseMapping,SSHCFG_GLOBAL },
- { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
- { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
- { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
- { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
- { "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
- { "maxauthtrieslog", sMaxAuthTriesLog, SSHCFG_GLOBAL },
- { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
- { "lookupclienthostnames", sLookupClientHostnames, SSHCFG_GLOBAL },
- { "useopensslengine", sUseOpenSSLEngine, SSHCFG_GLOBAL },
- { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
- { "preuserauthhook", sPreUserauthHook, SSHCFG_ALL},
- { "match", sMatch, SSHCFG_ALL },
- { "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL },
- { "pamservicename", sPAMServiceName, SSHCFG_GLOBAL },
-
- { NULL, sBadOption, 0 }
-};
-
-/*
- * Returns the number of the token pointed to by cp or sBadOption.
- */
-
-static ServerOpCodes
-parse_token(const char *cp, const char *filename,
- int linenum, u_int *flags)
-{
- u_int i;
-
- for (i = 0; keywords[i].name; i++)
- if (strcasecmp(cp, keywords[i].name) == 0) {
- *flags = keywords[i].flags;
- return keywords[i].opcode;
- }
-
- error("%s: line %d: Bad configuration option: %s",
- filename, linenum, cp);
- return sBadOption;
-}
-
-static void
-add_listen_addr(ServerOptions *options, char *addr, u_short port)
-{
- int i;
-
- if (options->num_ports == 0)
- options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
- if (port == 0)
- for (i = 0; i < options->num_ports; i++)
- add_one_listen_addr(options, addr, options->ports[i]);
- else
- add_one_listen_addr(options, addr, port);
-}
-
-static void
-add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
-{
- struct addrinfo hints, *ai, *aitop;
- char strport[NI_MAXSERV];
- int gaierr;
-
- (void) memset(&hints, 0, sizeof(hints));
- hints.ai_family = IPv4or6;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
- (void) snprintf(strport, sizeof strport, "%u", port);
- if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
- fatal("bad addr or host: %s (%s)",
- addr ? addr : "<NULL>",
- gai_strerror(gaierr));
- for (ai = aitop; ai->ai_next; ai = ai->ai_next)
- ;
- ai->ai_next = options->listen_addrs;
- options->listen_addrs = aitop;
-}
-
-/*
- * The strategy for the Match blocks is that the config file is parsed twice.
- *
- * The first time is at startup. activep is initialized to 1 and the
- * directives in the global context are processed and acted on. Hitting a
- * Match directive unsets activep and the directives inside the block are
- * checked for syntax only.
- *
- * The second time is after a connection has been established but before
- * authentication. activep is initialized to 2 and global config directives
- * are ignored since they have already been processed. If the criteria in a
- * Match block is met, activep is set and the subsequent directives
- * processed and actioned until EOF or another Match block unsets it. Any
- * options set are copied into the main server config.
- *
- * Potential additions/improvements:
- * - Add Match support for pre-kex directives, eg Protocol, Ciphers.
- *
- * - Add a Tag directive (idea from David Leonard) ala pf, eg:
- * Match Address 192.168.0.*
- * Tag trusted
- * Match Group wheel
- * Tag trusted
- * Match Tag trusted
- * AllowTcpForwarding yes
- * GatewayPorts clientspecified
- * [...]
- *
- * - Add a PermittedChannelRequests directive
- * Match Group shell
- * PermittedChannelRequests session,forwarded-tcpip
- */
-
-static int
-match_cfg_line_group(const char *grps, int line, const char *user)
-{
- int result = 0;
- struct passwd *pw;
-
- if (user == NULL)
- goto out;
-
- if ((pw = getpwnam(user)) == NULL) {
- debug("Can't match group at line %d because user %.100s does "
- "not exist", line, user);
- } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
- debug("Can't Match group because user %.100s not in any group "
- "at line %d", user, line);
- } else if (ga_match_pattern_list(grps) != 1) {
- debug("user %.100s does not match group list %.100s at line %d",
- user, grps, line);
- } else {
- debug("user %.100s matched group list %.100s at line %d", user,
- grps, line);
- result = 1;
- }
-out:
- ga_free();
- return result;
-}
-
-static int
-match_cfg_line(char **condition, int line, const char *user, const char *host,
- const char *address)
-{
- int result = 1;
- char *arg, *attrib, *cp = *condition;
- size_t len;
-
- if (user == NULL)
- debug3("checking syntax for 'Match %s'", cp);
- else
- debug3("checking match for '%s' user %s host %s addr %s", cp,
- user ? user : "(null)", host ? host : "(null)",
- address ? address : "(null)");
-
- while ((attrib = strdelim(&cp)) != NULL && *attrib != '\0') {
- if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
- error("Missing Match criteria for %s", attrib);
- return -1;
- }
- len = strlen(arg);
- if (strcasecmp(attrib, "user") == 0) {
- if (!user) {
- result = 0;
- continue;
- }
- if (match_pattern_list(user, arg, len, 0) != 1)
- result = 0;
- else
- debug("user %.100s matched 'User %.100s' at "
- "line %d", user, arg, line);
- } else if (strcasecmp(attrib, "group") == 0) {
- switch (match_cfg_line_group(arg, line, user)) {
- case -1:
- return -1;
- case 0:
- result = 0;
- }
- } else if (strcasecmp(attrib, "host") == 0) {
- if (!host) {
- result = 0;
- continue;
- }
- if (match_hostname(host, arg, len) != 1)
- result = 0;
- else
- debug("connection from %.100s matched 'Host "
- "%.100s' at line %d", host, arg, line);
- } else if (strcasecmp(attrib, "address") == 0) {
- switch (addr_match_list(address, arg)) {
- case 1:
- debug("connection from %.100s matched 'Address "
- "%.100s' at line %d", address, arg, line);
- break;
- case 0:
- case -1:
- result = 0;
- break;
- case -2:
- return -1;
- }
- } else {
- error("Unsupported Match attribute %s", attrib);
- return -1;
- }
- }
- if (user != NULL)
- debug3("match %sfound", result ? "" : "not ");
- *condition = cp;
- return result;
-}
-
-#define WHITESPACE " \t\r\n"
-
-int
-process_server_config_line(ServerOptions *options, char *line,
- const char *filename, int linenum, int *activep, const char *user,
- const char *host, const char *address)
-{
- char *cp, **charptr, *arg, *p;
- int cmdline = 0, *intptr, value, n;
- ServerOpCodes opcode;
- u_int i, flags = 0;
- size_t len;
-
- cp = line;
- arg = strdelim(&cp);
- /* Ignore leading whitespace */
- if (*arg == '\0')
- arg = strdelim(&cp);
- if (!arg || !*arg || *arg == '#')
- return 0;
- intptr = NULL;
- charptr = NULL;
- opcode = parse_token(arg, filename, linenum, &flags);
-
- if (activep == NULL) { /* We are processing a command line directive */
- cmdline = 1;
- activep = &cmdline;
- }
- if (*activep && opcode != sMatch)
- debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
- if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
- if (user == NULL) {
- fatal("%s line %d: Directive '%s' is not allowed "
- "within a Match block", filename, linenum, arg);
- } else { /* this is a directive we have already processed */
- while (arg)
- arg = strdelim(&cp);
- return 0;
- }
- }
-
- switch (opcode) {
- /* Portable-specific options */
- case sPAMAuthenticationViaKbdInt:
- log("%s line %d: PAMAuthenticationViaKbdInt has been "
- "deprecated. You should use KbdInteractiveAuthentication "
- "instead (which defaults to \"yes\").", filename, linenum);
- intptr = &options->pam_authentication_via_kbd_int;
- goto parse_flag;
-
- /* Standard Options */
- case sBadOption:
- return -1;
- case sPort:
- /* ignore ports from configfile if cmdline specifies ports */
- if (options->ports_from_cmdline)
- return 0;
- if (options->listen_addrs != NULL)
- fatal("%s line %d: ports must be specified before "
- "ListenAddress.", filename, linenum);
- if (options->num_ports >= MAX_PORTS)
- fatal("%s line %d: too many ports.",
- filename, linenum);
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing port number.",
- filename, linenum);
- options->ports[options->num_ports++] = a2port(arg);
- if (options->ports[options->num_ports-1] == 0)
- fatal("%s line %d: Badly formatted port number.",
- filename, linenum);
- break;
-
- case sServerKeyBits:
- intptr = &options->server_key_bits;
-parse_int:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing integer value.",
- filename, linenum);
- value = atoi(arg);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
-
- case sLoginGraceTime:
- intptr = &options->login_grace_time;
-parse_time:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing time value.",
- filename, linenum);
- if ((value = convtime(arg)) == -1)
- fatal("%s line %d: invalid time value.",
- filename, linenum);
- if (*intptr == -1)
- *intptr = value;
- break;
-
- case sKeyRegenerationTime:
- intptr = &options->key_regeneration_time;
- goto parse_time;
-
- case sListenAddress:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
- fatal("%s line %d: missing inet addr.",
- filename, linenum);
- if (*arg == '[') {
- if ((p = strchr(arg, ']')) == NULL)
- fatal("%s line %d: bad ipv6 inet addr usage.",
- filename, linenum);
- arg++;
- (void) memmove(p, p+1, strlen(p+1)+1);
- } else if (((p = strchr(arg, ':')) == NULL) ||
- (strchr(p+1, ':') != NULL)) {
- add_listen_addr(options, arg, 0);
- break;
- }
- if (*p == ':') {
- u_short port;
-
- p++;
- if (*p == '\0')
- fatal("%s line %d: bad inet addr:port usage.",
- filename, linenum);
- else {
- *(p-1) = '\0';
- if ((port = a2port(p)) == 0)
- fatal("%s line %d: bad port number.",
- filename, linenum);
- add_listen_addr(options, arg, port);
- }
- } else if (*p == '\0')
- add_listen_addr(options, arg, 0);
- else
- fatal("%s line %d: bad inet addr usage.",
- filename, linenum);
- break;
-
- case sHostKeyFile:
- intptr = &options->num_host_key_files;
- if (*intptr >= MAX_HOSTKEYS)
- fatal("%s line %d: too many host keys specified (max %d).",
- filename, linenum, MAX_HOSTKEYS);
- charptr = &options->host_key_files[*intptr];
-parse_filename:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing file name.",
- filename, linenum);
- if (*activep && *charptr == NULL) {
- *charptr = tilde_expand_filename(arg, getuid());
- /* increase optional counter */
- if (intptr != NULL)
- *intptr = *intptr + 1;
- }
- break;
-
- case sPidFile:
- charptr = &options->pid_file;
- goto parse_filename;
-
- case sPermitRootLogin:
- intptr = &options->permit_root_login;
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing yes/"
- "without-password/forced-commands-only/no "
- "argument.", filename, linenum);
- value = 0; /* silence compiler */
- if (strcmp(arg, "without-password") == 0)
- value = PERMIT_NO_PASSWD;
- else if (strcmp(arg, "forced-commands-only") == 0)
- value = PERMIT_FORCED_ONLY;
- else if (strcmp(arg, "yes") == 0)
- value = PERMIT_YES;
- else if (strcmp(arg, "no") == 0)
- value = PERMIT_NO;
- else
- fatal("%s line %d: Bad yes/"
- "without-password/forced-commands-only/no "
- "argument: %s", filename, linenum, arg);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
-
- case sIgnoreRhosts:
- intptr = &options->ignore_rhosts;
-parse_flag:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing yes/no argument.",
- filename, linenum);
- value = 0; /* silence compiler */
- if (strcmp(arg, "yes") == 0)
- value = 1;
- else if (strcmp(arg, "no") == 0)
- value = 0;
- else
- fatal("%s line %d: Bad yes/no argument: %s",
- filename, linenum, arg);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
-
- case sIgnoreUserKnownHosts:
- intptr = &options->ignore_user_known_hosts;
- goto parse_flag;
-
- case sRhostsAuthentication:
- intptr = &options->rhosts_authentication;
- goto parse_flag;
-
- case sRhostsRSAAuthentication:
- intptr = &options->rhosts_rsa_authentication;
- goto parse_flag;
-
- case sHostbasedAuthentication:
- intptr = &options->hostbased_authentication;
- goto parse_flag;
-
- case sHostbasedUsesNameFromPacketOnly:
- intptr = &options->hostbased_uses_name_from_packet_only;
- goto parse_flag;
-
- case sRSAAuthentication:
- intptr = &options->rsa_authentication;
- goto parse_flag;
-
- case sPubkeyAuthentication:
- intptr = &options->pubkey_authentication;
- goto parse_flag;
-#ifdef GSSAPI
- case sGssAuthentication:
- intptr = &options->gss_authentication;
- goto parse_flag;
- case sGssKeyEx:
- intptr = &options->gss_keyex;
- goto parse_flag;
- case sGssStoreDelegCreds:
- intptr = &options->gss_keyex;
- goto parse_flag;
-#ifndef SUNW_GSSAPI
- case sGssUseSessionCredCache:
- intptr = &options->gss_use_session_ccache;
- goto parse_flag;
- case sGssCleanupCreds:
- intptr = &options->gss_cleanup_creds;
- goto parse_flag;
-#endif /* SUNW_GSSAPI */
-#endif /* GSSAPI */
-#if defined(KRB4) || defined(KRB5)
- case sKerberosAuthentication:
- intptr = &options->kerberos_authentication;
- goto parse_flag;
-
- case sKerberosOrLocalPasswd:
- intptr = &options->kerberos_or_local_passwd;
- goto parse_flag;
-
- case sKerberosTicketCleanup:
- intptr = &options->kerberos_ticket_cleanup;
- goto parse_flag;
-#endif
-#if defined(AFS) || defined(KRB5)
- case sKerberosTgtPassing:
- intptr = &options->kerberos_tgt_passing;
- goto parse_flag;
-#endif
-#ifdef AFS
- case sAFSTokenPassing:
- intptr = &options->afs_token_passing;
- goto parse_flag;
-#endif
-
- case sPasswordAuthentication:
- intptr = &options->password_authentication;
- goto parse_flag;
-
- case sKbdInteractiveAuthentication:
- intptr = &options->kbd_interactive_authentication;
- goto parse_flag;
-
- case sChallengeResponseAuthentication:
- intptr = &options->challenge_response_authentication;
- goto parse_flag;
-
- case sPrintMotd:
- intptr = &options->print_motd;
- goto parse_flag;
-
- case sPrintLastLog:
- intptr = &options->print_lastlog;
- goto parse_flag;
-
- case sX11Forwarding:
- intptr = &options->x11_forwarding;
- goto parse_flag;
-
- case sX11DisplayOffset:
- intptr = &options->x11_display_offset;
- goto parse_int;
-
- case sX11UseLocalhost:
- intptr = &options->x11_use_localhost;
- goto parse_flag;
-
- case sXAuthLocation:
- charptr = &options->xauth_location;
- goto parse_filename;
-
- case sStrictModes:
- intptr = &options->strict_modes;
- goto parse_flag;
-
- case sKeepAlives:
- intptr = &options->keepalives;
- goto parse_flag;
-
- case sEmptyPasswd:
- intptr = &options->permit_empty_passwd;
- goto parse_flag;
-
- case sPermitUserEnvironment:
- intptr = &options->permit_user_env;
- goto parse_flag;
-
- case sUseLogin:
- log("%s line %d: ignoring UseLogin option value."
- " This option is always off.", filename, linenum);
- while (arg)
- arg = strdelim(&cp);
- break;
-
- case sCompression:
- intptr = &options->compression;
- goto parse_flag;
-
- case sGatewayPorts:
- intptr = &options->gateway_ports;
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing yes/no/clientspecified "
- "argument.", filename, linenum);
- value = 0; /* silence compiler */
- if (strcmp(arg, "clientspecified") == 0)
- value = 2;
- else if (strcmp(arg, "yes") == 0)
- value = 1;
- else if (strcmp(arg, "no") == 0)
- value = 0;
- else
- fatal("%s line %d: Bad yes/no/clientspecified "
- "argument: %s", filename, linenum, arg);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
-
- case sVerifyReverseMapping:
- intptr = &options->verify_reverse_mapping;
- goto parse_flag;
-
- case sLogFacility:
- intptr = (int *) &options->log_facility;
- arg = strdelim(&cp);
- value = log_facility_number(arg);
- if (value == SYSLOG_FACILITY_NOT_SET)
- fatal("%.200s line %d: unsupported log facility '%s'",
- filename, linenum, arg ? arg : "<NONE>");
- if (*intptr == -1)
- *intptr = (SyslogFacility) value;
- break;
-
- case sLogLevel:
- intptr = (int *) &options->log_level;
- arg = strdelim(&cp);
- value = log_level_number(arg);
- if (value == SYSLOG_LEVEL_NOT_SET)
- fatal("%.200s line %d: unsupported log level '%s'",
- filename, linenum, arg ? arg : "<NONE>");
- if (*intptr == -1)
- *intptr = (LogLevel) value;
- break;
-
- case sAllowTcpForwarding:
- intptr = &options->allow_tcp_forwarding;
- goto parse_flag;
-
- case sUsePrivilegeSeparation:
- log("%s line %d: ignoring UsePrivilegeSeparation option value."
- " This option is always on.", filename, linenum);
- while (arg)
- arg = strdelim(&cp);
- break;
-
- case sAllowUsers:
- while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
- if (options->num_allow_users >= MAX_ALLOW_USERS)
- fatal("%s line %d: too many allow users.",
- filename, linenum);
- options->allow_users[options->num_allow_users++] =
- xstrdup(arg);
- }
- break;
-
- case sDenyUsers:
- while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
- if (options->num_deny_users >= MAX_DENY_USERS)
- fatal( "%s line %d: too many deny users.",
- filename, linenum);
- options->deny_users[options->num_deny_users++] =
- xstrdup(arg);
- }
- break;
-
- case sAllowGroups:
- while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
- if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
- fatal("%s line %d: too many allow groups.",
- filename, linenum);
- options->allow_groups[options->num_allow_groups++] =
- xstrdup(arg);
- }
- break;
-
- case sDenyGroups:
- while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
- if (options->num_deny_groups >= MAX_DENY_GROUPS)
- fatal("%s line %d: too many deny groups.",
- filename, linenum);
- options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
- }
- break;
-
- case sCiphers:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.", filename, linenum);
- if (!ciphers_valid(arg))
- fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (options->ciphers == NULL)
- options->ciphers = xstrdup(arg);
- break;
-
- case sMacs:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.", filename, linenum);
- if (!mac_valid(arg))
- fatal("%s line %d: Bad SSH2 mac spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (options->macs == NULL)
- options->macs = xstrdup(arg);
- break;
-
- case sProtocol:
- intptr = &options->protocol;
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.", filename, linenum);
- value = proto_spec(arg);
- if (value == SSH_PROTO_UNKNOWN)
- fatal("%s line %d: Bad protocol spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (*intptr == SSH_PROTO_UNKNOWN)
- *intptr = value;
- break;
-
- case sSubsystem:
- if (options->num_subsystems >= MAX_SUBSYSTEMS) {
- fatal("%s line %d: too many subsystems defined.",
- filename, linenum);
- }
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing subsystem name.",
- filename, linenum);
- if (!*activep) {
- arg = strdelim(&cp);
- break;
- }
- for (i = 0; i < options->num_subsystems; i++)
- if (strcmp(arg, options->subsystem_name[i]) == 0)
- fatal("%s line %d: Subsystem '%s' already defined.",
- filename, linenum, arg);
- options->subsystem_name[options->num_subsystems] = xstrdup(arg);
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing subsystem command.",
- filename, linenum);
- options->subsystem_command[options->num_subsystems] = xstrdup(arg);
-
- /*
- * Collect arguments (separate to executable), including the
- * name of the executable, in a way that is easier to parse
- * later.
- */
- p = xstrdup(arg);
- len = strlen(p) + 1;
- while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
- len += 1 + strlen(arg);
- p = xrealloc(p, len);
- strlcat(p, " ", len);
- strlcat(p, arg, len);
- }
- options->subsystem_args[options->num_subsystems] = p;
- options->num_subsystems++;
- break;
-
- case sMaxStartups:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing MaxStartups spec.",
- filename, linenum);
- if ((n = sscanf(arg, "%d:%d:%d",
- &options->max_startups_begin,
- &options->max_startups_rate,
- &options->max_startups)) == 3) {
- if (options->max_startups_begin >
- options->max_startups ||
- options->max_startups_rate > 100 ||
- options->max_startups_rate < 1)
- fatal("%s line %d: Illegal MaxStartups spec.",
- filename, linenum);
- } else if (n != 1)
- fatal("%s line %d: Illegal MaxStartups spec.",
- filename, linenum);
- else
- options->max_startups = options->max_startups_begin;
- break;
-
- case sBanner:
- charptr = &options->banner;
- goto parse_filename;
- /*
- * These options can contain %X options expanded at
- * connect time, so that you can specify paths like:
- *
- * AuthorizedKeysFile /etc/ssh_keys/%u
- */
- case sAuthorizedKeysFile:
- case sAuthorizedKeysFile2:
- charptr = (opcode == sAuthorizedKeysFile) ?
- &options->authorized_keys_file :
- &options->authorized_keys_file2;
- goto parse_filename;
-
- case sClientAliveInterval:
- intptr = &options->client_alive_interval;
- goto parse_time;
-
- case sClientAliveCountMax:
- intptr = &options->client_alive_count_max;
- goto parse_int;
-
- case sMaxAuthTries:
- intptr = &options->max_auth_tries;
- goto parse_int;
-
- case sMaxAuthTriesLog:
- intptr = &options->max_auth_tries_log;
- goto parse_int;
-
- case sLookupClientHostnames:
- intptr = &options->lookup_client_hostnames;
- goto parse_flag;
-
- case sUseOpenSSLEngine:
- intptr = &options->use_openssl_engine;
- goto parse_flag;
-
- case sChrootDirectory:
- charptr = &options->chroot_directory;
-
- arg = strdelim(&cp);
- if (arg == NULL || *arg == '\0')
- fatal("%s line %d: missing directory name for "
- "ChrootDirectory.", filename, linenum);
- if (*activep && *charptr == NULL)
- *charptr = xstrdup(arg);
- break;
-
- case sPreUserauthHook:
- charptr = &options->pre_userauth_hook;
- goto parse_filename;
-
- case sMatch:
- if (cmdline)
- fatal("Match directive not supported as a command-line "
- "option");
- value = match_cfg_line(&cp, linenum, user, host, address);
- if (value < 0)
- fatal("%s line %d: Bad Match condition", filename,
- linenum);
- *activep = value;
- break;
-
- case sDeprecated:
- log("%s line %d: Deprecated option %s",
- filename, linenum, arg);
- while (arg)
- arg = strdelim(&cp);
- break;
-
- case sPAMServicePrefix:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.",
- filename, linenum);
- if (options->pam_service_name != NULL)
- fatal("%s line %d: PAMServiceName and PAMServicePrefix "
- "are mutually exclusive.", filename, linenum);
- if (options->pam_service_prefix == NULL)
- options->pam_service_prefix = xstrdup(arg);
- break;
-
- case sPAMServiceName:
- arg = strdelim(&cp);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing argument.",
- filename, linenum);
- if (options->pam_service_prefix != NULL)
- fatal("%s line %d: PAMServiceName and PAMServicePrefix "
- "are mutually exclusive.", filename, linenum);
- if (options->pam_service_name == NULL)
- options->pam_service_name = xstrdup(arg);
- break;
-
- default:
- fatal("%s line %d: Missing handler for opcode %s (%d)",
- filename, linenum, arg, opcode);
- }
- if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
- fatal("%s line %d: garbage at end of line; \"%.200s\".",
- filename, linenum, arg);
- return 0;
-}
-
-
-/* Reads the server configuration file. */
-
-void
-load_server_config(const char *filename, Buffer *conf)
-{
- char line[1024], *cp;
- FILE *f;
-
- debug2("%s: filename %s", __func__, filename);
- if ((f = fopen(filename, "r")) == NULL) {
- perror(filename);
- exit(1);
- }
- buffer_clear(conf);
- while (fgets(line, sizeof(line), f)) {
- /*
- * Trim out comments and strip whitespace
- * NB - preserve newlines, they are needed to reproduce
- * line numbers later for error messages
- */
- if ((cp = strchr(line, '#')) != NULL)
- memcpy(cp, "\n", 2);
- cp = line + strspn(line, " \t\r");
-
- buffer_append(conf, cp, strlen(cp));
- }
- buffer_append(conf, "\0", 1);
- fclose(f);
- debug2("%s: done config len = %d", __func__, buffer_len(conf));
-}
-
-void
-parse_server_match_config(ServerOptions *options, const char *user,
- const char *host, const char *address)
-{
- ServerOptions mo;
-
- initialize_server_options(&mo);
- parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
- copy_set_server_options(options, &mo, 0);
-}
-
-
-
-/* Helper macros */
-#define M_CP_INTOPT(n) do {\
- if (src->n != -1) \
- dst->n = src->n; \
-} while (0)
-#define M_CP_STROPT(n) do {\
- if (src->n != NULL) { \
- if (dst->n != NULL) \
- xfree(dst->n); \
- dst->n = src->n; \
- } \
-} while(0)
-
-/*
- * Copy any supported values that are set.
- *
- * If the preauth flag is set, we do not bother copying the the string or
- * array values that are not used pre-authentication, because any that we
- * do use must be explictly sent in mm_getpwnamallow().
- */
-void
-copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
-{
- M_CP_INTOPT(password_authentication);
- M_CP_INTOPT(gss_authentication);
- M_CP_INTOPT(rsa_authentication);
- M_CP_INTOPT(pubkey_authentication);
- M_CP_INTOPT(hostbased_authentication);
- M_CP_INTOPT(kbd_interactive_authentication);
- M_CP_INTOPT(permit_root_login);
- M_CP_INTOPT(permit_empty_passwd);
- M_CP_INTOPT(allow_tcp_forwarding);
- M_CP_INTOPT(gateway_ports);
- M_CP_INTOPT(x11_display_offset);
- M_CP_INTOPT(x11_forwarding);
- M_CP_INTOPT(x11_use_localhost);
- M_CP_INTOPT(max_auth_tries);
- M_CP_STROPT(banner);
-
- if (preauth)
- return;
- M_CP_STROPT(chroot_directory);
-}
-
-#undef M_CP_INTOPT
-#undef M_CP_STROPT
-
-void
-parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
- const char *user, const char *host, const char *address)
-{
- int active, linenum, bad_options = 0;
- char *cp, *obuf, *cbuf;
-
- debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
-
- obuf = cbuf = xstrdup(buffer_ptr(conf));
- active = user ? 0 : 1;
- linenum = 1;
- while ((cp = strsep(&cbuf, "\n")) != NULL) {
- if (process_server_config_line(options, cp, filename,
- linenum++, &active, user, host, address) != 0)
- bad_options++;
- }
- xfree(obuf);
- if (bad_options > 0)
- fatal("%s: terminating, %d bad configuration options",
- filename, bad_options);
-}
-
-
-/*
- * Note that "none" is a special path having the same affect on sshd
- * configuration as not specifying ChrootDirectory at all.
- */
-int
-chroot_requested(char *chroot_directory)
-{
- return (chroot_directory != NULL &&
- strcasecmp(chroot_directory, "none") != 0);
-}
diff --git a/usr/src/cmd/ssh/sshd/serverloop.c b/usr/src/cmd/ssh/sshd/serverloop.c
deleted file mode 100644
index 3dae9b1840..0000000000
--- a/usr/src/cmd/ssh/sshd/serverloop.c
+++ /dev/null
@@ -1,1310 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Server main loop for handling the interactive session.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- *
- * SSH2 support by Markus Friedl.
- * Copyright (c) 2000, 2001 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.104 2002/09/19 16:03:15 stevesk Exp $");
-
-#include "xmalloc.h"
-#include "packet.h"
-#include "buffer.h"
-#include "log.h"
-#include "servconf.h"
-#include "canohost.h"
-#include "sshpty.h"
-#include "channels.h"
-#include "compat.h"
-#include "ssh1.h"
-#include "ssh2.h"
-#include "auth.h"
-#include "session.h"
-#include "dispatch.h"
-#include "auth-options.h"
-#include "serverloop.h"
-#include "misc.h"
-#include "kex.h"
-
-#ifdef ALTPRIVSEP
-#include "altprivsep.h"
-#endif /* ALTPRIVSEP*/
-
-extern ServerOptions options;
-
-/* XXX */
-extern Kex *xxx_kex;
-static Authctxt *xxx_authctxt;
-
-static Buffer stdin_buffer; /* Buffer for stdin data. */
-static Buffer stdout_buffer; /* Buffer for stdout data. */
-static Buffer stderr_buffer; /* Buffer for stderr data. */
-static int fdin; /* Descriptor for stdin (for writing) */
-static int fdout; /* Descriptor for stdout (for reading);
- May be same number as fdin. */
-static int fderr; /* Descriptor for stderr. May be -1. */
-static long stdin_bytes = 0; /* Number of bytes written to stdin. */
-static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */
-static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */
-static long fdout_bytes = 0; /* Number of stdout bytes read from program. */
-static int stdin_eof = 0; /* EOF message received from client. */
-static int fdout_eof = 0; /* EOF encountered reading from fdout. */
-static int fderr_eof = 0; /* EOF encountered readung from fderr. */
-static int fdin_is_tty = 0; /* fdin points to a tty. */
-static int connection_in; /* Connection to client (input). */
-static int connection_out; /* Connection to client (output). */
-static int connection_closed = 0; /* Connection to client closed. */
-static u_int buffer_high; /* "Soft" max buffer size. */
-static int client_alive_timeouts = 0;
-
-/*
- * This SIGCHLD kludge is used to detect when the child exits. The server
- * will exit after that, as soon as forwarded connections have terminated.
- */
-
-static volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */
-
-/* prototypes */
-static void server_init_dispatch(void);
-
-/*
- * we write to this pipe if a SIGCHLD is caught in order to avoid
- * the race between select() and child_terminated
- */
-static int notify_pipe[2];
-static void
-notify_setup(void)
-{
- if (pipe(notify_pipe) < 0) {
- error("pipe(notify_pipe) failed %s", strerror(errno));
- } else if ((fcntl(notify_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
- (fcntl(notify_pipe[1], F_SETFD, FD_CLOEXEC) == -1)) {
- error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
- (void) close(notify_pipe[0]);
- (void) close(notify_pipe[1]);
- } else {
- set_nonblock(notify_pipe[0]);
- set_nonblock(notify_pipe[1]);
- return;
- }
- notify_pipe[0] = -1; /* read end */
- notify_pipe[1] = -1; /* write end */
-}
-static void
-notify_parent(void)
-{
- if (notify_pipe[1] != -1)
- (void) write(notify_pipe[1], "", 1);
-}
-static void
-notify_prepare(fd_set *readset)
-{
- if (notify_pipe[0] != -1)
- FD_SET(notify_pipe[0], readset);
-}
-static void
-notify_done(fd_set *readset)
-{
- char c;
-
- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
- while (read(notify_pipe[0], &c, 1) != -1)
- debug2("notify_done: reading");
-}
-
-static void
-sigchld_handler(int sig)
-{
- int save_errno = errno;
- debug("Received SIGCHLD.");
- child_terminated = 1;
-#ifndef _UNICOS
- mysignal(SIGCHLD, sigchld_handler);
-#endif
- notify_parent();
- errno = save_errno;
-}
-
-/*
- * Make packets from buffered stderr data, and buffer it for sending
- * to the client.
- */
-static void
-make_packets_from_stderr_data(void)
-{
- int len;
-
- /* Send buffered stderr data to the client. */
- while (buffer_len(&stderr_buffer) > 0 &&
- packet_not_very_much_data_to_write()) {
- len = buffer_len(&stderr_buffer);
- if (packet_is_interactive()) {
- if (len > 512)
- len = 512;
- } else {
- /* Keep the packets at reasonable size. */
- if (len > packet_get_maxsize())
- len = packet_get_maxsize();
- }
- packet_start(SSH_SMSG_STDERR_DATA);
- packet_put_string(buffer_ptr(&stderr_buffer), len);
- packet_send();
- buffer_consume(&stderr_buffer, len);
- stderr_bytes += len;
- }
-}
-
-/*
- * Make packets from buffered stdout data, and buffer it for sending to the
- * client.
- */
-static void
-make_packets_from_stdout_data(void)
-{
- int len;
-
- /* Send buffered stdout data to the client. */
- while (buffer_len(&stdout_buffer) > 0 &&
- packet_not_very_much_data_to_write()) {
- len = buffer_len(&stdout_buffer);
- if (packet_is_interactive()) {
- if (len > 512)
- len = 512;
- } else {
- /* Keep the packets at reasonable size. */
- if (len > packet_get_maxsize())
- len = packet_get_maxsize();
- }
- packet_start(SSH_SMSG_STDOUT_DATA);
- packet_put_string(buffer_ptr(&stdout_buffer), len);
- packet_send();
- buffer_consume(&stdout_buffer, len);
- stdout_bytes += len;
- }
-}
-
-static void
-client_alive_check(void)
-{
- static int had_channel = 0;
- int id;
-
- id = channel_find_open();
- if (id == -1) {
- if (!had_channel)
- return;
- packet_disconnect("No open channels after timeout!");
- }
- had_channel = 1;
-
- /* timeout, check to see how many we have had */
- if (++client_alive_timeouts > options.client_alive_count_max)
- packet_disconnect("Timeout, your session not responding.");
-
- /*
- * send a bogus channel request with "wantreply",
- * we should get back a failure
- */
- channel_request_start(id, "keepalive@openssh.com", 1);
- packet_send();
-}
-
-/*
- * Sleep in select() until we can do something. This will initialize the
- * select masks. Upon return, the masks will indicate which descriptors
- * have data or can accept data. Optionally, a maximum time can be specified
- * for the duration of the wait (0 = infinite).
- */
-static void
-wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
- int *nallocp, u_int max_time_milliseconds)
-{
- struct timeval tv, *tvp;
- int ret;
- int client_alive_scheduled = 0;
-
- /*
- * if using client_alive, set the max timeout accordingly,
- * and indicate that this particular timeout was for client
- * alive by setting the client_alive_scheduled flag.
- *
- * this could be randomized somewhat to make traffic
- * analysis more difficult, but we're not doing it yet.
- */
- if (compat20 &&
- max_time_milliseconds == 0 && options.client_alive_interval) {
- client_alive_scheduled = 1;
- max_time_milliseconds = options.client_alive_interval * 1000;
- }
-
- /* Allocate and update select() masks for channel descriptors. */
- channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
-
- if (compat20) {
-#ifdef ALTPRIVSEP
- int pipe_fd;
-
- if ((pipe_fd = altprivsep_get_pipe_fd()) != -1) {
- *maxfdp = MAX(*maxfdp, pipe_fd);
- FD_SET(altprivsep_get_pipe_fd(), *readsetp);
- }
-#endif /* ALTPRIVSEP */
-#if 0
- /* wrong: bad condition XXX */
- if (channel_not_very_much_buffered_data())
-#endif
- FD_SET(connection_in, *readsetp);
- } else {
- /*
- * Read packets from the client unless we have too much
- * buffered stdin or channel data.
- */
- if (buffer_len(&stdin_buffer) < buffer_high &&
- channel_not_very_much_buffered_data())
- FD_SET(connection_in, *readsetp);
- /*
- * If there is not too much data already buffered going to
- * the client, try to get some more data from the program.
- */
- if (packet_not_very_much_data_to_write()) {
- if (!fdout_eof)
- FD_SET(fdout, *readsetp);
- if (!fderr_eof)
- FD_SET(fderr, *readsetp);
- }
- /*
- * If we have buffered data, try to write some of that data
- * to the program.
- */
- if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
- FD_SET(fdin, *writesetp);
- }
- notify_prepare(*readsetp);
-
- /*
- * If we have buffered packet data going to the client, mark that
- * descriptor.
- */
- if (packet_have_data_to_write())
- FD_SET(connection_out, *writesetp);
-
- /*
- * If child has terminated and there is enough buffer space to read
- * from it, then read as much as is available and exit.
- */
- if (child_terminated && packet_not_very_much_data_to_write())
- if (max_time_milliseconds == 0 || client_alive_scheduled)
- max_time_milliseconds = 100;
-
- if (max_time_milliseconds == 0)
- tvp = NULL;
- else {
- tv.tv_sec = max_time_milliseconds / 1000;
- tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
- tvp = &tv;
- }
-
- /* Wait for something to happen, or the timeout to expire. */
- ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
-
- if (ret == -1) {
- memset(*readsetp, 0, *nallocp);
- memset(*writesetp, 0, *nallocp);
- if (errno != EINTR)
- error("select: %.100s", strerror(errno));
- } else if (ret == 0 && client_alive_scheduled)
- client_alive_check();
-
- notify_done(*readsetp);
-}
-
-/*
- * Processes input from the client and the program. Input data is stored
- * in buffers and processed later.
- */
-static void
-process_input(fd_set * readset)
-{
- int len;
- char buf[16384];
-
- /* Read and buffer any input data from the client. */
- if (FD_ISSET(connection_in, readset)) {
- len = read(connection_in, buf, sizeof(buf));
- if (len == 0) {
- if (packet_is_monitor()) {
- debug("child closed the communication pipe");
- } else {
- verbose("Connection closed by %.100s",
- get_remote_ipaddr());
- }
- connection_closed = 1;
- if (compat20)
- return;
- fatal_cleanup();
- } else if (len < 0) {
- if (errno != EINTR && errno != EAGAIN) {
- verbose("Read error from remote host "
- "%.100s: %.100s",
- get_remote_ipaddr(), strerror(errno));
- fatal_cleanup();
- }
- } else {
- /* Buffer any received data. */
- packet_process_incoming(buf, len);
- }
- }
- if (compat20)
- return;
-
- /* Read and buffer any available stdout data from the program. */
- if (!fdout_eof && FD_ISSET(fdout, readset)) {
- len = read(fdout, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
- /* EMPTY */
- } else if (len <= 0) {
- fdout_eof = 1;
- } else {
- buffer_append(&stdout_buffer, buf, len);
- fdout_bytes += len;
- }
- }
- /* Read and buffer any available stderr data from the program. */
- if (!fderr_eof && FD_ISSET(fderr, readset)) {
- len = read(fderr, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
- /* EMPTY */
- } else if (len <= 0) {
- fderr_eof = 1;
- } else {
- buffer_append(&stderr_buffer, buf, len);
- }
- }
-}
-
-/*
- * Sends data from internal buffers to client program stdin.
- */
-static void
-process_output(fd_set * writeset)
-{
- struct termios tio;
- u_char *data;
- u_int dlen;
- int len;
-
- /* Write buffered data to program stdin. */
- if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
- data = buffer_ptr(&stdin_buffer);
- dlen = buffer_len(&stdin_buffer);
- len = write(fdin, data, dlen);
- if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
- /* EMPTY */
- } else if (len <= 0) {
- if (fdin != fdout)
- (void) close(fdin);
- else
- (void) shutdown(fdin, SHUT_WR); /* We will no longer send. */
- fdin = -1;
- } else {
- /* Successful write. */
- if (fdin_is_tty && dlen >= 1 && data[0] != '\r' &&
- tcgetattr(fdin, &tio) == 0 &&
- !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
- /*
- * Simulate echo to reduce the impact of
- * traffic analysis
- */
- packet_send_ignore(len);
- packet_send();
- }
- /* Consume the data from the buffer. */
- buffer_consume(&stdin_buffer, len);
- /* Update the count of bytes written to the program. */
- stdin_bytes += len;
- }
- }
- /* Send any buffered packet data to the client. */
- if (FD_ISSET(connection_out, writeset))
- packet_write_poll();
-}
-
-/*
- * Wait until all buffered output has been sent to the client.
- * This is used when the program terminates.
- */
-static void
-drain_output(void)
-{
- /* Send any buffered stdout data to the client. */
- if (buffer_len(&stdout_buffer) > 0) {
- packet_start(SSH_SMSG_STDOUT_DATA);
- packet_put_string(buffer_ptr(&stdout_buffer),
- buffer_len(&stdout_buffer));
- packet_send();
- /* Update the count of sent bytes. */
- stdout_bytes += buffer_len(&stdout_buffer);
- }
- /* Send any buffered stderr data to the client. */
- if (buffer_len(&stderr_buffer) > 0) {
- packet_start(SSH_SMSG_STDERR_DATA);
- packet_put_string(buffer_ptr(&stderr_buffer),
- buffer_len(&stderr_buffer));
- packet_send();
- /* Update the count of sent bytes. */
- stderr_bytes += buffer_len(&stderr_buffer);
- }
- /* Wait until all buffered data has been written to the client. */
- packet_write_wait();
-}
-
-static void
-process_buffered_input_packets(void)
-{
- dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
-}
-
-/*
- * Performs the interactive session. This handles data transmission between
- * the client and the program. Note that the notion of stdin, stdout, and
- * stderr in this function is sort of reversed: this function writes to
- * stdin (of the child program), and reads from stdout and stderr (of the
- * child program).
- */
-void
-server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
-{
- fd_set *readset = NULL, *writeset = NULL;
- int max_fd = 0, nalloc = 0;
- int wait_status; /* Status returned by wait(). */
- pid_t wait_pid; /* pid returned by wait(). */
- int waiting_termination = 0; /* Have displayed waiting close message. */
- u_int max_time_milliseconds;
- u_int previous_stdout_buffer_bytes;
- u_int stdout_buffer_bytes;
- int type;
-
- debug("Entering interactive session.");
-
- /* Initialize the SIGCHLD kludge. */
- child_terminated = 0;
- mysignal(SIGCHLD, sigchld_handler);
-
- /* Initialize our global variables. */
- fdin = fdin_arg;
- fdout = fdout_arg;
- fderr = fderr_arg;
-
- /* nonblocking IO */
- set_nonblock(fdin);
- set_nonblock(fdout);
- /* we don't have stderr for interactive terminal sessions, see below */
- if (fderr != -1)
- set_nonblock(fderr);
-
- if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))
- fdin_is_tty = 1;
-
- connection_in = packet_get_connection_in();
- connection_out = packet_get_connection_out();
-
- notify_setup();
-
- previous_stdout_buffer_bytes = 0;
-
- /* Set approximate I/O buffer size. */
- if (packet_is_interactive())
- buffer_high = 4096;
- else
- buffer_high = 64 * 1024;
-
-#if 0
- /* Initialize max_fd to the maximum of the known file descriptors. */
- max_fd = MAX(connection_in, connection_out);
- max_fd = MAX(max_fd, fdin);
- max_fd = MAX(max_fd, fdout);
- if (fderr != -1)
- max_fd = MAX(max_fd, fderr);
-#endif
-
- /* Initialize Initialize buffers. */
- buffer_init(&stdin_buffer);
- buffer_init(&stdout_buffer);
- buffer_init(&stderr_buffer);
-
- /*
- * If we have no separate fderr (which is the case when we have a pty
- * - there we cannot make difference between data sent to stdout and
- * stderr), indicate that we have seen an EOF from stderr. This way
- * we don\'t need to check the descriptor everywhere.
- */
- if (fderr == -1)
- fderr_eof = 1;
-
- server_init_dispatch();
-
- /* Main loop of the server for the interactive session mode. */
- for (;;) {
-
- /* Process buffered packets from the client. */
- process_buffered_input_packets();
-
- /*
- * If we have received eof, and there is no more pending
- * input data, cause a real eof by closing fdin.
- */
- if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
- if (fdin != fdout)
- (void) close(fdin);
- else
- (void) shutdown(fdin, SHUT_WR); /* We will no longer send. */
- fdin = -1;
- }
- /* Make packets from buffered stderr data to send to the client. */
- make_packets_from_stderr_data();
-
- /*
- * Make packets from buffered stdout data to send to the
- * client. If there is very little to send, this arranges to
- * not send them now, but to wait a short while to see if we
- * are getting more data. This is necessary, as some systems
- * wake up readers from a pty after each separate character.
- */
- max_time_milliseconds = 0;
- stdout_buffer_bytes = buffer_len(&stdout_buffer);
- if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
- stdout_buffer_bytes != previous_stdout_buffer_bytes) {
- /* try again after a while */
- max_time_milliseconds = 10;
- } else {
- /* Send it now. */
- make_packets_from_stdout_data();
- }
- previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
-
- /* Send channel data to the client. */
- if (packet_not_very_much_data_to_write())
- channel_output_poll();
-
- /*
- * Bail out of the loop if the program has closed its output
- * descriptors, and we have no more data to send to the
- * client, and there is no pending buffered data.
- */
- if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
- buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
- if (!channel_still_open())
- break;
- if (!waiting_termination) {
- const char *s = "Waiting for forwarded connections to terminate...\r\n";
- char *cp;
- waiting_termination = 1;
- buffer_append(&stderr_buffer, s, strlen(s));
-
- /* Display list of open channels. */
- cp = channel_open_message();
- buffer_append(&stderr_buffer, cp, strlen(cp));
- xfree(cp);
- }
- }
- max_fd = MAX(connection_in, connection_out);
- max_fd = MAX(max_fd, fdin);
- max_fd = MAX(max_fd, fdout);
- max_fd = MAX(max_fd, fderr);
- max_fd = MAX(max_fd, notify_pipe[0]);
-
- /* Sleep in select() until we can do something. */
- wait_until_can_do_something(&readset, &writeset, &max_fd,
- &nalloc, max_time_milliseconds);
-
- /* Process any channel events. */
- channel_after_select(readset, writeset);
-
- /* Process input from the client and from program stdout/stderr. */
- process_input(readset);
-
- /* Process output to the client and to program stdin. */
- process_output(writeset);
- }
- if (readset)
- xfree(readset);
- if (writeset)
- xfree(writeset);
-
- /* Cleanup and termination code. */
-
- /* Wait until all output has been sent to the client. */
- drain_output();
-
- debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
- stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
-
- /* Free and clear the buffers. */
- buffer_free(&stdin_buffer);
- buffer_free(&stdout_buffer);
- buffer_free(&stderr_buffer);
-
- /* Close the file descriptors. */
- if (fdout != -1)
- (void) close(fdout);
- fdout = -1;
- fdout_eof = 1;
- if (fderr != -1)
- (void) close(fderr);
- fderr = -1;
- fderr_eof = 1;
- if (fdin != -1)
- (void) close(fdin);
- fdin = -1;
-
- channel_free_all();
-
- /* We no longer want our SIGCHLD handler to be called. */
- mysignal(SIGCHLD, SIG_DFL);
-
- while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0)
- if (errno != EINTR)
- packet_disconnect("wait: %.100s", strerror(errno));
- if (wait_pid != pid)
- error("Strange, wait returned pid %ld, expected %ld",
- (long)wait_pid, (long)pid);
-
- /* Check if it exited normally. */
- if (WIFEXITED(wait_status)) {
- /* Yes, normal exit. Get exit status and send it to the client. */
- debug("Command exited with status %d.", WEXITSTATUS(wait_status));
- packet_start(SSH_SMSG_EXITSTATUS);
- packet_put_int(WEXITSTATUS(wait_status));
- packet_send();
- packet_write_wait();
-
- /*
- * Wait for exit confirmation. Note that there might be
- * other packets coming before it; however, the program has
- * already died so we just ignore them. The client is
- * supposed to respond with the confirmation when it receives
- * the exit status.
- */
- do {
- type = packet_read();
- }
- while (type != SSH_CMSG_EXIT_CONFIRMATION);
-
- debug("Received exit confirmation.");
- return;
- }
- /* Check if the program terminated due to a signal. */
- if (WIFSIGNALED(wait_status))
- packet_disconnect("Command terminated on signal %d.",
- WTERMSIG(wait_status));
-
- /* Some weird exit cause. Just exit. */
- packet_disconnect("wait returned status %04x.", wait_status);
- /* NOTREACHED */
-}
-
-static void
-collect_children(void)
-{
- pid_t pid;
- sigset_t oset, nset;
- int status;
-
- /* block SIGCHLD while we check for dead children */
- (void) sigemptyset(&nset);
- (void) sigaddset(&nset, SIGCHLD);
- (void) sigprocmask(SIG_BLOCK, &nset, &oset);
- if (child_terminated) {
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
- (pid < 0 && errno == EINTR))
- if (pid > 0)
- session_close_by_pid(pid, status);
- child_terminated = 0;
- }
- (void) sigprocmask(SIG_SETMASK, &oset, NULL);
-}
-
-#ifdef ALTPRIVSEP
-/*
- * For ALTPRIVSEP the wait_until_can_do_something function is very
- * simple: select() on the read side of the pipe, and if there's packets
- * to send, on the write side, and on the read side of the SIGCHLD
- * handler pipe. That's it.
- */
-static void
-aps_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
- int *maxfdp, int *nallocp, u_int max_time_milliseconds)
-{
- int ret;
-
- /*
- * Use channel_prepare_select() to make the fd sets.
- *
- * This is cheating, really, since because the last argument in
- * this call is '1' nothing related to channels will be done --
- * we're using this function only to callocate the fd sets.
- */
- channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 1);
-
- if ((connection_in = packet_get_connection_in()) >= 0 &&
- !connection_closed)
- FD_SET(connection_in, *readsetp);
-
- notify_prepare(*readsetp);
-
- if ((connection_out = packet_get_connection_out()) >= 0 &&
- packet_have_data_to_write() && !connection_closed)
- FD_SET(connection_out, *writesetp);
-
- /* Wait for something to happen, or the timeout to expire. */
- ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL);
-
- if (ret == -1) {
- memset(*readsetp, 0, *nallocp);
- memset(*writesetp, 0, *nallocp);
- if (errno != EINTR)
- error("select: %.100s", strerror(errno));
- }
-
- notify_done(*readsetp);
-}
-
-/*
- * Slightly different than collect_children, aps_collect_child() has
- * only the unprivileged sshd to wait for, no sessions, no channells,
- * just one process.
- */
-static int
-aps_collect_child(pid_t child)
-{
- pid_t pid;
- sigset_t oset, nset;
- int status;
-
- /* block SIGCHLD while we check for dead children */
- (void) sigemptyset(&nset);
- (void) sigaddset(&nset, SIGCHLD);
- (void) sigprocmask(SIG_BLOCK, &nset, &oset);
- if (child_terminated) {
- while ((pid = waitpid(child, &status, WNOHANG)) > 0 ||
- (pid < 0 && errno == EINTR))
- if (pid == child) {
- (void) sigprocmask(SIG_SETMASK, &oset, NULL);
- return (1);
- }
- child_terminated = 0;
- }
- (void) sigprocmask(SIG_SETMASK, &oset, NULL);
- return (0);
-}
-
-static int killed = 0;
-
-static void
-aps_monitor_kill_handler(int sig)
-{
- int save_errno = errno;
- killed = 1;
- notify_parent();
- mysignal(sig, aps_monitor_kill_handler);
- errno = save_errno;
-}
-
-static void
-aps_monitor_sigchld_handler(int sig)
-{
- int save_errno = errno;
- debug("Monitor received SIGCHLD.");
- child_terminated = 1;
- mysignal(SIGCHLD, aps_monitor_sigchld_handler);
- notify_parent();
- errno = save_errno;
-}
-
-void
-aps_monitor_loop(Authctxt *authctxt, pid_t child_pid)
-{
- fd_set *readset = NULL, *writeset = NULL;
- int max_fd, nalloc = 0;
-
- debug("Entering monitor loop.");
-
- /*
- * Awful hack follows: fake compat20 == 1 to cause process_input()
- * and process_output() to behave as they would for SSHv2 because that's
- * the behaviour we need in SSHv2.
- *
- * This same hack is done in packet.c
- */
- compat20 = 1; /* causes process_input/output() to ignore stdio */
-
- mysignal(SIGHUP, aps_monitor_kill_handler);
- mysignal(SIGINT, aps_monitor_kill_handler);
- mysignal(SIGTERM, aps_monitor_kill_handler);
-
- child_terminated = 0;
- mysignal(SIGCHLD, aps_monitor_sigchld_handler);
-
- connection_in = packet_get_connection_in();
- connection_out = packet_get_connection_out();
-
- notify_setup();
-
- max_fd = MAX(connection_in, connection_out);
- max_fd = MAX(max_fd, notify_pipe[0]);
-
- dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
- dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_MAX,
- &dispatch_protocol_error);
- dispatch_set(SSH2_PRIV_MSG_ALTPRIVSEP, &aps_input_altpriv_msg);
-
- for (;;) {
- process_buffered_input_packets();
-
- aps_wait_until_can_do_something(&readset, &writeset, &max_fd,
- &nalloc, 0);
-
- if (aps_collect_child(child_pid))
- break;
-
- if (killed) {
- /* fatal cleanups will kill child, audit logout */
- log("Monitor killed; exiting");
- fatal_cleanup();
- }
-
- /*
- * Unlike server_loop2() we don't care if connection_closed
- * since we still want to wait for the monitor's child.
- */
- process_input(readset);
- process_output(writeset);
- }
-
- packet_close();
-}
-#endif /* ALTPRIVSEP */
-
-/*
- * This server loop is for unprivileged child only. Our monitor runs its own
- * aps_monitor_loop() funtion.
- */
-void
-server_loop2(Authctxt *authctxt)
-{
- fd_set *readset = NULL, *writeset = NULL;
- int rekeying = 0, max_fd, nalloc = 0;
-
- debug("Entering interactive session for SSH2.");
-
- mysignal(SIGCHLD, sigchld_handler);
- child_terminated = 0;
- connection_in = packet_get_connection_in();
- connection_out = packet_get_connection_out();
-
- notify_setup();
-
- max_fd = MAX(connection_in, connection_out);
- max_fd = MAX(max_fd, notify_pipe[0]);
-
- xxx_authctxt = authctxt;
-
- server_init_dispatch();
-
- for (;;) {
- process_buffered_input_packets();
-
- rekeying = (xxx_kex != NULL && !xxx_kex->done);
-
- if (!rekeying && packet_not_very_much_data_to_write())
- channel_output_poll();
- wait_until_can_do_something(&readset, &writeset, &max_fd,
- &nalloc, 0);
-
- collect_children();
-
- if (!rekeying) {
- channel_after_select(readset, writeset);
- if (packet_need_rekeying()) {
- debug("rekey limit reached, need rekeying");
- xxx_kex->done = 0;
- debug("poking the monitor to start "
- "key re-exchange");
- altprivsep_start_rekex();
- }
- }
-#ifdef ALTPRIVSEP
- else
- altprivsep_process_input(readset);
-#endif /* ALTPRIVSEP */
-
- process_input(readset);
- if (connection_closed)
- break;
- process_output(writeset);
- }
- collect_children();
-
- if (readset)
- xfree(readset);
- if (writeset)
- xfree(writeset);
-
- /* free all channels, no more reads and writes */
- channel_free_all();
-
- /* free remaining sessions, e.g. remove wtmp entries */
- session_destroy_all(NULL);
-}
-
-static void
-server_input_channel_failure(int type, u_int32_t seq, void *ctxt)
-{
- debug("Got CHANNEL_FAILURE for keepalive");
- /*
- * reset timeout, since we got a sane answer from the client.
- * even if this was generated by something other than
- * the bogus CHANNEL_REQUEST we send for keepalives.
- */
- client_alive_timeouts = 0;
-}
-
-static void
-server_input_stdin_data(int type, u_int32_t seq, void *ctxt)
-{
- char *data;
- u_int data_len;
-
- /* Stdin data from the client. Append it to the buffer. */
- /* Ignore any data if the client has closed stdin. */
- if (fdin == -1)
- return;
- data = packet_get_string(&data_len);
- packet_check_eom();
- buffer_append(&stdin_buffer, data, data_len);
- memset(data, 0, data_len);
- xfree(data);
-}
-
-static void
-server_input_eof(int type, u_int32_t seq, void *ctxt)
-{
- /*
- * Eof from the client. The stdin descriptor to the
- * program will be closed when all buffered data has
- * drained.
- */
- debug("EOF received for stdin.");
- packet_check_eom();
- stdin_eof = 1;
-}
-
-static void
-server_input_window_size(int type, u_int32_t seq, void *ctxt)
-{
- int row = packet_get_int();
- int col = packet_get_int();
- int xpixel = packet_get_int();
- int ypixel = packet_get_int();
-
- debug("Window change received.");
- packet_check_eom();
- if (fdin != -1)
- pty_change_window_size(fdin, row, col, xpixel, ypixel);
-}
-
-static Channel *
-server_request_direct_tcpip(char *ctype)
-{
- Channel *c;
- int sock;
- char *target, *originator;
- int target_port, originator_port;
-
- target = packet_get_string(NULL);
- target_port = packet_get_int();
- originator = packet_get_string(NULL);
- originator_port = packet_get_int();
- packet_check_eom();
-
- debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
- originator, originator_port, target, target_port);
-
- /* XXX check permission */
- sock = channel_connect_to(target, target_port);
-
- xfree(target);
- xfree(originator);
- if (sock < 0)
- return NULL;
- c = channel_new(ctype, SSH_CHANNEL_CONNECTING,
- sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
- CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
- return c;
-}
-
-static Channel *
-server_request_session(char *ctype)
-{
- Channel *c;
-
- debug("input_session_request");
- packet_check_eom();
- /*
- * A server session has no fd to read or write until a
- * CHANNEL_REQUEST for a shell is made, so we set the type to
- * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all
- * CHANNEL_REQUEST messages is registered.
- */
- c = channel_new(ctype, SSH_CHANNEL_LARVAL,
- -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
- 0, xstrdup("server-session"), 1);
- if (session_open(xxx_authctxt, c->self) != 1) {
- debug("session open failed, free channel %d", c->self);
- channel_free(c);
- return NULL;
- }
- channel_register_cleanup(c->self, session_close_by_channel);
- return c;
-}
-
-static void
-server_input_channel_open(int type, u_int32_t seq, void *ctxt)
-{
- Channel *c = NULL;
- char *ctype;
- int rchan;
- u_int rmaxpack, rwindow, len;
-
- ctype = packet_get_string(&len);
- rchan = packet_get_int();
- rwindow = packet_get_int();
- rmaxpack = packet_get_int();
-
- debug("server_input_channel_open: ctype %s rchan %d win %d max %d",
- ctype, rchan, rwindow, rmaxpack);
-
- if (strcmp(ctype, "session") == 0) {
- c = server_request_session(ctype);
- } else if (strcmp(ctype, "direct-tcpip") == 0) {
- c = server_request_direct_tcpip(ctype);
- }
- if (c != NULL) {
- debug("server_input_channel_open: confirm %s", ctype);
- c->remote_id = rchan;
- c->remote_window = rwindow;
- c->remote_maxpacket = rmaxpack;
- if (c->type != SSH_CHANNEL_CONNECTING) {
- packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(c->remote_id);
- packet_put_int(c->self);
- packet_put_int(c->local_window);
- packet_put_int(c->local_maxpacket);
- packet_send();
- }
- } else {
- debug("server_input_channel_open: failure %s", ctype);
- packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
- packet_put_int(rchan);
- packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
- if (!(datafellows & SSH_BUG_OPENFAILURE)) {
- packet_put_utf8_cstring("open failed");
- packet_put_cstring("");
- }
- packet_send();
- }
- xfree(ctype);
-}
-
-static void
-server_input_global_request(int type, u_int32_t seq, void *ctxt)
-{
- char *rtype;
- int want_reply;
- int success = 0;
-
- rtype = packet_get_string(NULL);
- want_reply = packet_get_char();
- debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);
-
- /* -R style forwarding */
- if (strcmp(rtype, "tcpip-forward") == 0) {
- struct passwd *pw;
- char *listen_address;
- u_short listen_port;
-
- pw = auth_get_user();
- if (pw == NULL)
- fatal("server_input_global_request: no user");
- listen_address = packet_get_string(NULL); /* XXX currently ignored */
- listen_port = (u_short)packet_get_int();
- debug("server_input_global_request: tcpip-forward listen %s port %d",
- listen_address, listen_port);
-
- /* check permissions */
- if (!options.allow_tcp_forwarding ||
- no_port_forwarding_flag
-#ifndef NO_IPPORT_RESERVED_CONCEPT
- || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)
-#endif
- ) {
- success = 0;
- packet_send_debug("Server has disabled port forwarding.");
- } else {
- /* Start listening on the port */
- success = channel_setup_remote_fwd_listener(
- listen_address, listen_port, options.gateway_ports);
- }
- xfree(listen_address);
- } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
- char *cancel_address;
- u_short cancel_port;
-
- cancel_address = packet_get_string(NULL);
- cancel_port = (u_short)packet_get_int();
- debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
- cancel_address, cancel_port);
-
- success = channel_cancel_rport_listener(cancel_address,
- cancel_port);
- xfree(cancel_address);
- }
- if (want_reply) {
- packet_start(success ?
- SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
- packet_send();
- packet_write_wait();
- }
- xfree(rtype);
-}
-
-static void
-server_input_channel_req(int type, u_int32_t seq, void *ctxt)
-{
- Channel *c;
- int id, reply, success = 0;
- char *rtype;
-
- id = packet_get_int();
- rtype = packet_get_string(NULL);
- reply = packet_get_char();
-
- debug("server_input_channel_req: channel %d request %s reply %d",
- id, rtype, reply);
-
- if ((c = channel_lookup(id)) == NULL)
- packet_disconnect("server_input_channel_req: "
- "unknown channel %d", id);
- if (!strcmp(rtype, "eow@openssh.com")) {
- packet_check_eom();
- chan_rcvd_eow(c);
- } else if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN)
- success = session_input_channel_req(c, rtype);
- if (reply) {
- packet_start(success ?
- SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
- packet_put_int(c->remote_id);
- packet_send();
- }
- xfree(rtype);
-}
-
-static void
-server_init_dispatch_20(void)
-{
- debug("server_init_dispatch_20");
- dispatch_init(&dispatch_protocol_error);
- dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
- dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
- dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
- dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
- dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
- dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
- dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
- dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
- dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
- dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
- /* client_alive */
- dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
- /* rekeying */
-
-#ifdef ALTPRIVSEP
- /* unprivileged sshd has a kex packet handler that must not be reset */
- debug3("server_init_dispatch_20 -- should we dispatch_set(KEXINIT) here? %d && !%d",
- packet_is_server(), packet_is_monitor());
- if (packet_is_server() && !packet_is_monitor()) {
- debug3("server_init_dispatch_20 -- skipping dispatch_set(KEXINIT) in unpriv proc");
- dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX,
- &altprivsep_rekey);
- return;
- }
-#endif /* ALTPRIVSEP */
- dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
-}
-static void
-server_init_dispatch_13(void)
-{
- debug("server_init_dispatch_13");
- dispatch_init(NULL);
- dispatch_set(SSH_CMSG_EOF, &server_input_eof);
- dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data);
- dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size);
- dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
- dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
- dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
- dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
- dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
- dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
-}
-static void
-server_init_dispatch_15(void)
-{
- server_init_dispatch_13();
- debug("server_init_dispatch_15");
- dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
- dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
-}
-static void
-server_init_dispatch(void)
-{
- if (compat20)
- server_init_dispatch_20();
- else if (compat13)
- server_init_dispatch_13();
- else
- server_init_dispatch_15();
-}
diff --git a/usr/src/cmd/ssh/sshd/session.c b/usr/src/cmd/ssh/sshd/session.c
deleted file mode 100644
index 871b06c758..0000000000
--- a/usr/src/cmd/ssh/sshd/session.c
+++ /dev/null
@@ -1,2641 +0,0 @@
-/*
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- *
- * SSH2 support by Markus Friedl.
- * Copyright (c) 2000, 2001 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.150 2002/09/16 19:55:33 stevesk Exp $");
-
-#ifdef HAVE_DEFOPEN
-#include <deflt.h>
-#include <ulimit.h>
-#endif /* HAVE_DEFOPEN */
-
-#ifdef HAVE_LIBGEN_H
-#include <libgen.h>
-#endif
-
-#include <priv.h>
-
-#include "ssh.h"
-#include "ssh1.h"
-#include "ssh2.h"
-#include "xmalloc.h"
-#include "sshpty.h"
-#include "packet.h"
-#include "buffer.h"
-#include "mpaux.h"
-#include "uidswap.h"
-#include "compat.h"
-#include "channels.h"
-#include "bufaux.h"
-#include "auth.h"
-#include "auth-options.h"
-#include "pathnames.h"
-#include "log.h"
-#include "servconf.h"
-#include "sshlogin.h"
-#include "serverloop.h"
-#include "canohost.h"
-#include "session.h"
-#include "tildexpand.h"
-#include "misc.h"
-#include "sftp.h"
-
-#ifdef USE_PAM
-#include <security/pam_appl.h>
-#endif /* USE_PAM */
-
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif
-
-#ifdef ALTPRIVSEP
-#include "altprivsep.h"
-#endif /* ALTPRIVSEP */
-
-#ifdef HAVE_CYGWIN
-#include <windows.h>
-#include <sys/cygwin.h>
-#define is_winnt (GetVersion() < 0x80000000)
-#endif
-
-/* func */
-
-Session *session_new(void);
-void session_set_fds(Session *, int, int, int);
-void session_pty_cleanup(void *);
-void session_xauthfile_cleanup(void *s);
-void session_proctitle(Session *);
-int session_setup_x11fwd(Session *);
-void do_exec_pty(Session *, const char *);
-void do_exec_no_pty(Session *, const char *);
-void do_exec(Session *, const char *);
-void do_login(Session *, const char *);
-void do_child(Session *, const char *);
-void do_motd(void);
-int check_quietlogin(Session *, const char *);
-
-static void do_authenticated1(Authctxt *);
-static void do_authenticated2(Authctxt *);
-
-static int session_pty_req(Session *);
-static int session_env_req(Session *s);
-static void session_free_env(char ***envp);
-static void safely_chroot(const char *path, uid_t uid);
-static void drop_privs(uid_t uid);
-
-#ifdef USE_PAM
-static void session_do_pam(Session *, int);
-#endif /* USE_PAM */
-
-/* import */
-extern ServerOptions options;
-extern char *__progname;
-extern int log_stderr;
-extern int debug_flag;
-extern u_int utmp_len;
-extern void destroy_sensitive_data(void);
-
-#ifdef GSSAPI
-extern Gssctxt *xxx_gssctxt;
-#endif /* GSSAPI */
-
-/* original command from peer. */
-const char *original_command = NULL;
-
-/* data */
-#define MAX_SESSIONS 10
-Session sessions[MAX_SESSIONS];
-
-#define SUBSYSTEM_NONE 0
-#define SUBSYSTEM_EXT 1
-#define SUBSYSTEM_INT_SFTP 2
-
-#ifdef HAVE_LOGIN_CAP
-login_cap_t *lc;
-#endif
-
-/* Name and directory of socket for authentication agent forwarding. */
-static char *auth_sock_name = NULL;
-static char *auth_sock_dir = NULL;
-
-/* removes the agent forwarding socket */
-
-static void
-auth_sock_cleanup_proc(void *_pw)
-{
- struct passwd *pw = _pw;
-
- if (auth_sock_name != NULL) {
- temporarily_use_uid(pw);
- unlink(auth_sock_name);
- rmdir(auth_sock_dir);
- auth_sock_name = NULL;
- restore_uid();
- }
-}
-
-static int
-auth_input_request_forwarding(struct passwd * pw)
-{
- Channel *nc;
- int sock;
- struct sockaddr_un sunaddr;
-
- if (auth_sock_name != NULL) {
- error("authentication forwarding requested twice.");
- return 0;
- }
-
- /* Temporarily drop privileged uid for mkdir/bind. */
- temporarily_use_uid(pw);
-
- /* Allocate a buffer for the socket name, and format the name. */
- auth_sock_name = xmalloc(MAXPATHLEN);
- auth_sock_dir = xmalloc(MAXPATHLEN);
- strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
-
- /* Create private directory for socket */
- if (mkdtemp(auth_sock_dir) == NULL) {
- packet_send_debug("Agent forwarding disabled: "
- "mkdtemp() failed: %.100s", strerror(errno));
- restore_uid();
- xfree(auth_sock_name);
- xfree(auth_sock_dir);
- auth_sock_name = NULL;
- auth_sock_dir = NULL;
- return 0;
- }
- snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",
- auth_sock_dir, (long) getpid());
-
- /* delete agent socket on fatal() */
- fatal_add_cleanup(auth_sock_cleanup_proc, pw);
-
- /* Create the socket. */
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0)
- packet_disconnect("socket: %.100s", strerror(errno));
-
- /* Bind it to the name. */
- memset(&sunaddr, 0, sizeof(sunaddr));
- sunaddr.sun_family = AF_UNIX;
- strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
-
- if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
- packet_disconnect("bind: %.100s", strerror(errno));
-
- /* Restore the privileged uid. */
- restore_uid();
-
- /* Start listening on the socket. */
- if (listen(sock, 5) < 0)
- packet_disconnect("listen: %.100s", strerror(errno));
-
- /* Allocate a channel for the authentication agent socket. */
- nc = channel_new("auth socket",
- SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
- CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
- 0, xstrdup("auth socket"), 1);
- strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
- return 1;
-}
-
-
-void
-do_authenticated(Authctxt *authctxt)
-{
- /* setup the channel layer */
- if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
- channel_permit_all_opens();
-
- if (compat20)
- do_authenticated2(authctxt);
- else
- do_authenticated1(authctxt);
-
- /* remove agent socket */
- if (auth_sock_name != NULL)
- auth_sock_cleanup_proc(authctxt->pw);
-#ifdef KRB4
- if (options.kerberos_ticket_cleanup)
- krb4_cleanup_proc(authctxt);
-#endif
-#ifdef KRB5
- if (options.kerberos_ticket_cleanup)
- krb5_cleanup_proc(authctxt);
-#endif
-}
-
-/*
- * Prepares for an interactive session. This is called after the user has
- * been successfully authenticated. During this message exchange, pseudo
- * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
- * are requested, etc.
- */
-static void
-do_authenticated1(Authctxt *authctxt)
-{
- Session *s;
- char *command;
- int success, type, screen_flag;
- int enable_compression_after_reply = 0;
- u_int proto_len, data_len, dlen, compression_level = 0;
-
- s = session_new();
- s->authctxt = authctxt;
- s->pw = authctxt->pw;
-
- /*
- * We stay in this loop until the client requests to execute a shell
- * or a command.
- */
- for (;;) {
- success = 0;
-
- /* Get a packet from the client. */
- type = packet_read();
-
- /* Process the packet. */
- switch (type) {
- case SSH_CMSG_REQUEST_COMPRESSION:
- compression_level = packet_get_int();
- packet_check_eom();
- if (compression_level < 1 || compression_level > 9) {
- packet_send_debug("Received illegal compression level %d.",
- compression_level);
- break;
- }
- if (!options.compression) {
- debug2("compression disabled");
- break;
- }
- /* Enable compression after we have responded with SUCCESS. */
- enable_compression_after_reply = 1;
- success = 1;
- break;
-
- case SSH_CMSG_REQUEST_PTY:
- success = session_pty_req(s);
- break;
-
- case SSH_CMSG_X11_REQUEST_FORWARDING:
- s->auth_proto = packet_get_string(&proto_len);
- s->auth_data = packet_get_string(&data_len);
-
- screen_flag = packet_get_protocol_flags() &
- SSH_PROTOFLAG_SCREEN_NUMBER;
- debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
-
- if (packet_remaining() == 4) {
- if (!screen_flag)
- debug2("Buggy client: "
- "X11 screen flag missing");
- s->screen = packet_get_int();
- } else {
- s->screen = 0;
- }
- packet_check_eom();
- success = session_setup_x11fwd(s);
- if (!success) {
- xfree(s->auth_proto);
- xfree(s->auth_data);
- s->auth_proto = NULL;
- s->auth_data = NULL;
- }
- break;
-
- case SSH_CMSG_AGENT_REQUEST_FORWARDING:
- if (no_agent_forwarding_flag || compat13) {
- debug("Authentication agent forwarding not permitted for this authentication.");
- break;
- }
- debug("Received authentication agent forwarding request.");
- success = auth_input_request_forwarding(s->pw);
- break;
-
- case SSH_CMSG_PORT_FORWARD_REQUEST:
- if (no_port_forwarding_flag) {
- debug("Port forwarding not permitted for this authentication.");
- break;
- }
- if (!options.allow_tcp_forwarding) {
- debug("Port forwarding not permitted.");
- break;
- }
- debug("Received TCP/IP port forwarding request.");
- channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
- success = 1;
- break;
-
- case SSH_CMSG_MAX_PACKET_SIZE:
- if (packet_set_maxsize(packet_get_int()) > 0)
- success = 1;
- break;
-
-#if defined(AFS) || defined(KRB5)
- case SSH_CMSG_HAVE_KERBEROS_TGT:
- if (!options.kerberos_tgt_passing) {
- verbose("Kerberos TGT passing disabled.");
- } else {
- char *kdata = packet_get_string(&dlen);
- packet_check_eom();
-
- /* XXX - 0x41, see creds_to_radix version */
- if (kdata[0] != 0x41) {
-#ifdef KRB5
- krb5_data tgt;
- tgt.data = kdata;
- tgt.length = dlen;
-
- if (auth_krb5_tgt(s->authctxt, &tgt))
- success = 1;
- else
- verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user);
-#endif /* KRB5 */
- } else {
-#ifdef AFS
- if (auth_krb4_tgt(s->authctxt, kdata))
- success = 1;
- else
- verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user);
-#endif /* AFS */
- }
- xfree(kdata);
- }
- break;
-#endif /* AFS || KRB5 */
-
-#ifdef AFS
- case SSH_CMSG_HAVE_AFS_TOKEN:
- if (!options.afs_token_passing || !k_hasafs()) {
- verbose("AFS token passing disabled.");
- } else {
- /* Accept AFS token. */
- char *token = packet_get_string(&dlen);
- packet_check_eom();
-
- if (auth_afs_token(s->authctxt, token))
- success = 1;
- else
- verbose("AFS token refused for %.100s",
- s->authctxt->user);
- xfree(token);
- }
- break;
-#endif /* AFS */
-
- case SSH_CMSG_EXEC_SHELL:
- case SSH_CMSG_EXEC_CMD:
- if (type == SSH_CMSG_EXEC_CMD) {
- command = packet_get_string(&dlen);
- debug("Exec command '%.500s'", command);
- do_exec(s, command);
- xfree(command);
- } else {
- do_exec(s, NULL);
- }
- packet_check_eom();
- session_close(s);
- return;
-
- default:
- /*
- * Any unknown messages in this phase are ignored,
- * and a failure message is returned.
- */
- log("Unknown packet type received after authentication: %d", type);
- }
- packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
-
- /* Enable compression now that we have replied if appropriate. */
- if (enable_compression_after_reply) {
- enable_compression_after_reply = 0;
- packet_start_compression(compression_level);
- }
- }
-}
-
-/*
- * This is called to fork and execute a command when we have no tty. This
- * will call do_child from the child, and server_loop from the parent after
- * setting up file descriptors and such.
- */
-void
-do_exec_no_pty(Session *s, const char *command)
-{
- pid_t pid;
-
- int inout[2], err[2];
- /* Uses socket pairs to communicate with the program. */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
- socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
- packet_disconnect("Could not create socket pairs: %.100s",
- strerror(errno));
- if (s == NULL)
- fatal("do_exec_no_pty: no session");
-
- session_proctitle(s);
-
- /* Fork the child. */
- if ((pid = fork()) == 0) {
- fatal_remove_all_cleanups();
-
- /* Child. Reinitialize the log since the pid has changed. */
- log_init(__progname, options.log_level, options.log_facility, log_stderr);
-
- /*
- * Create a new session and process group since the 4.4BSD
- * setlogin() affects the entire process group.
- */
- if (setsid() < 0)
- error("setsid failed: %.100s", strerror(errno));
-
- /*
- * Redirect stdin, stdout, and stderr. Stdin and stdout will
- * use the same socket, as some programs (particularly rdist)
- * seem to depend on it.
- */
- close(inout[1]);
- close(err[1]);
- if (dup2(inout[0], 0) < 0) /* stdin */
- perror("dup2 stdin");
- if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
- perror("dup2 stdout");
- if (s->is_subsystem) {
- /*
- * Redirect the subsystem's stderr to /dev/null. We might send it
- * over to the other side but changing that might break existing
- * SSH clients.
- */
- close(err[0]);
- if ((err[0] = open(_PATH_DEVNULL, O_WRONLY)) == -1)
- fatal("Cannot open /dev/null: %.100s", strerror(errno));
- }
- if (dup2(err[0], 2) < 0) /* stderr */
- perror("dup2 stderr");
-
-#ifdef _UNICOS
- cray_init_job(s->pw); /* set up cray jid and tmpdir */
-#endif
-
- /* Do processing for the child (exec command etc). */
- do_child(s, command);
- /* NOTREACHED */
- }
-#ifdef _UNICOS
- signal(WJSIGNAL, cray_job_termination_handler);
-#endif /* _UNICOS */
-#ifdef HAVE_CYGWIN
- if (is_winnt)
- cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
-#endif
- if (pid < 0)
- packet_disconnect("fork failed: %.100s", strerror(errno));
-
- s->pid = pid;
- /* Set interactive/non-interactive mode. */
- packet_set_interactive(s->display != NULL);
-
- /* We are the parent. Close the child sides of the socket pairs. */
- close(inout[0]);
- close(err[0]);
-
- /*
- * Enter the interactive session. Note: server_loop must be able to
- * handle the case that fdin and fdout are the same.
- */
- if (compat20) {
- session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
- if (s->is_subsystem)
- close(err[1]);
- /* Don't close channel before sending exit-status! */
- channel_set_wait_for_exit(s->chanid, 1);
- } else {
- server_loop(pid, inout[1], inout[1], err[1]);
- /* server_loop has closed inout[1] and err[1]. */
- }
-}
-
-/*
- * This is called to fork and execute a command when we have a tty. This
- * will call do_child from the child, and server_loop from the parent after
- * setting up file descriptors, controlling tty, updating wtmp, utmp,
- * lastlog, and other such operations.
- */
-void
-do_exec_pty(Session *s, const char *command)
-{
- int fdout, ptyfd, ttyfd, ptymaster, pipe_fds[2];
- pid_t pid;
-
- if (s == NULL)
- fatal("do_exec_pty: no session");
- ptyfd = s->ptyfd;
- ttyfd = s->ttyfd;
-
-#ifdef USE_PAM
- session_do_pam(s, 1); /* pam_open_session() */
-#endif /* USE_PAM */
-
- /*
- * This pipe lets sshd wait for child to exec or exit. This is
- * particularly important for ALTPRIVSEP because the child is
- * the one to call the monitor to request a record_login() and
- * we don't want the child and the parent to compete for the
- * monitor's attention. But this is generic code and doesn't
- * hurt to have here even if ALTPRIVSEP is not used.
- */
- if (pipe(pipe_fds) != 0)
- packet_disconnect("pipe failed: %.100s", strerror(errno));
-
- (void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC);
- (void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC);
-
- /* Fork the child. */
- if ((pid = fork()) == 0) {
- (void) close(pipe_fds[0]);
-
- fatal_remove_all_cleanups();
-
- /* Child. Reinitialize the log because the pid has changed. */
- log_init(__progname, options.log_level, options.log_facility, log_stderr);
- /* Close the master side of the pseudo tty. */
- close(ptyfd);
-
- /* Make the pseudo tty our controlling tty. */
- pty_make_controlling_tty(&ttyfd, s->tty);
-
- /* Redirect stdin/stdout/stderr from the pseudo tty. */
- if (dup2(ttyfd, 0) < 0)
- error("dup2 stdin: %s", strerror(errno));
- if (dup2(ttyfd, 1) < 0)
- error("dup2 stdout: %s", strerror(errno));
- if (dup2(ttyfd, 2) < 0)
- error("dup2 stderr: %s", strerror(errno));
-
- /* Close the extra descriptor for the pseudo tty. */
- close(ttyfd);
-
- /* record login, etc. similar to login(1) */
- do_login(s, command);
-
- /*
- * Close the pipe to the parent so it can re-enter its event
- * loop and service the ptm; if enough debug messages get
- * written to the pty before this happens there will be a
- * deadlock.
- */
- close(pipe_fds[1]);
-
- /*
- * do_motd() was called originally in do_login(). However,
- * when the /etc/motd file is large, a deadlock would happen,
- * because
- * - The child is blocked at fputs() to pty, when pty buffer
- * is full.
- * - The parent can not consume the pty buffer, because it is
- * still blocked at read(pipe_fds[0]).
- *
- * To resolve the deadlock issue, we defer do_motd() after
- * close(pipe_fds[1]).
- */
- do_motd();
-
- /* Do common processing for the child, such as execing the command. */
- do_child(s, command);
- /* NOTREACHED */
- }
-
- /* Wait for child to exec() or exit() */
- (void) close(pipe_fds[1]);
- (void) read(pipe_fds[0], &pipe_fds[1], sizeof(int));
-
-#ifdef _UNICOS
- signal(WJSIGNAL, cray_job_termination_handler);
-#endif /* _UNICOS */
-#ifdef HAVE_CYGWIN
- if (is_winnt)
- cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
-#endif
- if (pid < 0)
- packet_disconnect("fork failed: %.100s", strerror(errno));
- s->pid = pid;
-
- /* Parent. Close the slave side of the pseudo tty. */
- close(ttyfd);
-
- /*
- * Create another descriptor of the pty master side for use as the
- * standard input. We could use the original descriptor, but this
- * simplifies code in server_loop. The descriptor is bidirectional.
- */
- fdout = dup(ptyfd);
- if (fdout < 0)
- packet_disconnect("dup #1 failed: %.100s", strerror(errno));
-
- /* we keep a reference to the pty master */
- ptymaster = dup(ptyfd);
- if (ptymaster < 0)
- packet_disconnect("dup #2 failed: %.100s", strerror(errno));
- s->ptymaster = ptymaster;
-
- /* Enter interactive session. */
- packet_set_interactive(1);
- if (compat20) {
- session_set_fds(s, ptyfd, fdout, -1);
- /* Don't close channel before sending exit-status! */
- channel_set_wait_for_exit(s->chanid, 1);
- } else {
- server_loop(pid, ptyfd, fdout, -1);
- /* server_loop _has_ closed ptyfd and fdout. */
- }
-}
-
-/*
- * This is called to fork and execute a command. If another command is
- * to be forced, execute that instead.
- */
-void
-do_exec(Session *s, const char *command)
-{
- if (command)
- s->command = xstrdup(command);
-
- if (forced_command) {
- original_command = command;
- command = forced_command;
- debug("Forced command '%.900s'", command);
- }
-
- if (s->ttyfd != -1)
- do_exec_pty(s, command);
- else
- do_exec_no_pty(s, command);
-
- original_command = NULL;
-}
-
-
-/* administrative, login(1)-like work */
-void
-do_login(Session *s, const char *command)
-{
- char *time_string;
-#ifndef ALTPRIVSEP
- struct passwd * pw = s->pw;
-#endif /* ALTPRIVSEP*/
- pid_t pid = getpid();
-
- /* Record that there was a login on that tty from the remote host. */
-#ifdef ALTPRIVSEP
- debug3("Recording SSHv2 channel login in utmpx/wtmpx");
- altprivsep_record_login(pid, s->tty);
-#endif /* ALTPRIVSEP*/
-
- if (check_quietlogin(s, command))
- return;
-
-#ifdef USE_PAM
- print_pam_messages();
-#endif /* USE_PAM */
-#ifdef WITH_AIXAUTHENTICATE
- if (aixloginmsg && *aixloginmsg)
- printf("%s\n", aixloginmsg);
-#endif /* WITH_AIXAUTHENTICATE */
-
-#ifndef NO_SSH_LASTLOG
- if (options.print_lastlog && s->last_login_time != 0) {
- time_string = ctime(&s->last_login_time);
- if (strchr(time_string, '\n'))
- *strchr(time_string, '\n') = 0;
- if (strcmp(s->hostname, "") == 0)
- printf("Last login: %s\r\n", time_string);
- else
- printf("Last login: %s from %s\r\n", time_string,
- s->hostname);
- }
-#endif /* NO_SSH_LASTLOG */
-
-}
-
-/*
- * Display the message of the day.
- */
-void
-do_motd(void)
-{
- FILE *f;
- char buf[256];
-
- if (options.print_motd) {
-#ifdef HAVE_LOGIN_CAP
- f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
- "/etc/motd"), "r");
-#else
- f = fopen("/etc/motd", "r");
-#endif
- if (f) {
- while (fgets(buf, sizeof(buf), f))
- fputs(buf, stdout);
- fclose(f);
- }
- }
-}
-
-
-/*
- * Check for quiet login, either .hushlogin or command given.
- */
-int
-check_quietlogin(Session *s, const char *command)
-{
- char buf[256];
- struct passwd *pw = s->pw;
- struct stat st;
-
- /* Return 1 if .hushlogin exists or a command given. */
- if (command != NULL)
- return 1;
- snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
-#ifdef HAVE_LOGIN_CAP
- if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
- return 1;
-#else
- if (stat(buf, &st) >= 0)
- return 1;
-#endif
- return 0;
-}
-
-/*
- * Sets the value of the given variable in the environment. If the variable
- * already exists, its value is overriden.
- */
-void
-child_set_env(char ***envp, u_int *envsizep, const char *name,
- const char *value)
-{
- debug3("child_set_env(%s, %s)", name, value);
- child_set_env_silent(envp, envsizep, name, value);
-}
-
-
-void
-child_set_env_silent(char ***envp, u_int *envsizep, const char *name,
- const char *value)
-{
- u_int i, namelen;
- char **env;
-
- /*
- * Find the slot where the value should be stored. If the variable
- * already exists, we reuse the slot; otherwise we append a new slot
- * at the end of the array, expanding if necessary.
- */
- env = *envp;
- namelen = strlen(name);
- for (i = 0; env[i]; i++)
- if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
- break;
- if (env[i]) {
- /* Reuse the slot. */
- xfree(env[i]);
- } else {
- /* New variable. Expand if necessary. */
- if (i >= (*envsizep) - 1) {
- if (*envsizep >= 1000)
- fatal("child_set_env: too many env vars,"
- " skipping: %.100s", name);
- (*envsizep) += 50;
- env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
- }
- /* Need to set the NULL pointer at end of array beyond the new slot. */
- env[i + 1] = NULL;
- }
-
- /* Allocate space and format the variable in the appropriate slot. */
- env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
- snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
-}
-
-/*
- * Reads environment variables from the given file and adds/overrides them
- * into the environment. If the file does not exist, this does nothing.
- * Otherwise, it must consist of empty lines, comments (line starts with '#')
- * and assignments of the form name=value. No other forms are allowed.
- */
-static void
-read_environment_file(char ***env, u_int *envsize,
- const char *filename)
-{
- FILE *f;
- char buf[4096];
- char *cp, *value;
- u_int lineno = 0;
-
- f = fopen(filename, "r");
- if (!f)
- return;
-
- while (fgets(buf, sizeof(buf), f)) {
- if (++lineno > 1000)
- fatal("Too many lines in environment file %s", filename);
- for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (!*cp || *cp == '#' || *cp == '\n')
- continue;
- if (strchr(cp, '\n'))
- *strchr(cp, '\n') = '\0';
- value = strchr(cp, '=');
- if (value == NULL) {
- fprintf(stderr, gettext("Bad line %u in %.100s\n"),
- lineno, filename);
- continue;
- }
- /*
- * Replace the equals sign by nul, and advance value to
- * the value string.
- */
- *value = '\0';
- value++;
- child_set_env(env, envsize, cp, value);
- }
- fclose(f);
-}
-
-void copy_environment(char **source, char ***env, u_int *envsize)
-{
- char *var_name, *var_val;
- int i;
-
- if (source == NULL)
- return;
-
- for(i = 0; source[i] != NULL; i++) {
- var_name = xstrdup(source[i]);
- if ((var_val = strstr(var_name, "=")) == NULL) {
- xfree(var_name);
- continue;
- }
- *var_val++ = '\0';
-
- debug3("Copy environment: %s=%s", var_name, var_val);
- child_set_env(env, envsize, var_name, var_val);
-
- xfree(var_name);
- }
-}
-
-#ifdef HAVE_DEFOPEN
-static
-void
-deflt_do_setup_env(Session *s, const char *shell, char ***env, u_int *envsize)
-{
- int flags;
- char *ptr;
- mode_t Umask = 022;
-
- if (defopen(_PATH_DEFAULT_LOGIN))
- return;
-
- /* Ignore case */
- flags = defcntl(DC_GETFLAGS, 0);
- TURNOFF(flags, DC_CASE);
- (void) defcntl(DC_SETFLAGS, flags);
-
- /* TZ & HZ */
- if ((ptr = defread("TIMEZONE=")) != NULL)
- child_set_env(env, envsize, "TZ", ptr);
- if ((ptr = defread("HZ=")) != NULL)
- child_set_env(env, envsize, "HZ", ptr);
-
- /* PATH */
- if (s->pw->pw_uid != 0 && (ptr = defread("PATH=")) != NULL)
- child_set_env(env, envsize, "PATH", ptr);
- if (s->pw->pw_uid == 0 && (ptr = defread("SUPATH=")) != NULL)
- child_set_env(env, envsize, "PATH", ptr);
-
- /* SHELL */
- if ((ptr = defread("ALTSHELL=")) != NULL) {
- if (strcasecmp("YES", ptr) == 0)
- child_set_env(env, envsize, "SHELL", shell);
- else
- child_set_env(env, envsize, "SHELL", "");
- }
-
- /* UMASK */
- if ((ptr = defread("UMASK=")) != NULL &&
- sscanf(ptr, "%lo", &Umask) == 1 &&
- Umask <= (mode_t)0777)
- (void) umask(Umask);
- else
- (void) umask(022);
-
- /* ULIMIT */
- if ((ptr = defread("ULIMIT=")) != NULL && atol(ptr) > 0L &&
- ulimit(UL_SETFSIZE, atol(ptr)) < 0L)
- error("Could not set ULIMIT to %ld from %s\n", atol(ptr),
- _PATH_DEFAULT_LOGIN);
-
- (void) defopen(NULL);
-}
-#endif /* HAVE_DEFOPEN */
-
-static char **
-do_setup_env(Session *s, const char *shell)
-{
- char buf[256];
- char path_maildir[] = _PATH_MAILDIR;
- u_int i, envsize, pm_len;
- char **env;
- struct passwd *pw = s->pw;
-
- /* Initialize the environment. */
- envsize = 100;
- env = xmalloc(envsize * sizeof(char *));
- env[0] = NULL;
-
-#ifdef HAVE_CYGWIN
- /*
- * The Windows environment contains some setting which are
- * important for a running system. They must not be dropped.
- */
- copy_environment(environ, &env, &envsize);
-#endif
-
-#ifdef GSSAPI
- /* Allow any GSSAPI methods that we've used to alter
- * the childs environment as they see fit
- */
- ssh_gssapi_do_child(xxx_gssctxt, &env,&envsize);
-#endif
-
- /* Set basic environment. */
- child_set_env(&env, &envsize, "USER", pw->pw_name);
- child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
- child_set_env(&env, &envsize, "HOME", pw->pw_dir);
-#ifdef HAVE_LOGIN_CAP
- if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0)
- child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
- else
- child_set_env(&env, &envsize, "PATH", getenv("PATH"));
-#else /* HAVE_LOGIN_CAP */
-# ifndef HAVE_CYGWIN
- /*
- * There's no standard path on Windows. The path contains
- * important components pointing to the system directories,
- * needed for loading shared libraries. So the path better
- * remains intact here.
- */
-# ifdef SUPERUSER_PATH
- child_set_env(&env, &envsize, "PATH",
- s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH);
-# else
- child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
-# endif /* SUPERUSER_PATH */
-# endif /* HAVE_CYGWIN */
-#endif /* HAVE_LOGIN_CAP */
-
- pm_len = strlen(path_maildir);
- if (path_maildir[pm_len - 1] == '/' && pm_len > 1)
- path_maildir[pm_len - 1] = NULL;
- snprintf(buf, sizeof buf, "%.200s/%.50s",
- path_maildir, pw->pw_name);
- child_set_env(&env, &envsize, "MAIL", buf);
-
- /* Normal systems set SHELL by default. */
- child_set_env(&env, &envsize, "SHELL", shell);
-
-#ifdef HAVE_DEFOPEN
- deflt_do_setup_env(s, shell, &env, &envsize);
-#endif /* HAVE_DEFOPEN */
-
-#define PASS_ENV(x) \
- if (getenv(x)) \
- child_set_env(&env, &envsize, x, getenv(x));
-
- if (getenv("TZ"))
- child_set_env(&env, &envsize, "TZ", getenv("TZ"));
-
- if (s->auth_file != NULL)
- child_set_env(&env, &envsize, "XAUTHORITY", s->auth_file);
-
- PASS_ENV("LANG")
- PASS_ENV("LC_ALL")
- PASS_ENV("LC_CTYPE")
- PASS_ENV("LC_COLLATE")
- PASS_ENV("LC_TIME")
- PASS_ENV("LC_NUMERIC")
- PASS_ENV("LC_MONETARY")
- PASS_ENV("LC_MESSAGES")
-
-#undef PASS_ENV
-
- if (s->env != NULL)
- copy_environment(s->env, &env, &envsize);
-
- /* Set custom environment options from RSA authentication. */
- while (custom_environment) {
- struct envstring *ce = custom_environment;
- char *str = ce->s;
-
- for (i = 0; str[i] != '=' && str[i]; i++)
- ;
- if (str[i] == '=') {
- str[i] = 0;
- child_set_env(&env, &envsize, str, str + i + 1);
- }
- custom_environment = ce->next;
- xfree(ce->s);
- xfree(ce);
- }
-
- /* SSH_CLIENT deprecated */
- snprintf(buf, sizeof buf, "%.50s %d %d",
- get_remote_ipaddr(), get_remote_port(), get_local_port());
- child_set_env(&env, &envsize, "SSH_CLIENT", buf);
-
- snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
- get_remote_ipaddr(), get_remote_port(),
- get_local_ipaddr(packet_get_connection_in()), get_local_port());
- child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
-
- if (s->ttyfd != -1)
- child_set_env(&env, &envsize, "SSH_TTY", s->tty);
- if (s->term)
- child_set_env(&env, &envsize, "TERM", s->term);
- if (s->display)
- child_set_env(&env, &envsize, "DISPLAY", s->display);
- if (original_command)
- child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
- original_command);
-
-#ifdef _UNICOS
- if (cray_tmpdir[0] != '\0')
- child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir);
-#endif /* _UNICOS */
-
-#ifdef _AIX
- {
- char *cp;
-
- if ((cp = getenv("AUTHSTATE")) != NULL)
- child_set_env(&env, &envsize, "AUTHSTATE", cp);
- if ((cp = getenv("KRB5CCNAME")) != NULL)
- child_set_env(&env, &envsize, "KRB5CCNAME", cp);
- read_environment_file(&env, &envsize, "/etc/environment");
- }
-#endif
-#ifdef KRB4
- if (s->authctxt->krb4_ticket_file)
- child_set_env(&env, &envsize, "KRBTKFILE",
- s->authctxt->krb4_ticket_file);
-#endif
-#ifdef KRB5
- if (s->authctxt->krb5_ticket_file)
- child_set_env(&env, &envsize, "KRB5CCNAME",
- s->authctxt->krb5_ticket_file);
-#endif
-#ifdef USE_PAM
- /*
- * Pull in any environment variables that may have
- * been set by PAM.
- */
- {
- char **p;
-
- p = fetch_pam_environment(s->authctxt);
- copy_environment(p, &env, &envsize);
- free_pam_environment(p);
- }
-#endif /* USE_PAM */
-
- if (auth_sock_name != NULL)
- child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
- auth_sock_name);
-
- /* read $HOME/.ssh/environment. */
- if (options.permit_user_env) {
- snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
- strcmp(pw->pw_dir, "/") ? pw->pw_dir : "");
- read_environment_file(&env, &envsize, buf);
- }
- if (debug_flag) {
- /* dump the environment */
- fprintf(stderr, gettext("Environment:\n"));
- for (i = 0; env[i]; i++)
- fprintf(stderr, " %.200s\n", env[i]);
- }
- return env;
-}
-
-/*
- * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
- * first in this order).
- */
-static void
-do_rc_files(Session *s, const char *shell)
-{
- FILE *f = NULL;
- char cmd[1024];
- int do_xauth;
- struct stat st;
-
- do_xauth =
- s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
-
- /* ignore _PATH_SSH_USER_RC for subsystems */
- if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
- snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
- shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
- if (debug_flag)
- fprintf(stderr, "Running %s\n", cmd);
- f = popen(cmd, "w");
- if (f) {
- if (do_xauth)
- fprintf(f, "%s %s\n", s->auth_proto,
- s->auth_data);
- pclose(f);
- } else
- fprintf(stderr, "Could not run %s\n",
- _PATH_SSH_USER_RC);
- } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
- if (debug_flag)
- fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
- _PATH_SSH_SYSTEM_RC);
- f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
- if (f) {
- if (do_xauth)
- fprintf(f, "%s %s\n", s->auth_proto,
- s->auth_data);
- pclose(f);
- } else
- fprintf(stderr, "Could not run %s\n",
- _PATH_SSH_SYSTEM_RC);
- } else if (do_xauth && options.xauth_location != NULL) {
- /* Add authority data to .Xauthority if appropriate. */
- if (debug_flag) {
- fprintf(stderr,
- "Running %.500s add "
- "%.100s %.100s %.100s\n",
- options.xauth_location, s->auth_display,
- s->auth_proto, s->auth_data);
- }
- snprintf(cmd, sizeof cmd, "%s -q -",
- options.xauth_location);
- f = popen(cmd, "w");
- if (f) {
- fprintf(f, "add %s %s %s\n",
- s->auth_display, s->auth_proto,
- s->auth_data);
- pclose(f);
- } else {
- fprintf(stderr, "Could not run %s\n",
- cmd);
- }
- }
-}
-
-/* Disallow logins if /etc/nologin exists. This does not apply to root. */
-static void
-do_nologin(struct passwd *pw)
-{
- FILE *f = NULL;
- char buf[1024];
- struct stat sb;
-
- if (pw->pw_uid == 0)
- return;
-
- if (stat(_PATH_NOLOGIN, &sb) == -1)
- return;
-
- /* /etc/nologin exists. Print its contents if we can and exit. */
- log("User %.100s not allowed because %s exists.", pw->pw_name,
- _PATH_NOLOGIN);
- if ((f = fopen(_PATH_NOLOGIN, "r")) != NULL) {
- while (fgets(buf, sizeof(buf), f))
- fputs(buf, stderr);
- fclose(f);
- }
- exit(254);
-}
-
-/* Chroot into ChrootDirectory if the option is set. */
-void
-chroot_if_needed(struct passwd *pw)
-{
- char *chroot_path, *tmp;
-
- if (chroot_requested(options.chroot_directory)) {
- tmp = tilde_expand_filename(options.chroot_directory,
- pw->pw_uid);
- chroot_path = percent_expand(tmp, "h", pw->pw_dir,
- "u", pw->pw_name, (char *)NULL);
- safely_chroot(chroot_path, pw->pw_uid);
- free(tmp);
- free(chroot_path);
- }
-}
-
-/*
- * Chroot into a directory after checking it for safety: all path components
- * must be root-owned directories with strict permissions.
- */
-static void
-safely_chroot(const char *path, uid_t uid)
-{
- const char *cp;
- char component[MAXPATHLEN];
- struct stat st;
-
- if (*path != '/')
- fatal("chroot path does not begin at root");
- if (strlen(path) >= sizeof(component))
- fatal("chroot path too long");
-
- /*
- * Descend the path, checking that each component is a
- * root-owned directory with strict permissions.
- */
- for (cp = path; cp != NULL;) {
- if ((cp = strchr(cp, '/')) == NULL)
- strlcpy(component, path, sizeof(component));
- else {
- cp++;
- memcpy(component, path, cp - path);
- component[cp - path] = '\0';
- }
-
- debug3("%s: checking '%s'", __func__, component);
-
- if (stat(component, &st) != 0)
- fatal("%s: stat(\"%s\"): %s", __func__,
- component, strerror(errno));
- if (st.st_uid != 0 || (st.st_mode & 022) != 0)
- fatal("bad ownership or modes for chroot "
- "directory %s\"%s\"",
- cp == NULL ? "" : "component ", component);
- if (!S_ISDIR(st.st_mode))
- fatal("chroot path %s\"%s\" is not a directory",
- cp == NULL ? "" : "component ", component);
- }
-
- if (chdir(path) == -1)
- fatal("Unable to chdir to chroot path \"%s\": "
- "%s", path, strerror(errno));
- if (chroot(path) == -1)
- fatal("chroot(\"%s\"): %s", path, strerror(errno));
- if (chdir("/") == -1)
- fatal("%s: chdir(/) after chroot: %s",
- __func__, strerror(errno));
- verbose("Changed root directory to \"%s\"", path);
-}
-
-static void
-launch_login(struct passwd *pw, const char *hostname)
-{
- /* Launch login(1). */
-
- execl(LOGIN_PROGRAM, "login", "-h", hostname,
-#ifdef xxxLOGIN_NEEDS_TERM
- (s->term ? s->term : "unknown"),
-#endif /* LOGIN_NEEDS_TERM */
-#ifdef LOGIN_NO_ENDOPT
- "-p", "-f", pw->pw_name, (char *)NULL);
-#else
- "-p", "-f", "--", pw->pw_name, (char *)NULL);
-#endif
-
- /* Login couldn't be executed, die. */
-
- perror("login");
- exit(1);
-}
-
-/*
- * Performs common processing for the child, such as setting up the
- * environment, closing extra file descriptors, setting the user and group
- * ids, and executing the command or shell.
- */
-#define ARGV_MAX 10
-void
-do_child(Session *s, const char *command)
-{
- extern char **environ;
- char **env;
- char *argv[ARGV_MAX];
- const char *shell, *shell0;
- struct passwd *pw = s->pw;
-
- /* remove hostkey from the child's memory */
- destroy_sensitive_data();
-
- do_nologin(pw);
- chroot_if_needed(pw);
-
- /*
- * Get the shell from the password data. An empty shell field is
- * legal, and means /bin/sh.
- */
- shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
-#ifdef HAVE_LOGIN_CAP
- shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
-#endif
-
- env = do_setup_env(s, shell);
-
- /*
- * Close the connection descriptors; note that this is the child, and
- * the server will still have the socket open, and it is important
- * that we do not shutdown it. Note that the descriptors cannot be
- * closed before building the environment, as we call
- * get_remote_ipaddr there.
- */
- if (packet_get_connection_in() == packet_get_connection_out())
- close(packet_get_connection_in());
- else {
- close(packet_get_connection_in());
- close(packet_get_connection_out());
- }
- /*
- * Close all descriptors related to channels. They will still remain
- * open in the parent.
- */
- /* XXX better use close-on-exec? -markus */
- channel_close_all();
-
- /*
- * Close any extra file descriptors. Note that there may still be
- * descriptors left by system functions. They will be closed later.
- */
- endpwent();
-
- /*
- * Must switch to the new environment variables so that .ssh/rc,
- * /etc/ssh/sshrc, and xauth are run in the proper environment.
- */
- environ = env;
-
- /*
- * New environment has been installed. We need to update locale
- * so that error messages beyond this point have the proper
- * character encoding.
- */
- (void) setlocale(LC_ALL, "");
-
- /*
- * Close any extra open file descriptors so that we don\'t have them
- * hanging around in clients. Note that we want to do this after
- * initgroups, because at least on Solaris 2.3 it leaves file
- * descriptors open.
- */
- closefrom(STDERR_FILENO + 1);
-
-#ifdef AFS
- /* Try to get AFS tokens for the local cell. */
- if (k_hasafs()) {
- char cell[64];
-
- if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
- krb_afslog(cell, 0);
-
- krb_afslog(0, 0);
- }
-#endif /* AFS */
-
- /* Change current directory to the user's home directory. */
- if (chdir(pw->pw_dir) < 0) {
- /* Suppress missing homedir warning for chroot case */
- if (!chroot_requested(options.chroot_directory))
- fprintf(stderr, "Could not chdir to home "
- "directory %s: %s\n", pw->pw_dir,
- strerror(errno));
- }
-
- do_rc_files(s, shell);
-
- /* restore SIGPIPE for child */
- signal(SIGPIPE, SIG_DFL);
-
- if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
- int i;
- char *p, *args;
- extern int optind, optreset;
-
- /* This will set the E/P sets here, simulating exec(2). */
- drop_privs(pw->pw_uid);
-
- setproctitle("%s@internal-sftp-server", s->pw->pw_name);
- args = xstrdup(command ? command : "sftp-server");
-
- i = 0;
- for ((p = strtok(args, " ")); p != NULL; (p = strtok(NULL, " "))) {
- if (i < ARGV_MAX - 1)
- argv[i++] = p;
- }
-
- argv[i] = NULL;
- optind = optreset = 1;
- __progname = argv[0];
- exit(sftp_server_main(i, argv, s->pw));
- }
-
- /* Get the last component of the shell name. */
- if ((shell0 = strrchr(shell, '/')) != NULL)
- shell0++;
- else
- shell0 = shell;
-
- /*
- * If we have no command, execute the shell. In this case, the shell
- * name to be passed in argv[0] is preceded by '-' to indicate that
- * this is a login shell.
- */
- if (!command) {
- char argv0[256];
-
- /* Start the shell. Set initial character to '-'. */
- argv0[0] = '-';
-
- if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
- >= sizeof(argv0) - 1) {
- errno = EINVAL;
- perror(shell);
- exit(1);
- }
-
- /* Execute the shell. */
- argv[0] = argv0;
- argv[1] = NULL;
- execve(shell, argv, env);
-
- /* Executing the shell failed. */
- perror(shell);
- exit(1);
- }
- /*
- * Execute the command using the user's shell. This uses the -c
- * option to execute the command.
- */
- argv[0] = (char *) shell0;
- argv[1] = "-c";
- argv[2] = (char *) command;
- argv[3] = NULL;
- execve(shell, argv, env);
- perror(shell);
- exit(1);
-}
-
-Session *
-session_new(void)
-{
- int i;
- static int did_init = 0;
- if (!did_init) {
- debug("session_new: init");
- for (i = 0; i < MAX_SESSIONS; i++) {
- sessions[i].used = 0;
- }
- did_init = 1;
- }
- for (i = 0; i < MAX_SESSIONS; i++) {
- Session *s = &sessions[i];
- if (! s->used) {
- memset(s, 0, sizeof(*s));
- s->chanid = -1;
- s->ptyfd = -1;
- s->ttyfd = -1;
- s->used = 1;
- s->self = i;
- s->env = NULL;
- debug("session_new: session %d", i);
- return s;
- }
- }
- return NULL;
-}
-
-static void
-session_dump(void)
-{
- int i;
- for (i = 0; i < MAX_SESSIONS; i++) {
- Session *s = &sessions[i];
- debug("dump: used %d session %d %p channel %d pid %ld",
- s->used,
- s->self,
- s,
- s->chanid,
- (long)s->pid);
- }
-}
-
-int
-session_open(Authctxt *authctxt, int chanid)
-{
- Session *s = session_new();
- debug("session_open: channel %d", chanid);
- if (s == NULL) {
- error("no more sessions");
- return 0;
- }
- s->authctxt = authctxt;
- s->pw = authctxt->pw;
- if (s->pw == NULL)
- fatal("no user for session %d", s->self);
- debug("session_open: session %d: link with channel %d", s->self, chanid);
- s->chanid = chanid;
- return 1;
-}
-
-#ifndef lint
-Session *
-session_by_tty(char *tty)
-{
- int i;
- for (i = 0; i < MAX_SESSIONS; i++) {
- Session *s = &sessions[i];
- if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
- debug("session_by_tty: session %d tty %s", i, tty);
- return s;
- }
- }
- debug("session_by_tty: unknown tty %.100s", tty);
- session_dump();
- return NULL;
-}
-#endif /* lint */
-
-static Session *
-session_by_channel(int id)
-{
- int i;
- for (i = 0; i < MAX_SESSIONS; i++) {
- Session *s = &sessions[i];
- if (s->used && s->chanid == id) {
- debug("session_by_channel: session %d channel %d", i, id);
- return s;
- }
- }
- debug("session_by_channel: unknown channel %d", id);
- session_dump();
- return NULL;
-}
-
-static Session *
-session_by_pid(pid_t pid)
-{
- int i;
- debug("session_by_pid: pid %ld", (long)pid);
- for (i = 0; i < MAX_SESSIONS; i++) {
- Session *s = &sessions[i];
- if (s->used && s->pid == pid)
- return s;
- }
- error("session_by_pid: unknown pid %ld", (long)pid);
- session_dump();
- return NULL;
-}
-
-static int
-session_window_change_req(Session *s)
-{
- s->col = packet_get_int();
- s->row = packet_get_int();
- s->xpixel = packet_get_int();
- s->ypixel = packet_get_int();
- packet_check_eom();
- pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
- return 1;
-}
-
-static int
-session_pty_req(Session *s)
-{
- u_int len;
- int n_bytes;
-
- if (no_pty_flag) {
- debug("Allocating a pty not permitted for this authentication.");
- return 0;
- }
- if (s->ttyfd != -1) {
- packet_disconnect("Protocol error: you already have a pty.");
- return 0;
- }
- /* Get the time and hostname when the user last logged in. */
- if (options.print_lastlog) {
- s->hostname[0] = '\0';
- s->last_login_time = get_last_login_time(s->pw->pw_uid,
- s->pw->pw_name, s->hostname, sizeof(s->hostname));
-
- /*
- * PAM may update the last login date.
- *
- * Ideally PAM would also show the last login date as a
- * PAM_TEXT_INFO conversation message, and then we could just
- * always force the use of keyboard-interactive just so we can
- * pass any such PAM prompts and messages from the account and
- * session stacks, but skip pam_authenticate() if other userauth
- * has succeeded and the user's password isn't expired.
- *
- * Unfortunately this depends on support for keyboard-
- * interactive in the client, and support for lastlog messages
- * in some PAM module.
- *
- * As it is Solaris updates the lastlog in PAM, but does
- * not show the lastlog date in PAM. If and when this state of
- * affairs changes this hack can be reconsidered, and, maybe,
- * removed.
- *
- * So we're stuck with a crude hack: get the lastlog
- * time before calling pam_open_session() and store it
- * in the Authctxt and then use it here once. After
- * that, if the client opens any more pty sessions we'll
- * show the last lastlog entry since userauth.
- */
- if (s->authctxt != NULL && s->authctxt->last_login_time > 0) {
- s->last_login_time = s->authctxt->last_login_time;
- (void) strlcpy(s->hostname,
- s->authctxt->last_login_host,
- sizeof(s->hostname));
- s->authctxt->last_login_time = 0;
- s->authctxt->last_login_host[0] = '\0';
- }
- }
-
- s->term = packet_get_string(&len);
-
- if (compat20) {
- s->col = packet_get_int();
- s->row = packet_get_int();
- } else {
- s->row = packet_get_int();
- s->col = packet_get_int();
- }
- s->xpixel = packet_get_int();
- s->ypixel = packet_get_int();
-
- if (strcmp(s->term, "") == 0) {
- xfree(s->term);
- s->term = NULL;
- }
-
- /* Allocate a pty and open it. */
- debug("Allocating pty.");
- if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
- if (s->term)
- xfree(s->term);
- s->term = NULL;
- s->ptyfd = -1;
- s->ttyfd = -1;
- error("session_pty_req: session %d alloc failed", s->self);
- return 0;
- }
- debug("session_pty_req: session %d alloc %s", s->self, s->tty);
-
- /* for SSH1 the tty modes length is not given */
- if (!compat20)
- n_bytes = packet_remaining();
- tty_parse_modes(s->ttyfd, &n_bytes);
-
- /*
- * Add a cleanup function to clear the utmp entry and record logout
- * time in case we call fatal() (e.g., the connection gets closed).
- */
- fatal_add_cleanup(session_pty_cleanup, (void *)s);
- pty_setowner(s->pw, s->tty);
-
- /* Set window size from the packet. */
- pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
-
- packet_check_eom();
- session_proctitle(s);
- return 1;
-}
-
-static int
-session_subsystem_req(Session *s)
-{
- struct stat st;
- u_int len;
- int success = 0;
- char *prog, *cmd, *subsys = packet_get_string(&len);
- u_int i;
-
- packet_check_eom();
- log("subsystem request for %.100s", subsys);
-
- for (i = 0; i < options.num_subsystems; i++) {
- if (strcmp(subsys, options.subsystem_name[i]) == 0) {
- prog = options.subsystem_command[i];
- cmd = options.subsystem_args[i];
- if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
- s->is_subsystem = SUBSYSTEM_INT_SFTP;
- /*
- * We must stat(2) the subsystem before we chroot in
- * order to be able to send a proper error message.
- */
- } else if (chroot_requested(options.chroot_directory)) {
- char chdirsub[MAXPATHLEN];
-
- strlcpy(chdirsub, options.chroot_directory,
- sizeof (chdirsub));
- strlcat(chdirsub, "/", sizeof (chdirsub));
- strlcat(chdirsub, prog, sizeof (chdirsub));
- if (stat(chdirsub, &st) < 0) {
- error("subsystem: cannot stat %s under "
- "chroot directory %s: %s", prog,
- options.chroot_directory,
- strerror(errno));
- if (strcmp(subsys, "sftp") == 0)
- error("subsystem: please see "
- "the Subsystem option in "
- "sshd_config(4) for an "
- "explanation of '%s'.",
- INTERNAL_SFTP_NAME);
- break;
- }
- } else if (stat(prog, &st) < 0) {
- error("subsystem: cannot stat %s: %s", prog,
- strerror(errno));
- break;
- } else {
- s->is_subsystem = SUBSYSTEM_EXT;
- }
- debug("subsystem: exec() %s", cmd);
- do_exec(s, cmd);
- success = 1;
- break;
- }
- }
-
- if (!success)
- log("subsystem request for %.100s failed, subsystem not found",
- subsys);
-
- xfree(subsys);
- return success;
-}
-
-/*
- * Serve "x11-req" channel request for X11 forwarding for the current session
- * channel.
- */
-static int
-session_x11_req(Session *s)
-{
- int success, fd;
- char xauthdir[] = "/tmp/ssh-xauth-XXXXXX";
-
- s->single_connection = packet_get_char();
- s->auth_proto = packet_get_string(NULL);
- s->auth_data = packet_get_string(NULL);
- s->screen = packet_get_int();
- packet_check_eom();
-
- success = session_setup_x11fwd(s);
- if (!success) {
- xfree(s->auth_proto);
- xfree(s->auth_data);
- s->auth_proto = NULL;
- s->auth_data = NULL;
- return (success);
- }
-
- /*
- * Create per session X authority file so that different sessions
- * don't contend for one common file. The reason for this is that
- * xauth(1) locking doesn't work too well over network filesystems.
- *
- * If mkdtemp() or open() fails then s->auth_file remains NULL which
- * means that we won't set XAUTHORITY variable in child's environment
- * and xauth(1) will use the default location for the authority file.
- */
- if (mkdtemp(xauthdir) != NULL) {
- s->auth_file = xmalloc(MAXPATHLEN);
- snprintf(s->auth_file, MAXPATHLEN, "%s/xauthfile",
- xauthdir);
- /*
- * we don't want that "creating new authority file" message to
- * be printed by xauth(1) so we must create that file
- * beforehand.
- */
- if ((fd = open(s->auth_file, O_CREAT | O_EXCL | O_RDONLY,
- S_IRUSR | S_IWUSR)) == -1) {
- error("failed to create the temporary X authority "
- "file %s: %.100s; will use the default one",
- s->auth_file, strerror(errno));
- xfree(s->auth_file);
- s->auth_file = NULL;
- if (rmdir(xauthdir) == -1) {
- error("cannot remove xauth directory %s: %.100s",
- xauthdir, strerror(errno));
- }
- } else {
- close(fd);
- debug("temporary X authority file %s created",
- s->auth_file);
-
- /*
- * add a cleanup function to remove the temporary
- * xauth file in case we call fatal() (e.g., the
- * connection gets closed).
- */
- fatal_add_cleanup(session_xauthfile_cleanup, (void *)s);
- }
- }
- else {
- error("failed to create a directory for the temporary X "
- "authority file: %.100s; will use the default xauth file",
- strerror(errno));
- }
-
- return (success);
-}
-
-static int
-session_shell_req(Session *s)
-{
- packet_check_eom();
- do_exec(s, NULL);
- return 1;
-}
-
-static int
-session_exec_req(Session *s)
-{
- u_int len;
- char *command = packet_get_string(&len);
- packet_check_eom();
- do_exec(s, command);
- xfree(command);
- return 1;
-}
-
-static int
-session_auth_agent_req(Session *s)
-{
- static int called = 0;
- packet_check_eom();
- if (no_agent_forwarding_flag) {
- debug("session_auth_agent_req: no_agent_forwarding_flag");
- return 0;
- }
- if (called) {
- return 0;
- } else {
- called = 1;
- return auth_input_request_forwarding(s->pw);
- }
-}
-
-static int
-session_loc_env_check(char *var, char *val)
-{
- char *current;
- int cat, ret;
-
- if (strcmp(var, "LANG") == 0)
- cat = LC_ALL;
- else if (strcmp(var, "LC_ALL") == 0)
- cat = LC_ALL;
- else if (strcmp(var, "LC_CTYPE") == 0)
- cat = LC_CTYPE;
- else if (strcmp(var, "LC_COLLATE") == 0)
- cat = LC_COLLATE;
- else if (strcmp(var, "LC_TIME") == 0)
- cat = LC_TIME;
- else if (strcmp(var, "LC_NUMERIC") == 0)
- cat = LC_NUMERIC;
- else if (strcmp(var, "LC_MONETARY") == 0)
- cat = LC_MONETARY;
- else if (strcmp(var, "LC_MESSAGES") == 0)
- cat = LC_MESSAGES;
-
- current = setlocale(cat, NULL);
-
- ret = (setlocale(cat, val) != NULL);
- (void) setlocale(cat, current);
- return (ret);
-}
-
-static int
-session_env_req(Session *s)
-{
- Channel *c;
- char *var, *val, *e;
- char **p;
- size_t len;
- int ret = 0;
-
- /* Get var/val from the rest of this packet */
- var = packet_get_string(NULL);
- val = packet_get_string(NULL);
-
- /*
- * We'll need the channel ID for the packet_send_debug messages,
- * so get it now.
- */
- if ((c = channel_lookup(s->chanid)) == NULL)
- goto done; /* shouldn't happen! */
-
- debug2("Received request for environment variable %s=%s", var, val);
-
- /* For now allow only LANG and LC_* */
- if (strcmp(var, "LANG") != 0 && strncmp(var, "LC_", 3) != 0) {
- debug2("Rejecting request for environment variable %s", var);
- goto done;
- }
-
- if (!session_loc_env_check(var, val)) {
- packet_send_debug(gettext("Missing locale support for %s=%s"),
- var, val);
- goto done;
- }
-
- packet_send_debug(gettext("Channel %d set: %s=%s"), c->remote_id,
- var, val);
-
- /*
- * Always append new environment variables without regard to old
- * ones being overriden. The way these are actually added to
- * the environment of the session process later settings
- * override earlier ones; see copy_environment().
- */
- if (s->env == NULL) {
- char **env;
-
- env = xmalloc(sizeof (char **) * 2);
- memset(env, 0, sizeof (char **) * 2);
-
- s->env = env;
- p = env;
- } else {
- for (p = s->env; *p != NULL ; p++);
-
- s->env = xrealloc(s->env, (p - s->env + 2) * sizeof (char **));
-
- for (p = s->env; *p != NULL ; p++);
- }
-
- len = snprintf(NULL, 0, "%s=%s", var, val);
- e = xmalloc(len + 1);
- (void) snprintf(e, len + 1, "%s=%s", var, val);
-
- (*p++) = e;
- *p = NULL;
-
- ret = 1;
-
-done:
- xfree(var);
- xfree(val);
-
- return (ret);
-}
-
-static void
-session_free_env(char ***envp)
-{
- char **env, **p;
-
- if (envp == NULL || *envp == NULL)
- return;
-
- env = *envp;
-
- *envp = NULL;
-
- for (p = env; *p != NULL; p++)
- xfree(*p);
-
- xfree(env);
-}
-
-int
-session_input_channel_req(Channel *c, const char *rtype)
-{
- int success = 0;
- Session *s;
-
- if ((s = session_by_channel(c->self)) == NULL) {
- log("session_input_channel_req: no session %d req %.100s",
- c->self, rtype);
- return 0;
- }
- debug("session_input_channel_req: session %d req %s", s->self, rtype);
-
- /*
- * a session is in LARVAL state until a shell, a command
- * or a subsystem is executed
- */
- if (c->type == SSH_CHANNEL_LARVAL) {
- if (strcmp(rtype, "shell") == 0) {
- success = session_shell_req(s);
- } else if (strcmp(rtype, "exec") == 0) {
- success = session_exec_req(s);
- } else if (strcmp(rtype, "pty-req") == 0) {
- success = session_pty_req(s);
- } else if (strcmp(rtype, "x11-req") == 0) {
- success = session_x11_req(s);
- } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
- success = session_auth_agent_req(s);
- } else if (strcmp(rtype, "subsystem") == 0) {
- success = session_subsystem_req(s);
- } else if (strcmp(rtype, "env") == 0) {
- success = session_env_req(s);
- }
- }
- if (strcmp(rtype, "window-change") == 0) {
- success = session_window_change_req(s);
- }
- return success;
-}
-
-void
-session_set_fds(Session *s, int fdin, int fdout, int fderr)
-{
- if (!compat20)
- fatal("session_set_fds: called for proto != 2.0");
- /*
- * now that have a child and a pipe to the child,
- * we can activate our channel and register the fd's
- */
- if (s->chanid == -1)
- fatal("no channel for session %d", s->self);
- channel_set_fds(s->chanid,
- fdout, fdin, fderr,
- fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
- 1,
- CHAN_SES_WINDOW_DEFAULT);
-}
-
-/*
- * Function to perform pty cleanup. Also called if we get aborted abnormally
- * (e.g., due to a dropped connection).
- */
-void
-session_pty_cleanup2(void *session)
-{
- Session *s = session;
-
- if (s == NULL) {
- error("session_pty_cleanup: no session");
- return;
- }
- if (s->ttyfd == -1)
- return;
-
- debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
-
-#ifdef USE_PAM
- session_do_pam(s, 0);
-#endif /* USE_PAM */
-
- /* Record that the user has logged out. */
- if (s->pid != 0) {
- debug3("Recording SSHv2 channel logout in utmpx/wtmpx");
-#ifdef ALTPRIVSEP
- altprivsep_record_logout(s->pid);
-#endif /* ALTPRIVSEP */
- }
-
- /* Release the pseudo-tty. */
- if (getuid() == 0)
- pty_release(s->tty);
-
- /*
- * Close the server side of the socket pairs. We must do this after
- * the pty cleanup, so that another process doesn't get this pty
- * while we're still cleaning up.
- */
- if (close(s->ptymaster) < 0)
- error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno));
-
- /* unlink pty from session */
- s->ttyfd = -1;
-}
-
-void
-session_pty_cleanup(void *session)
-{
- session_pty_cleanup2(session);
-}
-
-/*
- * We use a different temporary X authority file per every session so we
- * should remove those files when fatal() is called.
- */
-void
-session_xauthfile_cleanup(void *session)
-{
- Session *s = session;
-
- if (s == NULL) {
- error("session_xauthfile_cleanup: no session");
- return;
- }
-
- debug("session_xauthfile_cleanup: session %d removing %s", s->self,
- s->auth_file);
-
- if (unlink(s->auth_file) == -1) {
- error("session_xauthfile_cleanup: cannot remove xauth file: "
- "%.100s", strerror(errno));
- return;
- }
-
- /* dirname() will modify s->auth_file but that's ok */
- if (rmdir(dirname(s->auth_file)) == -1) {
- error("session_xauthfile_cleanup: "
- "cannot remove xauth directory: %.100s", strerror(errno));
- return;
- }
-}
-
-static char *
-sig2name(int sig)
-{
-#define SSH_SIG(x) if (sig == SIG ## x) return #x
- SSH_SIG(ABRT);
- SSH_SIG(ALRM);
- SSH_SIG(FPE);
- SSH_SIG(HUP);
- SSH_SIG(ILL);
- SSH_SIG(INT);
- SSH_SIG(KILL);
- SSH_SIG(PIPE);
- SSH_SIG(QUIT);
- SSH_SIG(SEGV);
- SSH_SIG(TERM);
- SSH_SIG(USR1);
- SSH_SIG(USR2);
-#undef SSH_SIG
- return "SIG@openssh.com";
-}
-
-static void
-session_exit_message(Session *s, int status)
-{
- Channel *c;
-
- if ((c = channel_lookup(s->chanid)) == NULL)
- fatal("session_exit_message: session %d: no channel %d",
- s->self, s->chanid);
- debug("session_exit_message: session %d channel %d pid %ld",
- s->self, s->chanid, (long)s->pid);
-
- if (WIFEXITED(status)) {
- channel_request_start(s->chanid, "exit-status", 0);
- packet_put_int(WEXITSTATUS(status));
- packet_send();
- } else if (WIFSIGNALED(status)) {
- channel_request_start(s->chanid, "exit-signal", 0);
- packet_put_cstring(sig2name(WTERMSIG(status)));
-#ifdef WCOREDUMP
- packet_put_char(WCOREDUMP(status));
-#else /* WCOREDUMP */
- packet_put_char(0);
-#endif /* WCOREDUMP */
- packet_put_cstring("");
- packet_put_cstring("");
- packet_send();
- } else {
- /* Some weird exit cause. Just exit. */
- packet_disconnect("wait returned status %04x.", status);
- }
-
- /* Ok to close channel now */
- channel_set_wait_for_exit(s->chanid, 0);
-
- /* disconnect channel */
- debug("session_exit_message: release channel %d", s->chanid);
- channel_cancel_cleanup(s->chanid);
- /*
- * emulate a write failure with 'chan_write_failed', nobody will be
- * interested in data we write.
- * Note that we must not call 'chan_read_failed', since there could
- * be some more data waiting in the pipe.
- */
- if (c->ostate != CHAN_OUTPUT_CLOSED)
- chan_write_failed(c);
- s->chanid = -1;
-}
-
-void
-session_close(Session *s)
-{
- debug("session_close: session %d pid %ld", s->self, (long)s->pid);
- if (s->ttyfd != -1) {
- fatal_remove_cleanup(session_pty_cleanup, (void *)s);
- session_pty_cleanup(s);
- }
- if (s->auth_file != NULL) {
- fatal_remove_cleanup(session_xauthfile_cleanup, (void *)s);
- session_xauthfile_cleanup(s);
- xfree(s->auth_file);
- }
- if (s->term)
- xfree(s->term);
- if (s->display)
- xfree(s->display);
- if (s->auth_display)
- xfree(s->auth_display);
- if (s->auth_data)
- xfree(s->auth_data);
- if (s->auth_proto)
- xfree(s->auth_proto);
- if (s->command)
- xfree(s->command);
- session_free_env(&s->env);
- s->used = 0;
- session_proctitle(s);
-}
-
-void
-session_close_by_pid(pid_t pid, int status)
-{
- Session *s = session_by_pid(pid);
- if (s == NULL) {
- debug("session_close_by_pid: no session for pid %ld",
- (long)pid);
- return;
- }
- if (s->chanid != -1)
- session_exit_message(s, status);
- session_close(s);
-}
-
-/*
- * This is called when a channel dies before the session 'child' itself dies.
- * It can happen for example if we exit from an interactive shell before we
- * exit from forwarded X11 applications.
- */
-void
-session_close_by_channel(int id, void *arg)
-{
- Session *s = session_by_channel(id);
- if (s == NULL) {
- debug("session_close_by_channel: no session for id %d", id);
- return;
- }
- debug("session_close_by_channel: channel %d child %ld",
- id, (long)s->pid);
- if (s->pid != 0) {
- debug("session_close_by_channel: channel %d: has child", id);
- /*
- * delay detach of session, but release pty, since
- * the fd's to the child are already closed
- */
- if (s->ttyfd != -1) {
- fatal_remove_cleanup(session_pty_cleanup, (void *)s);
- session_pty_cleanup(s);
- }
- return;
- }
- /* detach by removing callback */
- channel_cancel_cleanup(s->chanid);
- s->chanid = -1;
- session_close(s);
-}
-
-void
-session_destroy_all(void (*closefunc)(Session *))
-{
- int i;
- for (i = 0; i < MAX_SESSIONS; i++) {
- Session *s = &sessions[i];
- if (s->used) {
- if (closefunc != NULL)
- closefunc(s);
- else
- session_close(s);
- }
- }
-}
-
-static char *
-session_tty_list(void)
-{
- static char buf[1024];
- int i;
- buf[0] = '\0';
- for (i = 0; i < MAX_SESSIONS; i++) {
- Session *s = &sessions[i];
- if (s->used && s->ttyfd != -1) {
- if (buf[0] != '\0')
- strlcat(buf, ",", sizeof buf);
- strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf);
- }
- }
- if (buf[0] == '\0')
- strlcpy(buf, "notty", sizeof buf);
- return buf;
-}
-
-void
-session_proctitle(Session *s)
-{
- if (s->pw == NULL)
- error("no user for session %d", s->self);
- else
- setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
-}
-
-int
-session_setup_x11fwd(Session *s)
-{
- struct stat st;
- char display[512], auth_display[512];
- char hostname[MAXHOSTNAMELEN];
-
- if (no_x11_forwarding_flag) {
- packet_send_debug("X11 forwarding disabled in user configuration file.");
- return 0;
- }
- if (!options.x11_forwarding) {
- debug("X11 forwarding disabled in server configuration file.");
- return 0;
- }
- if (!options.xauth_location ||
- (stat(options.xauth_location, &st) == -1)) {
- packet_send_debug("No xauth program; cannot forward with spoofing.");
- return 0;
- }
- if (s->display != NULL) {
- debug("X11 display already set.");
- return 0;
- }
- if (x11_create_display_inet(options.x11_display_offset,
- options.x11_use_localhost, s->single_connection,
- &s->display_number) == -1) {
- debug("x11_create_display_inet failed.");
- return 0;
- }
-
- /* Set up a suitable value for the DISPLAY variable. */
- if (gethostname(hostname, sizeof(hostname)) < 0)
- fatal("gethostname: %.100s", strerror(errno));
- /*
- * auth_display must be used as the displayname when the
- * authorization entry is added with xauth(1). This will be
- * different than the DISPLAY string for localhost displays.
- */
- if (options.x11_use_localhost) {
- snprintf(display, sizeof display, "localhost:%u.%u",
- s->display_number, s->screen);
- snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
- s->display_number, s->screen);
- s->display = xstrdup(display);
- s->auth_display = xstrdup(auth_display);
- } else {
-#ifdef IPADDR_IN_DISPLAY
- struct hostent *he;
- struct in_addr my_addr;
-
- he = gethostbyname(hostname);
- if (he == NULL) {
- error("Can't get IP address for X11 DISPLAY.");
- packet_send_debug("Can't get IP address for X11 DISPLAY.");
- return 0;
- }
- memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
- snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
- s->display_number, s->screen);
-#else
- snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
- s->display_number, s->screen);
-#endif
- s->display = xstrdup(display);
- s->auth_display = xstrdup(display);
- }
-
- return 1;
-}
-
-#ifdef USE_PAM
-int session_do_pam_conv(int, struct pam_message **,
- struct pam_response **, void *);
-
-static struct pam_conv session_pam_conv = {
- session_do_pam_conv,
- NULL
-};
-
-static void
-session_do_pam(Session *s, int do_open)
-{
- int pam_retval;
- char *where, *old_tty, *old_tty_copy = NULL;
- struct pam_conv old_conv, *old_conv_ptr;
-
- if (!s || !s->authctxt || !s->authctxt->pam || !s->authctxt->pam->h)
- return;
-
- /* Save current PAM item values */
- where = "getting PAM_CONV";
- pam_retval = pam_get_item(s->authctxt->pam->h, PAM_CONV,
- (void **) &old_conv_ptr);
- if (pam_retval != PAM_SUCCESS)
- goto done;
- old_conv = *old_conv_ptr;
-
- where = "getting PAM_TTY";
- pam_retval = pam_get_item(s->authctxt->pam->h, PAM_TTY,
- (void **) &old_tty);
- if (pam_retval != PAM_SUCCESS)
- goto done;
- old_tty_copy = xstrdup(old_tty);
-
- /* Change PAM_TTY and PAM_CONV items */
- where = "setting PAM_TTY";
- pam_retval = pam_set_item(s->authctxt->pam->h, PAM_TTY, s->tty);
- if (pam_retval != PAM_SUCCESS)
- goto done;
-
- where = "setting PAM_CONV";
- session_pam_conv.appdata_ptr = s;
- pam_retval = pam_set_item(s->authctxt->pam->h,
- PAM_CONV, &session_pam_conv);
- if (pam_retval != PAM_SUCCESS)
- goto done;
-
- /* Call pam_open/close_session() */
- if (do_open) {
- where = "calling pam_open_session()";
- pam_retval = pam_open_session(s->authctxt->pam->h, 0);
- }
- else {
- where = "calling pam_close_session()";
- pam_retval = pam_close_session(s->authctxt->pam->h, 0);
- }
-
- /* Reset PAM_TTY and PAM_CONV items to previous values */
- where = "setting PAM_TTY";
- pam_retval = pam_set_item(s->authctxt->pam->h, PAM_TTY, old_tty_copy);
- if (pam_retval != PAM_SUCCESS)
- goto done;
-
- where = "setting PAM_CONV";
- pam_retval = pam_set_item(s->authctxt->pam->h, PAM_CONV, &old_conv);
- if (pam_retval != PAM_SUCCESS)
- goto done;
-
- session_pam_conv.appdata_ptr = NULL;
-
-done:
- if (old_tty_copy)
- xfree(old_tty_copy);
-
- if (pam_retval == PAM_SUCCESS)
- return;
-
- /* fatal()? probably not... */
- log("PAM failed[%d] while %s: %s", pam_retval, where,
- PAM_STRERROR(s->authctxt->pam->h, pam_retval));
-}
-
-int
-session_do_pam_conv(int num_prompts,
- struct pam_message **prompts,
- struct pam_response **resp,
- void *app_data)
-{
- Session *s = (Session *) app_data;
-
- struct pam_response *reply;
- int count;
- char *prompt;
-
- if (channel_lookup(s->chanid) == NULL)
- return PAM_CONV_ERR;
-
- /* PAM will free this later */
- reply = xmalloc(num_prompts * sizeof(*reply));
-
- (void) memset(reply, 0, num_prompts * sizeof(*reply));
- for (count = 0; count < num_prompts; count++) {
- switch(PAM_MSG_MEMBER(prompts, count, msg_style)) {
- case PAM_TEXT_INFO:
- /* Write to stdout of channel */
- prompt = PAM_MSG_MEMBER(prompts, count, msg);
- if (prompt != NULL && s->ttyfd != -1) {
- debug2("session_do_pam_conv: text info "
- "prompt: %s", prompt);
- (void) write(s->ttyfd, prompt, strlen(prompt));
- (void) write(s->ttyfd, "\n", 1);
- }
- reply[count].resp = xstrdup("");
- reply[count].resp_retcode = PAM_SUCCESS;
- break;
- case PAM_ERROR_MSG:
- /* Write to stderr of channel */
- prompt = PAM_MSG_MEMBER(prompts, count, msg);
- if (prompt != NULL && s->ttyfd != -1) {
- debug2("session_do_pam_conv: error "
- "prompt: %s", prompt);
- (void) write(s->ttyfd, prompt, strlen(prompt));
- (void) write(s->ttyfd, "\n", 1);
- }
- reply[count].resp = xstrdup("");
- reply[count].resp_retcode = PAM_SUCCESS;
- break;
- case PAM_PROMPT_ECHO_ON:
- case PAM_PROMPT_ECHO_OFF:
- /*
- * XXX Someday add support for echo on/off prompts
- * here on sessions with ttys.
- */
- default:
- xfree(reply);
- return PAM_CONV_ERR;
- }
- }
-
- *resp = reply;
-
- return PAM_SUCCESS;
-}
-#endif /* USE_PAM */
-
-static void
-do_authenticated2(Authctxt *authctxt)
-{
- server_loop2(authctxt);
-}
-
-/*
- * Drop the privileges. We need this for the in-process SFTP server only. For
- * the shell and the external subsystem the exec(2) call will do the P = E = I
- * assignment itself. Never change the privileges if the connecting user is
- * root. See privileges(5) if the terminology used here is not known to you.
- */
-static void
-drop_privs(uid_t uid)
-{
- priv_set_t *priv_inherit;
-
- /* If root is connecting we are done. */
- if (uid == 0)
- return;
-
- if ((priv_inherit = priv_allocset()) == NULL)
- fatal("priv_allocset: %s", strerror(errno));
- if (getppriv(PRIV_INHERITABLE, priv_inherit) != 0)
- fatal("getppriv: %s", strerror(errno));
-
- /*
- * This will limit E as well. Note that before this P was a
- * superset of I, see permanently_set_uid().
- */
- if (setppriv(PRIV_SET, PRIV_PERMITTED, priv_inherit) == -1)
- fatal("setppriv: %s", strerror(errno));
-
- priv_freeset(priv_inherit);
-
- /*
- * By manipulating the P set above we entered a PA mode which we
- * do not need to retain in.
- */
- if (setpflags(PRIV_AWARE, 0) == -1)
- fatal("setpflags: %s", strerror(errno));
-}
diff --git a/usr/src/cmd/ssh/sshd/sshd.c b/usr/src/cmd/ssh/sshd/sshd.c
deleted file mode 100644
index 3be0890a8c..0000000000
--- a/usr/src/cmd/ssh/sshd/sshd.c
+++ /dev/null
@@ -1,2051 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * This program is the ssh daemon. It listens for connections from clients,
- * and performs authentication, executes use commands or shell, and forwards
- * information to/from the application to the user client over an encrypted
- * connection. This can also handle forwarding of X11, TCP/IP, and
- * authentication agent connections.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- *
- * SSH2 implementation:
- * Privilege Separation:
- *
- * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved.
- * Copyright (c) 2002 Niels Provos. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.260 2002/09/27 10:42:09 mickey Exp $");
-
-#include <openssl/dh.h>
-#include <openssl/bn.h>
-#include <openssl/md5.h>
-
-#include <openssl/rand.h>
-
-#include "ssh.h"
-#include "ssh1.h"
-#include "ssh2.h"
-#include "xmalloc.h"
-#include "rsa.h"
-#include "sshpty.h"
-#include "packet.h"
-#include "mpaux.h"
-#include "log.h"
-#include "servconf.h"
-#include "uidswap.h"
-#include "compat.h"
-#include "buffer.h"
-#include "cipher.h"
-#include "kex.h"
-#include "key.h"
-#include "dh.h"
-#include "myproposal.h"
-#include "authfile.h"
-#include "pathnames.h"
-#include "atomicio.h"
-#include "canohost.h"
-#include "auth.h"
-#include "misc.h"
-#include "dispatch.h"
-#include "channels.h"
-#include "session.h"
-#include "g11n.h"
-#include "sshlogin.h"
-#include "xlist.h"
-#include "engine.h"
-
-#ifdef HAVE_BSM
-#include "bsmaudit.h"
-#endif /* HAVE_BSM */
-
-#ifdef ALTPRIVSEP
-#include "altprivsep.h"
-#endif /* ALTPRIVSEP */
-
-#ifdef HAVE_SOLARIS_CONTRACTS
-#include <sys/ctfs.h>
-#include <sys/contract.h>
-#include <sys/contract/process.h>
-#include <libcontract.h>
-#endif /* HAVE_SOLARIS_CONTRACTS */
-
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif /* GSSAPI */
-
-#ifdef LIBWRAP
-#include <tcpd.h>
-#include <syslog.h>
-#ifndef lint
-int allow_severity = LOG_INFO;
-int deny_severity = LOG_WARNING;
-#endif /* lint */
-#endif /* LIBWRAP */
-
-#ifndef O_NOCTTY
-#define O_NOCTTY 0
-#endif
-
-#ifdef HAVE___PROGNAME
-extern char *__progname;
-#else
-char *__progname;
-#endif
-
-/* Server configuration options. */
-ServerOptions options;
-
-/* Name of the server configuration file. */
-static char *config_file_name = _PATH_SERVER_CONFIG_FILE;
-
-/*
- * Flag indicating whether IPv4 or IPv6. This can be set on the command line.
- * Default value is AF_UNSPEC means both IPv4 and IPv6.
- */
-#ifdef IPV4_DEFAULT
-int IPv4or6 = AF_INET;
-#else
-int IPv4or6 = AF_UNSPEC;
-#endif
-
-/*
- * Debug mode flag. This can be set on the command line. If debug
- * mode is enabled, extra debugging output will be sent to the system
- * log, the daemon will not go to background, and will exit after processing
- * the first connection.
- */
-int debug_flag = 0;
-
-/* Flag indicating that the daemon should only test the configuration and keys. */
-static int test_flag = 0;
-
-/* Flag indicating that the daemon is being started from inetd. */
-static int inetd_flag = 0;
-
-/* Flag indicating that sshd should not detach and become a daemon. */
-static int no_daemon_flag = 0;
-
-/* debug goes to stderr unless inetd_flag is set */
-int log_stderr = 0;
-
-/* Saved arguments to main(). */
-static char **saved_argv;
-static int saved_argc;
-
-/*
- * The sockets that the server is listening; this is used in the SIGHUP
- * signal handler.
- */
-#define MAX_LISTEN_SOCKS 16
-static int listen_socks[MAX_LISTEN_SOCKS];
-static int num_listen_socks = 0;
-
-/*
- * the client's version string, passed by sshd2 in compat mode. if != NULL,
- * sshd will skip the version-number exchange
- */
-static char *client_version_string = NULL;
-static char *server_version_string = NULL;
-
-/* for rekeying XXX fixme */
-Kex *xxx_kex;
-
-/*
- * Any really sensitive data in the application is contained in this
- * structure. The idea is that this structure could be locked into memory so
- * that the pages do not get written into swap. However, there are some
- * problems. The private key contains BIGNUMs, and we do not (in principle)
- * have access to the internals of them, and locking just the structure is
- * not very useful. Currently, memory locking is not implemented.
- */
-static struct {
- Key *server_key; /* ephemeral server key */
- Key *ssh1_host_key; /* ssh1 host key */
- Key **host_keys; /* all private host keys */
- int have_ssh1_key;
- int have_ssh2_key;
- u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH];
-} sensitive_data;
-
-/*
- * Flag indicating whether the RSA server key needs to be regenerated.
- * Is set in the SIGALRM handler and cleared when the key is regenerated.
- */
-static volatile sig_atomic_t key_do_regen = 0;
-
-/* This is set to true when a signal is received. */
-static volatile sig_atomic_t received_sighup = 0;
-static volatile sig_atomic_t received_sigterm = 0;
-
-/* session identifier, used by RSA-auth */
-u_char session_id[16];
-
-/* same for ssh2 */
-u_char *session_id2 = NULL;
-int session_id2_len = 0;
-
-/* record remote hostname or ip */
-u_int utmp_len = MAXHOSTNAMELEN;
-
-/* options.max_startup sized array of fd ints */
-static int *startup_pipes = NULL;
-static int startup_pipe = -1; /* in child */
-
-/* sshd_config buffer */
-Buffer cfg;
-
-#ifdef GSSAPI
-static gss_OID_set mechs = GSS_C_NULL_OID_SET;
-#endif /* GSSAPI */
-
-/* Prototypes for various functions defined later in this file. */
-void destroy_sensitive_data(void);
-static void demote_sensitive_data(void);
-
-static void do_ssh1_kex(void);
-static void do_ssh2_kex(void);
-
-/*
- * Close all listening sockets
- */
-static void
-close_listen_socks(void)
-{
- int i;
-
- for (i = 0; i < num_listen_socks; i++)
- (void) close(listen_socks[i]);
- num_listen_socks = -1;
-}
-
-static void
-close_startup_pipes(void)
-{
- int i;
-
- if (startup_pipes)
- for (i = 0; i < options.max_startups; i++)
- if (startup_pipes[i] != -1)
- (void) close(startup_pipes[i]);
-}
-
-/*
- * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
- * the effect is to reread the configuration file (and to regenerate
- * the server key).
- */
-static void
-sighup_handler(int sig)
-{
- int save_errno = errno;
-
- received_sighup = 1;
- (void) signal(SIGHUP, sighup_handler);
- errno = save_errno;
-}
-
-/*
- * Called from the main program after receiving SIGHUP.
- * Restarts the server.
- */
-static void
-sighup_restart(void)
-{
- log("Received SIGHUP; restarting.");
- close_listen_socks();
- close_startup_pipes();
- (void) execv(saved_argv[0], saved_argv);
- log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0],
- strerror(errno));
- exit(1);
-}
-
-/*
- * Generic signal handler for terminating signals in the master daemon.
- */
-static void
-sigterm_handler(int sig)
-{
- received_sigterm = sig;
-}
-
-/*
- * SIGCHLD handler. This is called whenever a child dies. This will then
- * reap any zombies left by exited children.
- */
-static void
-main_sigchld_handler(int sig)
-{
- int save_errno = errno;
- pid_t pid;
- int status;
-
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
- (pid < 0 && errno == EINTR))
- ;
-
- (void) signal(SIGCHLD, main_sigchld_handler);
- errno = save_errno;
-}
-
-/*
- * Signal handler for the alarm after the login grace period has expired. This
- * is for the (soon-to-be) unprivileged child only. The monitor gets an event on
- * the communication pipe and exits as well.
- */
-static void
-grace_alarm_handler(int sig)
-{
- /* Log error and exit. */
- fatal("Timeout before authentication for %.200s", get_remote_ipaddr());
-}
-
-#ifdef HAVE_SOLARIS_CONTRACTS
-static int contracts_fd = -1;
-void
-contracts_pre_fork()
-{
- const char *during = "opening process contract template";
-
- /*
- * Failure should not be treated as fatal on the theory that
- * it's better to start with children in the same contract as
- * the master listener than not at all.
- */
-
- if (contracts_fd == -1) {
- if ((contracts_fd = open64(CTFS_ROOT "/process/template",
- O_RDWR)) == -1)
- goto cleanup;
-
- during = "setting sundry contract terms";
- if ((errno = ct_pr_tmpl_set_param(contracts_fd, CT_PR_PGRPONLY)))
- goto cleanup;
-
- if ((errno = ct_tmpl_set_informative(contracts_fd, CT_PR_EV_HWERR)))
- goto cleanup;
-
- if ((errno = ct_pr_tmpl_set_fatal(contracts_fd, CT_PR_EV_HWERR)))
- goto cleanup;
-
- if ((errno = ct_tmpl_set_critical(contracts_fd, 0)))
- goto cleanup;
- }
-
- during = "setting active template";
- if ((errno = ct_tmpl_activate(contracts_fd)))
- goto cleanup;
-
- debug3("Set active contract");
- return;
-
-cleanup:
- if (contracts_fd != -1)
- (void) close(contracts_fd);
-
- contracts_fd = -1;
-
- if (errno)
- debug2("Error while trying to set up active contract"
- " template: %s while %s", strerror(errno), during);
-}
-
-void
-contracts_post_fork_child()
-{
- /* Clear active template so fork() creates no new contracts. */
-
- if (contracts_fd == -1)
- return;
-
- if ((errno = (ct_tmpl_clear(contracts_fd))))
- debug2("Error while trying to clear active contract template"
- " (child): %s", strerror(errno));
- else
- debug3("Cleared active contract template (child)");
-
- (void) close(contracts_fd);
-
- contracts_fd = -1;
-}
-
-void
-contracts_post_fork_parent(int fork_succeeded)
-{
- char path[PATH_MAX];
- int cfd, n;
- ct_stathdl_t st;
- ctid_t latest;
-
- /* Clear active template, abandon latest contract. */
- if (contracts_fd == -1)
- return;
-
- if ((errno = ct_tmpl_clear(contracts_fd)))
- debug2("Error while clearing active contract template: %s",
- strerror(errno));
- else
- debug3("Cleared active contract template (parent)");
-
- if (!fork_succeeded)
- return;
-
- if ((cfd = open64(CTFS_ROOT "/process/latest", O_RDONLY)) == -1) {
- debug2("Error while getting latest contract: %s",
- strerror(errno));
- return;
- }
-
- if ((errno = ct_status_read(cfd, CTD_COMMON, &st)) != 0) {
- debug2("Error while getting latest contract ID: %s",
- strerror(errno));
- (void) close(cfd);
- return;
- }
-
- latest = ct_status_get_id(st);
- ct_status_free(st);
- (void) close(cfd);
-
- n = snprintf(path, PATH_MAX, CTFS_ROOT "/all/%ld/ctl", latest);
-
- if (n >= PATH_MAX) {
- debug2("Error while opening the latest contract ctl file: %s",
- strerror(ENAMETOOLONG));
- return;
- }
-
- if ((cfd = open64(path, O_WRONLY)) == -1) {
- debug2("Error while opening the latest contract ctl file: %s",
- strerror(errno));
- return;
- }
-
- if ((errno = ct_ctl_abandon(cfd)))
- debug2("Error while abandoning latest contract: %s",
- strerror(errno));
- else
- debug3("Abandoned latest contract");
-
- (void) close(cfd);
-}
-#endif /* HAVE_SOLARIS_CONTRACTS */
-
-/*
- * Signal handler for the key regeneration alarm. Note that this
- * alarm only occurs in the daemon waiting for connections, and it does not
- * do anything with the private key or random state before forking.
- * Thus there should be no concurrency control/asynchronous execution
- * problems.
- */
-static void
-generate_ephemeral_server_key(void)
-{
- u_int32_t rnd = 0;
- int i;
-
- verbose("Generating %s%d bit RSA key.",
- sensitive_data.server_key ? "new " : "", options.server_key_bits);
- if (sensitive_data.server_key != NULL)
- key_free(sensitive_data.server_key);
- sensitive_data.server_key = key_generate(KEY_RSA1,
- options.server_key_bits);
- verbose("RSA key generation complete.");
-
- for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
- if (i % 4 == 0)
- rnd = arc4random();
- sensitive_data.ssh1_cookie[i] = rnd & 0xff;
- rnd >>= 8;
- }
- arc4random_stir();
-}
-
-static void
-key_regeneration_alarm(int sig)
-{
- int save_errno = errno;
-
- (void) signal(SIGALRM, SIG_DFL);
- errno = save_errno;
- key_do_regen = 1;
-}
-
-static void
-sshd_exchange_identification(int sock_in, int sock_out)
-{
- int i, mismatch;
- int remote_major, remote_minor;
- int major, minor;
- char *s;
- char buf[256]; /* Must not be larger than remote_version. */
- char remote_version[256]; /* Must be at least as big as buf. */
-
- if ((options.protocol & SSH_PROTO_1) &&
- (options.protocol & SSH_PROTO_2)) {
- major = PROTOCOL_MAJOR_1;
- minor = 99;
- } else if (options.protocol & SSH_PROTO_2) {
- major = PROTOCOL_MAJOR_2;
- minor = PROTOCOL_MINOR_2;
- } else {
- major = PROTOCOL_MAJOR_1;
- minor = PROTOCOL_MINOR_1;
- }
- (void) snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
- server_version_string = xstrdup(buf);
-
- if (client_version_string == NULL) {
- /* Send our protocol version identification. */
- if (atomicio(write, sock_out, server_version_string,
- strlen(server_version_string))
- != strlen(server_version_string)) {
- log("Could not write ident string to %s", get_remote_ipaddr());
- fatal_cleanup();
- }
-
- /* Read other sides version identification. */
- (void) memset(buf, 0, sizeof(buf));
- for (i = 0; i < sizeof(buf) - 1; i++) {
- if (atomicio(read, sock_in, &buf[i], 1) != 1) {
- log("Did not receive identification string from %s",
- get_remote_ipaddr());
- fatal_cleanup();
- }
- if (buf[i] == '\r') {
- buf[i] = 0;
- /* Kludge for F-Secure Macintosh < 1.0.2 */
- if (i == 12 &&
- strncmp(buf, "SSH-1.5-W1.0", 12) == 0)
- break;
- continue;
- }
- if (buf[i] == '\n') {
- buf[i] = 0;
- break;
- }
- }
- buf[sizeof(buf) - 1] = 0;
- client_version_string = xstrdup(buf);
- }
-
- /*
- * Check that the versions match. In future this might accept
- * several versions and set appropriate flags to handle them.
- */
- if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n",
- &remote_major, &remote_minor, remote_version) != 3) {
- s = "Protocol mismatch.\n";
- (void) atomicio(write, sock_out, s, strlen(s));
- (void) close(sock_in);
- (void) close(sock_out);
- log("Bad protocol version identification '%.100s' from %s",
- client_version_string, get_remote_ipaddr());
- fatal_cleanup();
- }
- debug("Client protocol version %d.%d; client software version %.100s",
- remote_major, remote_minor, remote_version);
-
- compat_datafellows(remote_version);
-
- if (datafellows & SSH_BUG_PROBE) {
- log("probed from %s with %s. Don't panic.",
- get_remote_ipaddr(), client_version_string);
- fatal_cleanup();
- }
-
- if (datafellows & SSH_BUG_SCANNER) {
- log("scanned from %s with %s. Don't panic.",
- get_remote_ipaddr(), client_version_string);
- fatal_cleanup();
- }
-
- mismatch = 0;
- switch (remote_major) {
- case 1:
- if (remote_minor == 99) {
- if (options.protocol & SSH_PROTO_2)
- enable_compat20();
- else
- mismatch = 1;
- break;
- }
- if (!(options.protocol & SSH_PROTO_1)) {
- mismatch = 1;
- break;
- }
- if (remote_minor < 3) {
- packet_disconnect("Your ssh version is too old and "
- "is no longer supported. Please install a newer version.");
- } else if (remote_minor == 3) {
- /* note that this disables agent-forwarding */
- enable_compat13();
- }
- break;
- case 2:
- if (options.protocol & SSH_PROTO_2) {
- enable_compat20();
- break;
- }
- /* FALLTHROUGH */
- default:
- mismatch = 1;
- break;
- }
- chop(server_version_string);
- debug("Local version string %.200s", server_version_string);
-
- if (mismatch) {
- s = "Protocol major versions differ.\n";
- (void) atomicio(write, sock_out, s, strlen(s));
- (void) close(sock_in);
- (void) close(sock_out);
- log("Protocol major versions differ for %s: %.200s vs. %.200s",
- get_remote_ipaddr(),
- server_version_string, client_version_string);
- fatal_cleanup();
- }
-}
-
-/* Destroy the host and server keys. They will no longer be needed. */
-void
-destroy_sensitive_data(void)
-{
- int i;
-
- if (sensitive_data.server_key) {
- key_free(sensitive_data.server_key);
- sensitive_data.server_key = NULL;
- }
- for (i = 0; i < options.num_host_key_files; i++) {
- if (sensitive_data.host_keys[i]) {
- key_free(sensitive_data.host_keys[i]);
- sensitive_data.host_keys[i] = NULL;
- }
- }
- sensitive_data.ssh1_host_key = NULL;
- (void) memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
-}
-
-/* Demote private to public keys for network child */
-static void
-demote_sensitive_data(void)
-{
- Key *tmp;
- int i;
-
- if (sensitive_data.server_key) {
- tmp = key_demote(sensitive_data.server_key);
- key_free(sensitive_data.server_key);
- sensitive_data.server_key = tmp;
- }
-
- for (i = 0; i < options.num_host_key_files; i++) {
- if (sensitive_data.host_keys[i]) {
- tmp = key_demote(sensitive_data.host_keys[i]);
- key_free(sensitive_data.host_keys[i]);
- sensitive_data.host_keys[i] = tmp;
- if (tmp->type == KEY_RSA1)
- sensitive_data.ssh1_host_key = tmp;
- }
- }
-
- /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */
-}
-
-static char *
-list_hostkey_types(void)
-{
- Buffer b;
- char *p;
- int i;
-
- buffer_init(&b);
- for (i = 0; i < options.num_host_key_files; i++) {
- Key *key = sensitive_data.host_keys[i];
- if (key == NULL)
- continue;
- switch (key->type) {
- case KEY_RSA:
- case KEY_DSA:
- if (buffer_len(&b) > 0)
- buffer_append(&b, ",", 1);
- p = key_ssh_name(key);
- buffer_append(&b, p, strlen(p));
- break;
- }
- }
- buffer_append(&b, "\0", 1);
- p = xstrdup(buffer_ptr(&b));
- buffer_free(&b);
- debug("list_hostkey_types: %s", p);
- return p;
-}
-
-#ifdef lint
-static
-#endif /* lint */
-Key *
-get_hostkey_by_type(int type)
-{
- int i;
-
- for (i = 0; i < options.num_host_key_files; i++) {
- Key *key = sensitive_data.host_keys[i];
- if (key != NULL && key->type == type)
- return key;
- }
- return NULL;
-}
-
-#ifdef lint
-static
-#endif /* lint */
-Key *
-get_hostkey_by_index(int ind)
-{
- if (ind < 0 || ind >= options.num_host_key_files)
- return (NULL);
- return (sensitive_data.host_keys[ind]);
-}
-
-#ifdef lint
-static
-#endif /* lint */
-int
-get_hostkey_index(Key *key)
-{
- int i;
-
- for (i = 0; i < options.num_host_key_files; i++) {
- if (key == sensitive_data.host_keys[i])
- return (i);
- }
- return (-1);
-}
-
-/*
- * returns 1 if connection should be dropped, 0 otherwise.
- * dropping starts at connection #max_startups_begin with a probability
- * of (max_startups_rate/100). the probability increases linearly until
- * all connections are dropped for startups > max_startups
- */
-static int
-drop_connection(int startups)
-{
- double p, r;
-
- if (startups < options.max_startups_begin)
- return 0;
- if (startups >= options.max_startups)
- return 1;
- if (options.max_startups_rate == 100)
- return 1;
-
- p = 100 - options.max_startups_rate;
- p *= startups - options.max_startups_begin;
- p /= (double) (options.max_startups - options.max_startups_begin);
- p += options.max_startups_rate;
- p /= 100.0;
- r = arc4random() / (double) UINT_MAX;
-
- debug("drop_connection: p %g, r %g", p, r);
- return (r < p) ? 1 : 0;
-}
-
-static void
-usage(void)
-{
- (void) fprintf(stderr, gettext("sshd version %s\n"), SSH_VERSION);
- (void) fprintf(stderr,
- gettext("Usage: %s [options]\n"
- "Options:\n"
- " -f file Configuration file (default %s)\n"
- " -d Debugging mode (multiple -d means more "
- "debugging)\n"
- " -i Started from inetd\n"
- " -D Do not fork into daemon mode\n"
- " -t Only test configuration file and keys\n"
- " -q Quiet (no logging)\n"
- " -p port Listen on the specified port (default: 22)\n"
- " -k seconds Regenerate server key every this many seconds "
- "(default: 3600)\n"
- " -g seconds Grace period for authentication (default: 600)\n"
- " -b bits Size of server RSA key (default: 768 bits)\n"
- " -h file File from which to read host key (default: %s)\n"
- " -4 Use IPv4 only\n"
- " -6 Use IPv6 only\n"
- " -o option Process the option as if it was read from "
- "a configuration file.\n"),
- __progname, _PATH_SERVER_CONFIG_FILE, _PATH_HOST_KEY_FILE);
- exit(1);
-}
-
-/*
- * Main program for the daemon.
- */
-int
-main(int ac, char **av)
-{
- extern char *optarg;
- extern int optind;
- int opt, j, i, fdsetsz, sock_in = 0, sock_out = 0, newsock = -1, on = 1;
- pid_t pid;
- socklen_t fromlen;
- fd_set *fdset;
- struct sockaddr_storage from;
- const char *remote_ip;
- int remote_port;
- FILE *f;
- struct addrinfo *ai;
- char ntop[NI_MAXHOST], strport[NI_MAXSERV];
- int listen_sock, maxfd;
- int startup_p[2];
- int startups = 0;
- Authctxt *authctxt = NULL;
- Key *key;
- int ret, key_used = 0;
-#ifdef HAVE_BSM
- au_id_t auid = AU_NOAUDITID;
-#endif /* HAVE_BSM */
- int mpipe;
-
- __progname = get_progname(av[0]);
-
- (void) g11n_setlocale(LC_ALL, "");
-
- init_rng();
-
- /* Save argv. */
- saved_argc = ac;
- saved_argv = av;
-
- /* Initialize configuration options to their default values. */
- initialize_server_options(&options);
-
- /* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:o:dDeiqtQ46")) != -1) {
- switch (opt) {
- case '4':
- IPv4or6 = AF_INET;
- break;
- case '6':
- IPv4or6 = AF_INET6;
- break;
- case 'f':
- config_file_name = optarg;
- break;
- case 'd':
- if (0 == debug_flag) {
- debug_flag = 1;
- options.log_level = SYSLOG_LEVEL_DEBUG1;
- } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
- options.log_level++;
- } else {
- (void) fprintf(stderr,
- gettext("Debug level too high.\n"));
- exit(1);
- }
- break;
- case 'D':
- no_daemon_flag = 1;
- break;
- case 'e':
- log_stderr = 1;
- break;
- case 'i':
- inetd_flag = 1;
- break;
- case 'Q':
- /* ignored */
- break;
- case 'q':
- options.log_level = SYSLOG_LEVEL_QUIET;
- break;
- case 'b':
- options.server_key_bits = atoi(optarg);
- break;
- case 'p':
- options.ports_from_cmdline = 1;
- if (options.num_ports >= MAX_PORTS) {
- (void) fprintf(stderr, gettext("too many ports.\n"));
- exit(1);
- }
- options.ports[options.num_ports++] = a2port(optarg);
- if (options.ports[options.num_ports-1] == 0) {
- (void) fprintf(stderr, gettext("Bad port number.\n"));
- exit(1);
- }
- break;
- case 'g':
- if ((options.login_grace_time = convtime(optarg)) == -1) {
- (void) fprintf(stderr,
- gettext("Invalid login grace time.\n"));
- exit(1);
- }
- break;
- case 'k':
- if ((options.key_regeneration_time = convtime(optarg)) == -1) {
- (void) fprintf(stderr,
- gettext("Invalid key regeneration "
- "interval.\n"));
- exit(1);
- }
- break;
- case 'h':
- if (options.num_host_key_files >= MAX_HOSTKEYS) {
- (void) fprintf(stderr,
- gettext("too many host keys.\n"));
- exit(1);
- }
- options.host_key_files[options.num_host_key_files++] = optarg;
- break;
- case 'V':
- client_version_string = optarg;
- /* only makes sense with inetd_flag, i.e. no listen() */
- inetd_flag = 1;
- break;
- case 't':
- test_flag = 1;
- break;
- case 'o':
- if (process_server_config_line(&options, optarg,
- "command-line", 0, NULL, NULL, NULL, NULL) != 0)
- exit(1);
- break;
- case '?':
- default:
- usage();
- break;
- }
- }
-
- /*
- * There is no need to use the PKCS#11 engine in the master SSH process.
- */
- SSLeay_add_all_algorithms();
- seed_rng();
- channel_set_af(IPv4or6);
-
- /*
- * Force logging to stderr until we have loaded the private host
- * key (unless started from inetd)
- */
- log_init(__progname,
- options.log_level == SYSLOG_LEVEL_NOT_SET ?
- SYSLOG_LEVEL_INFO : options.log_level,
- options.log_facility == SYSLOG_FACILITY_NOT_SET ?
- SYSLOG_FACILITY_AUTH : options.log_facility,
- !inetd_flag);
-
-#ifdef _UNICOS
- /* Cray can define user privs drop all prives now!
- * Not needed on PRIV_SU systems!
- */
- drop_cray_privs();
-#endif
-
- /* Fetch our configuration */
- buffer_init(&cfg);
- load_server_config(config_file_name, &cfg);
- parse_server_config(&options, config_file_name, &cfg, NULL, NULL, NULL);
-
- /*
- * ChallengeResponseAuthentication is deprecated for protocol 2 which is
- * the default setting on Solaris. Warn the user about it. Note that
- * ChallengeResponseAuthentication is on by default but the option is
- * not set until fill_default_server_options() is called. If the option
- * is already set now, the user must have set it manually.
- */
- if ((options.protocol & SSH_PROTO_2) &&
- !(options.protocol & SSH_PROTO_1) &&
- options.challenge_response_authentication != -1) {
- log("ChallengeResponseAuthentication has been "
- "deprecated for the SSH Protocol 2. You should use "
- "KbdInteractiveAuthentication instead (which defaults to "
- "\"yes\").");
- }
-
- /*
- * While PAMAuthenticationViaKbdInt was not documented, it was
- * previously set in our default sshd_config and also the only way to
- * switch off the keyboard-interactive authentication. To maintain
- * backward compatibility, if PAMAuthenticationViaKbdInt is manually set
- * to "no" and KbdInteractiveAuthentication is not set, switch off the
- * keyboard-interactive authentication method as before. As with the
- * challenge response auth situation dealt above, we have not called
- * fill_default_server_options() yet so if KbdInteractiveAuthentication
- * is already set to 1 here the admin must have set it manually and we
- * will honour it.
- */
- if (options.kbd_interactive_authentication != 1 &&
- options.pam_authentication_via_kbd_int == 0) {
- options.kbd_interactive_authentication = 0;
- }
-
- /* Fill in default values for those options not explicitly set. */
- fill_default_server_options(&options);
-
- utmp_len = options.lookup_client_hostnames ? utmp_len : 0;
-
- /* Check that there are no remaining arguments. */
- if (optind < ac) {
- (void) fprintf(stderr, gettext("Extra argument %s.\n"), av[optind]);
- exit(1);
- }
-
- debug("sshd version %.100s", SSH_VERSION);
-
- /* load private host keys */
- if (options.num_host_key_files > 0)
- sensitive_data.host_keys =
- xmalloc(options.num_host_key_files * sizeof(Key *));
- for (i = 0; i < options.num_host_key_files; i++)
- sensitive_data.host_keys[i] = NULL;
- sensitive_data.server_key = NULL;
- sensitive_data.ssh1_host_key = NULL;
- sensitive_data.have_ssh1_key = 0;
- sensitive_data.have_ssh2_key = 0;
-
- for (i = 0; i < options.num_host_key_files; i++) {
- key = key_load_private(options.host_key_files[i], "", NULL);
- sensitive_data.host_keys[i] = key;
- if (key == NULL) {
- error("Could not load host key: %s",
- options.host_key_files[i]);
- sensitive_data.host_keys[i] = NULL;
- continue;
- }
- switch (key->type) {
- case KEY_RSA1:
- sensitive_data.ssh1_host_key = key;
- sensitive_data.have_ssh1_key = 1;
- break;
- case KEY_RSA:
- case KEY_DSA:
- sensitive_data.have_ssh2_key = 1;
- break;
- }
- debug("private host key: #%d type %d %s", i, key->type,
- key_type(key));
- }
- if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
- log("Disabling protocol version 1. Could not load host key");
- options.protocol &= ~SSH_PROTO_1;
- }
- if ((options.protocol & SSH_PROTO_2) &&
- !sensitive_data.have_ssh2_key) {
-#ifdef GSSAPI
- if (options.gss_keyex)
- ssh_gssapi_server_mechs(&mechs);
-
- if (mechs == GSS_C_NULL_OID_SET) {
- log("Disabling protocol version 2. Could not load host"
- "key or GSS-API mechanisms");
- options.protocol &= ~SSH_PROTO_2;
- }
-#else
- log("Disabling protocol version 2. Could not load host key");
- options.protocol &= ~SSH_PROTO_2;
-#endif /* GSSAPI */
- }
- if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
- log("sshd: no hostkeys available -- exiting.");
- exit(1);
- }
-
- /* Check certain values for sanity. */
- if (options.protocol & SSH_PROTO_1) {
- if (options.server_key_bits < 512 ||
- options.server_key_bits > 32768) {
- (void) fprintf(stderr, gettext("Bad server key size.\n"));
- exit(1);
- }
- /*
- * Check that server and host key lengths differ sufficiently. This
- * is necessary to make double encryption work with rsaref. Oh, I
- * hate software patents. I dont know if this can go? Niels
- */
- if (options.server_key_bits >
- BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) -
- SSH_KEY_BITS_RESERVED && options.server_key_bits <
- BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) +
- SSH_KEY_BITS_RESERVED) {
- options.server_key_bits =
- BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) +
- SSH_KEY_BITS_RESERVED;
- debug("Forcing server key to %d bits to make it differ from host key.",
- options.server_key_bits);
- }
- }
-
- /* Configuration looks good, so exit if in test mode. */
- if (test_flag)
- exit(0);
-
- /*
- * Clear out any supplemental groups we may have inherited. This
- * prevents inadvertent creation of files with bad modes (in the
- * portable version at least, it's certainly possible for PAM
- * to create a file, and we can't control the code in every
- * module which might be used).
- */
- if (setgroups(0, NULL) < 0)
- debug("setgroups() failed: %.200s", strerror(errno));
-
- /* Initialize the log (it is reinitialized below in case we forked). */
- if (debug_flag && !inetd_flag)
- log_stderr = 1;
- log_init(__progname, options.log_level, options.log_facility, log_stderr);
-
- /*
- * Solaris 9 and systems upgraded from it may have the Ciphers option
- * explicitly set to "aes128-cbc,blowfish-cbc,3des-cbc" in the
- * sshd_config. Since the default server cipher list completely changed
- * since then we rather notify the administator on startup. We do this
- * check after log_init() so that the message goes to syslogd and not to
- * stderr (unless the server is in the debug mode). Note that since
- * Solaris 10 we no longer ship sshd_config with explicit settings for
- * Ciphers or MACs. Do not try to augment the cipher list here since
- * that might end up in a very confusing situation.
- */
-#define OLD_DEFAULT_CIPHERS_LIST "aes128-cbc,blowfish-cbc,3des-cbc"
- if (options.ciphers != NULL &&
- strcmp(options.ciphers, OLD_DEFAULT_CIPHERS_LIST) == 0) {
- notice("Old default value \"%s\" for the \"Ciphers\" "
- "option found in use. In general it is prudent to let "
- "the server choose the defaults unless your environment "
- "specifically needs an explicit setting. See "
- "sshd_config(4) for more information.",
- OLD_DEFAULT_CIPHERS_LIST);
- }
-
-#ifdef HAVE_BSM
- (void) setauid(&auid);
-#endif /* HAVE_BSM */
-
- /*
- * If not in debugging mode, and not started from inetd, disconnect
- * from the controlling terminal, and fork. The original process
- * exits.
- */
- if (!(debug_flag || inetd_flag || no_daemon_flag)) {
-#ifdef TIOCNOTTY
- int fd;
-#endif /* TIOCNOTTY */
- if (daemon(0, 0) < 0)
- fatal("daemon() failed: %.200s", strerror(errno));
-
- /* Disconnect from the controlling tty. */
-#ifdef TIOCNOTTY
- fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
- if (fd >= 0) {
- (void) ioctl(fd, TIOCNOTTY, NULL);
- (void) close(fd);
- }
-#endif /* TIOCNOTTY */
- }
- /* Reinitialize the log (because of the fork above). */
- log_init(__progname, options.log_level, options.log_facility, log_stderr);
-
- /* Initialize the random number generator. */
- arc4random_stir();
-
- /* Chdir to the root directory so that the current disk can be
- unmounted if desired. */
- (void) chdir("/");
-
- /* ignore SIGPIPE */
- (void) signal(SIGPIPE, SIG_IGN);
-
- /* Start listening for a socket, unless started from inetd. */
- if (inetd_flag) {
- int s1;
- s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */
- (void) dup(s1);
- sock_in = dup(0);
- sock_out = dup(1);
- startup_pipe = -1;
- /* we need this later for setting audit context */
- newsock = sock_in;
- /*
- * We intentionally do not close the descriptors 0, 1, and 2
- * as our code for setting the descriptors won\'t work if
- * ttyfd happens to be one of those.
- */
- debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
- if (options.protocol & SSH_PROTO_1)
- generate_ephemeral_server_key();
- } else {
- for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
- if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
- continue;
- if (num_listen_socks >= MAX_LISTEN_SOCKS)
- fatal("Too many listen sockets. "
- "Enlarge MAX_LISTEN_SOCKS");
- if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
- ntop, sizeof(ntop), strport, sizeof(strport),
- NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
- error("getnameinfo failed");
- continue;
- }
- /* Create socket for listening. */
- listen_sock = socket(ai->ai_family, SOCK_STREAM, 0);
- if (listen_sock < 0) {
- /* kernel may not support ipv6 */
- verbose("socket: %.100s", strerror(errno));
- continue;
- }
- if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) {
- error("listen_sock O_NONBLOCK: %s", strerror(errno));
- (void) close(listen_sock);
- continue;
- }
- /*
- * Set socket options.
- * Allow local port reuse in TIME_WAIT.
- */
- if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
- &on, sizeof(on)) == -1)
- error("setsockopt SO_REUSEADDR: %s", strerror(errno));
-
- debug("Bind to port %s on %s.", strport, ntop);
-
- /* Bind the socket to the desired port. */
- if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
- if (!ai->ai_next)
- error("Bind to port %s on %s failed: %.200s.",
- strport, ntop, strerror(errno));
- (void) close(listen_sock);
- continue;
- }
- listen_socks[num_listen_socks] = listen_sock;
- num_listen_socks++;
-
- /* Start listening on the port. */
- log("Server listening on %s port %s.", ntop, strport);
- if (listen(listen_sock, 5) < 0)
- fatal("listen: %.100s", strerror(errno));
-
- }
- freeaddrinfo(options.listen_addrs);
-
- if (!num_listen_socks)
- fatal("Cannot bind any address.");
-
- if (options.protocol & SSH_PROTO_1)
- generate_ephemeral_server_key();
-
- /*
- * Arrange to restart on SIGHUP. The handler needs
- * listen_sock.
- */
- (void) signal(SIGHUP, sighup_handler);
-
- (void) signal(SIGTERM, sigterm_handler);
- (void) signal(SIGQUIT, sigterm_handler);
-
- /* Arrange SIGCHLD to be caught. */
- (void) signal(SIGCHLD, main_sigchld_handler);
-
- /* Write out the pid file after the sigterm handler is setup */
- if (!debug_flag) {
- /*
- * Record our pid in /var/run/sshd.pid to make it
- * easier to kill the correct sshd. We don't want to
- * do this before the bind above because the bind will
- * fail if there already is a daemon, and this will
- * overwrite any old pid in the file.
- */
- f = fopen(options.pid_file, "wb");
- if (f) {
- (void) fprintf(f, "%ld\n", (long) getpid());
- (void) fclose(f);
- }
- }
-
- /* setup fd set for listen */
- fdset = NULL;
- maxfd = 0;
- for (i = 0; i < num_listen_socks; i++)
- if (listen_socks[i] > maxfd)
- maxfd = listen_socks[i];
- /* pipes connected to unauthenticated childs */
- startup_pipes = xmalloc(options.max_startups * sizeof(int));
- for (i = 0; i < options.max_startups; i++)
- startup_pipes[i] = -1;
-
- /*
- * Stay listening for connections until the system crashes or
- * the daemon is killed with a signal.
- */
- for (;;) {
- if (received_sighup)
- sighup_restart();
- if (fdset != NULL)
- xfree(fdset);
- fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
- fdset = (fd_set *)xmalloc(fdsetsz);
- (void) memset(fdset, 0, fdsetsz);
-
- for (i = 0; i < num_listen_socks; i++)
- FD_SET(listen_socks[i], fdset);
- for (i = 0; i < options.max_startups; i++)
- if (startup_pipes[i] != -1)
- FD_SET(startup_pipes[i], fdset);
-
- /* Wait in select until there is a connection. */
- ret = select(maxfd+1, fdset, NULL, NULL, NULL);
- if (ret < 0 && errno != EINTR)
- error("select: %.100s", strerror(errno));
- if (received_sigterm) {
- log("Received signal %d; terminating.",
- (int) received_sigterm);
- close_listen_socks();
- (void) unlink(options.pid_file);
- exit(255);
- }
- if (key_used && key_do_regen) {
- generate_ephemeral_server_key();
- key_used = 0;
- key_do_regen = 0;
- }
- if (ret < 0)
- continue;
-
- for (i = 0; i < options.max_startups; i++)
- if (startup_pipes[i] != -1 &&
- FD_ISSET(startup_pipes[i], fdset)) {
- /*
- * the read end of the pipe is ready
- * if the child has closed the pipe
- * after successful authentication
- * or if the child has died
- */
- (void) close(startup_pipes[i]);
- startup_pipes[i] = -1;
- startups--;
- }
- for (i = 0; i < num_listen_socks; i++) {
- if (!FD_ISSET(listen_socks[i], fdset))
- continue;
- fromlen = sizeof(from);
- newsock = accept(listen_socks[i], (struct sockaddr *)&from,
- &fromlen);
- if (newsock < 0) {
- if (errno != EINTR && errno != EWOULDBLOCK)
- error("accept: %.100s", strerror(errno));
- continue;
- }
- if (fcntl(newsock, F_SETFL, 0) < 0) {
- error("newsock del O_NONBLOCK: %s", strerror(errno));
- (void) close(newsock);
- continue;
- }
- if (drop_connection(startups) == 1) {
- debug("drop connection #%d", startups);
- (void) close(newsock);
- continue;
- }
- if (pipe(startup_p) == -1) {
- (void) close(newsock);
- continue;
- }
-
- for (j = 0; j < options.max_startups; j++)
- if (startup_pipes[j] == -1) {
- startup_pipes[j] = startup_p[0];
- if (maxfd < startup_p[0])
- maxfd = startup_p[0];
- startups++;
- break;
- }
-
- /*
- * Got connection. Fork a child to handle it, unless
- * we are in debugging mode.
- */
- if (debug_flag) {
- /*
- * In debugging mode. Close the listening
- * socket, and start processing the
- * connection without forking.
- */
- debug("Server will not fork when running in debugging mode.");
- close_listen_socks();
- sock_in = newsock;
- sock_out = newsock;
- startup_pipe = -1;
- pid = getpid();
- break;
- } else {
- /*
- * Normal production daemon. Fork, and have
- * the child process the connection. The
- * parent continues listening.
- */
-#ifdef HAVE_SOLARIS_CONTRACTS
- /*
- * Setup Solaris contract template so
- * the child process is in a different
- * process contract than the parent;
- * prevents established connections from
- * being killed when the sshd master
- * listener service is stopped.
- */
- contracts_pre_fork();
-#endif /* HAVE_SOLARIS_CONTRACTS */
- if ((pid = fork()) == 0) {
- /*
- * Child. Close the listening and max_startup
- * sockets. Start using the accepted socket.
- * Reinitialize logging (since our pid has
- * changed). We break out of the loop to handle
- * the connection.
- */
-#ifdef HAVE_SOLARIS_CONTRACTS
- contracts_post_fork_child();
-#endif /* HAVE_SOLARIS_CONTRACTS */
- xfree(fdset);
- startup_pipe = startup_p[1];
- close_startup_pipes();
- close_listen_socks();
- sock_in = newsock;
- sock_out = newsock;
- log_init(__progname, options.log_level, options.log_facility, log_stderr);
- break;
- }
-
- /* Parent. Stay in the loop. */
- if (pid < 0)
- error("fork: %.100s", strerror(errno));
- else
- debug("Forked child %ld.", (long)pid);
-
-#ifdef HAVE_SOLARIS_CONTRACTS
- contracts_post_fork_parent((pid > 0));
-#endif /* HAVE_SOLARIS_CONTRACTS */
- }
-
- (void) close(startup_p[1]);
-
- /* Mark that the key has been used (it was "given" to the child). */
- if ((options.protocol & SSH_PROTO_1) &&
- key_used == 0) {
- /* Schedule server key regeneration alarm. */
- (void) signal(SIGALRM, key_regeneration_alarm);
- (void) alarm(options.key_regeneration_time);
- key_used = 1;
- }
-
- arc4random_stir();
-
- /*
- * Close the accepted socket since the child
- * will now take care of the new connection.
- */
- (void) close(newsock);
- }
- /* child process check (or debug mode) */
- if (num_listen_socks < 0)
- break;
- }
- }
-
- /*
- * This is the child processing a new connection, the SSH master process
- * stays in the ( ; ; ) loop above.
- */
-#ifdef HAVE_BSM
- audit_sshd_settid(newsock);
-#endif
- /*
- * Create a new session and process group since the 4.4BSD
- * setlogin() affects the entire process group. We don't
- * want the child to be able to affect the parent.
- */
-#if 0
- /* XXX: this breaks Solaris */
- if (!debug_flag && !inetd_flag && setsid() < 0)
- error("setsid: %.100s", strerror(errno));
-#endif
-
- /*
- * Disable the key regeneration alarm. We will not regenerate the
- * key since we are no longer in a position to give it to anyone. We
- * will not restart on SIGHUP since it no longer makes sense.
- */
- (void) alarm(0);
- (void) signal(SIGALRM, SIG_DFL);
- (void) signal(SIGHUP, SIG_DFL);
- (void) signal(SIGTERM, SIG_DFL);
- (void) signal(SIGQUIT, SIG_DFL);
- (void) signal(SIGCHLD, SIG_DFL);
- (void) signal(SIGINT, SIG_DFL);
-
- /* Set keepalives if requested. */
- if (options.keepalives &&
- setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on,
- sizeof(on)) < 0)
- debug2("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
-
- /*
- * Register our connection. This turns encryption off because we do
- * not have a key.
- */
- packet_set_connection(sock_in, sock_out);
-
- remote_port = get_remote_port();
- remote_ip = get_remote_ipaddr();
-
-#ifdef LIBWRAP
- /* Check whether logins are denied from this host. */
- {
- struct request_info req;
-
- (void) request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
- fromhost(&req);
-
- if (!hosts_access(&req)) {
- debug("Connection refused by tcp wrapper");
- refuse(&req);
- /* NOTREACHED */
- fatal("libwrap refuse returns");
- }
- }
-#endif /* LIBWRAP */
-
- /* Log the connection. */
- verbose("Connection from %.500s port %d", remote_ip, remote_port);
-
- sshd_exchange_identification(sock_in, sock_out);
- /*
- * Check that the connection comes from a privileged port.
- * Rhosts-Authentication only makes sense from privileged
- * programs. Of course, if the intruder has root access on his local
- * machine, he can connect from any port. So do not use these
- * authentication methods from machines that you do not trust.
- */
- if (options.rhosts_authentication &&
- (remote_port >= IPPORT_RESERVED ||
- remote_port < IPPORT_RESERVED / 2)) {
- debug("Rhosts Authentication disabled, "
- "originating port %d not trusted.", remote_port);
- options.rhosts_authentication = 0;
- }
-#if defined(KRB4) && !defined(KRB5)
- if (!packet_connection_is_ipv4() &&
- options.kerberos_authentication) {
- debug("Kerberos Authentication disabled, only available for IPv4.");
- options.kerberos_authentication = 0;
- }
-#endif /* KRB4 && !KRB5 */
-#ifdef AFS
- /* If machine has AFS, set process authentication group. */
- if (k_hasafs()) {
- k_setpag();
- k_unlog();
- }
-#endif /* AFS */
-
- packet_set_nonblocking();
-
- /*
- * Start the monitor. That way both processes will have their own
- * PKCS#11 sessions. See the PKCS#11 standard for more information on
- * fork safety and packet.c for information about forking with the
- * engine.
- *
- * Note that the monitor stays in the function while the child is the
- * only one that returns.
- */
- altprivsep_start_and_do_monitor(options.use_openssl_engine,
- inetd_flag, newsock, startup_pipe);
-
- /*
- * We don't want to listen forever unless the other side successfully
- * authenticates itself. So we set up an alarm which is cleared after
- * successful authentication. A limit of zero indicates no limit. Note
- * that we don't set the alarm in debugging mode; it is just annoying to
- * have the server exit just when you are about to discover the bug.
- */
- (void) signal(SIGALRM, grace_alarm_handler);
- if (!debug_flag)
- (void) alarm(options.login_grace_time);
-
- /*
- * The child is about to start the first key exchange while the monitor
- * stays in altprivsep_start_and_do_monitor() function.
- */
- (void) pkcs11_engine_load(options.use_openssl_engine);
-
- /* perform the key exchange */
- /* authenticate user and start session */
- if (compat20) {
- do_ssh2_kex();
- authctxt = do_authentication2();
- } else {
- do_ssh1_kex();
- authctxt = do_authentication();
- }
-
- /* Authentication complete */
- (void) alarm(0);
- /* we no longer need an alarm handler */
- (void) signal(SIGALRM, SIG_DFL);
-
- if (startup_pipe != -1) {
- (void) close(startup_pipe);
- startup_pipe = -1;
- }
-
- /* ALTPRIVSEP Child */
-
- /*
- * Drop privileges, access to privileged resources.
- *
- * Destroy private host keys, if any.
- *
- * No need to release any GSS credentials -- sshd only acquires
- * creds to determine what mechs it can negotiate then releases
- * them right away and uses GSS_C_NO_CREDENTIAL to accept
- * contexts.
- */
- debug2("Unprivileged server process dropping privileges");
- permanently_set_uid(authctxt->pw, options.chroot_directory);
- destroy_sensitive_data();
-
- /* Just another safety check. */
- if (getuid() != authctxt->pw->pw_uid ||
- geteuid() != authctxt->pw->pw_uid) {
- fatal("Failed to set uids to %u.", (u_int)authctxt->pw->pw_uid);
- }
-
- ssh_gssapi_server_mechs(NULL); /* release cached mechs list */
- packet_set_server();
-
- /* now send the authentication context to the monitor */
- altprivsep_send_auth_context(authctxt);
-
- mpipe = altprivsep_get_pipe_fd();
- if (fcntl(mpipe, F_SETFL, O_NONBLOCK) < 0)
- error("fcntl O_NONBLOCK: %.100s", strerror(errno));
-
-#ifdef HAVE_BSM
- fatal_remove_cleanup(
- (void (*)(void *))audit_failed_login_cleanup,
- (void *)authctxt);
-#endif /* HAVE_BSM */
-
- if (compat20) {
- debug3("setting handler to forward re-key packets to the monitor");
- dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX,
- &altprivsep_rekey);
- }
-
- /* Logged-in session. */
- do_authenticated(authctxt);
-
- /* The connection has been terminated. */
- verbose("Closing connection to %.100s", remote_ip);
-
- packet_close();
-
-#ifdef USE_PAM
- finish_pam(authctxt);
-#endif /* USE_PAM */
-
- return (0);
-}
-
-/*
- * Decrypt session_key_int using our private server key and private host key
- * (key with larger modulus first).
- */
-int
-ssh1_session_key(BIGNUM *session_key_int)
-{
- int rsafail = 0;
-
- if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) {
- /* Server key has bigger modulus. */
- if (BN_num_bits(sensitive_data.server_key->rsa->n) <
- BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
- fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
- get_remote_ipaddr(),
- BN_num_bits(sensitive_data.server_key->rsa->n),
- BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
- SSH_KEY_BITS_RESERVED);
- }
- if (rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.server_key->rsa) <= 0)
- rsafail++;
- if (rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.ssh1_host_key->rsa) <= 0)
- rsafail++;
- } else {
- /* Host key has bigger modulus (or they are equal). */
- if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) <
- BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
- fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d",
- get_remote_ipaddr(),
- BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
- BN_num_bits(sensitive_data.server_key->rsa->n),
- SSH_KEY_BITS_RESERVED);
- }
- if (rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.ssh1_host_key->rsa) < 0)
- rsafail++;
- if (rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.server_key->rsa) < 0)
- rsafail++;
- }
- return (rsafail);
-}
-/*
- * SSH1 key exchange
- */
-static void
-do_ssh1_kex(void)
-{
- int i, len;
- int rsafail = 0;
- BIGNUM *session_key_int;
- u_char session_key[SSH_SESSION_KEY_LENGTH];
- u_char cookie[8];
- u_int cipher_type, auth_mask, protocol_flags;
- u_int32_t rnd = 0;
-
- /*
- * Generate check bytes that the client must send back in the user
- * packet in order for it to be accepted; this is used to defy ip
- * spoofing attacks. Note that this only works against somebody
- * doing IP spoofing from a remote machine; any machine on the local
- * network can still see outgoing packets and catch the random
- * cookie. This only affects rhosts authentication, and this is one
- * of the reasons why it is inherently insecure.
- */
- for (i = 0; i < 8; i++) {
- if (i % 4 == 0)
- rnd = arc4random();
- cookie[i] = rnd & 0xff;
- rnd >>= 8;
- }
-
- /*
- * Send our public key. We include in the packet 64 bits of random
- * data that must be matched in the reply in order to prevent IP
- * spoofing.
- */
- packet_start(SSH_SMSG_PUBLIC_KEY);
- for (i = 0; i < 8; i++)
- packet_put_char(cookie[i]);
-
- /* Store our public server RSA key. */
- packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n));
- packet_put_bignum(sensitive_data.server_key->rsa->e);
- packet_put_bignum(sensitive_data.server_key->rsa->n);
-
- /* Store our public host RSA key. */
- packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n));
- packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e);
- packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n);
-
- /* Put protocol flags. */
- packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
-
- /* Declare which ciphers we support. */
- packet_put_int(cipher_mask_ssh1(0));
-
- /* Declare supported authentication types. */
- auth_mask = 0;
- if (options.rhosts_authentication)
- auth_mask |= 1 << SSH_AUTH_RHOSTS;
- if (options.rhosts_rsa_authentication)
- auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
- if (options.rsa_authentication)
- auth_mask |= 1 << SSH_AUTH_RSA;
-#if defined(KRB4) || defined(KRB5)
- if (options.kerberos_authentication)
- auth_mask |= 1 << SSH_AUTH_KERBEROS;
-#endif
-#if defined(AFS) || defined(KRB5)
- if (options.kerberos_tgt_passing)
- auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
-#endif
-#ifdef AFS
- if (options.afs_token_passing)
- auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
-#endif
- if (options.challenge_response_authentication == 1)
- auth_mask |= 1 << SSH_AUTH_TIS;
- if (options.password_authentication)
- auth_mask |= 1 << SSH_AUTH_PASSWORD;
- packet_put_int(auth_mask);
-
- /* Send the packet and wait for it to be sent. */
- packet_send();
- packet_write_wait();
-
- debug("Sent %d bit server key and %d bit host key.",
- BN_num_bits(sensitive_data.server_key->rsa->n),
- BN_num_bits(sensitive_data.ssh1_host_key->rsa->n));
-
- /* Read clients reply (cipher type and session key). */
- packet_read_expect(SSH_CMSG_SESSION_KEY);
-
- /* Get cipher type and check whether we accept this. */
- cipher_type = packet_get_char();
-
- if (!(cipher_mask_ssh1(0) & (1 << cipher_type))) {
- packet_disconnect("Warning: client selects unsupported cipher.");
- }
-
- /* Get check bytes from the packet. These must match those we
- sent earlier with the public key packet. */
- for (i = 0; i < 8; i++) {
- if (cookie[i] != packet_get_char()) {
- packet_disconnect("IP Spoofing check bytes do not match.");
- }
- }
-
- debug("Encryption type: %.200s", cipher_name(cipher_type));
-
- /* Get the encrypted integer. */
- if ((session_key_int = BN_new()) == NULL)
- fatal("do_ssh1_kex: BN_new failed");
- packet_get_bignum(session_key_int);
-
- protocol_flags = packet_get_int();
- packet_set_protocol_flags(protocol_flags);
- packet_check_eom();
-
- /* Decrypt session_key_int using host/server keys */
- rsafail = ssh1_session_key(session_key_int);
-
- /*
- * Extract session key from the decrypted integer. The key is in the
- * least significant 256 bits of the integer; the first byte of the
- * key is in the highest bits.
- */
- if (!rsafail) {
- (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8);
- len = BN_num_bytes(session_key_int);
- if (len < 0 || len > sizeof(session_key)) {
- error("do_connection: bad session key len from %s: "
- "session_key_int %d > sizeof(session_key) %lu",
- get_remote_ipaddr(), len, (u_long)sizeof(session_key));
- rsafail++;
- } else {
- (void) memset(session_key, 0, sizeof(session_key));
- (void) BN_bn2bin(session_key_int,
- session_key + sizeof(session_key) - len);
-
- compute_session_id(session_id, cookie,
- sensitive_data.ssh1_host_key->rsa->n,
- sensitive_data.server_key->rsa->n);
- /*
- * Xor the first 16 bytes of the session key with the
- * session id.
- */
- for (i = 0; i < 16; i++)
- session_key[i] ^= session_id[i];
- }
- }
- if (rsafail) {
- int bytes = BN_num_bytes(session_key_int);
- u_char *buf = xmalloc(bytes);
- MD5_CTX md;
-
- log("do_connection: generating a fake encryption key");
- (void) BN_bn2bin(session_key_int, buf);
- MD5_Init(&md);
- MD5_Update(&md, buf, bytes);
- MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
- MD5_Final(session_key, &md);
- MD5_Init(&md);
- MD5_Update(&md, session_key, 16);
- MD5_Update(&md, buf, bytes);
- MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
- MD5_Final(session_key + 16, &md);
- (void) memset(buf, 0, bytes);
- xfree(buf);
- for (i = 0; i < 16; i++)
- session_id[i] = session_key[i] ^ session_key[i + 16];
- }
- /* Destroy the private and public keys. No longer. */
- destroy_sensitive_data();
-
- /* Destroy the decrypted integer. It is no longer needed. */
- BN_clear_free(session_key_int);
-
- /* Set the session key. From this on all communications will be encrypted. */
- packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
-
- /* Destroy our copy of the session key. It is no longer needed. */
- (void) memset(session_key, 0, sizeof(session_key));
-
- debug("Received session key; encryption turned on.");
-
- /* Send an acknowledgment packet. Note that this packet is sent encrypted. */
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
-}
-
-/*
- * Prepare for SSH2 key exchange.
- */
-Kex *
-prepare_for_ssh2_kex(void)
-{
- Kex *kex;
- Kex_hook_func kex_hook = NULL;
- char **locales;
- static char **myproposal;
-
- myproposal = my_srv_proposal;
-
- if (options.ciphers != NULL) {
- myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
- }
- myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
- myproposal[PROPOSAL_ENC_ALGS_STOC] =
- compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
-
- if (options.macs != NULL) {
- myproposal[PROPOSAL_MAC_ALGS_CTOS] =
- myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
- }
- if (!options.compression) {
- myproposal[PROPOSAL_COMP_ALGS_CTOS] =
- myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
- }
-
- /*
- * Prepare kex algs / hostkey algs (excluding GSS, which is
- * handled in the kex hook.
- *
- * XXX This should probably move to the kex hook as well, where
- * all non-constant kex offer material belongs.
- */
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
-
- /* If we have no host key algs we can't offer KEXDH/KEX_DH_GEX */
- if (myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] == NULL ||
- *myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] == '\0')
- myproposal[PROPOSAL_KEX_ALGS] = "";
-
- if ((locales = g11n_getlocales()) != NULL) {
- /* Solaris 9 SSH expects a list of locales */
- if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS)
- myproposal[PROPOSAL_LANG_STOC] = xjoin(locales, ',');
- else
- myproposal[PROPOSAL_LANG_STOC] =
- g11n_locales2langs(locales);
- }
-
- if (locales != NULL)
- g11n_freelist(locales);
-
- if ((myproposal[PROPOSAL_LANG_STOC] != NULL) &&
- (strcmp(myproposal[PROPOSAL_LANG_STOC], "")) != 0)
- myproposal[PROPOSAL_LANG_CTOS] =
- xstrdup(myproposal[PROPOSAL_LANG_STOC]);
-
-#ifdef GSSAPI
- if (options.gss_keyex)
- kex_hook = ssh_gssapi_server_kex_hook;
-#endif /* GSSAPI */
-
- kex = kex_setup(NULL, myproposal, kex_hook);
-
- /*
- * Note that the my_srv_proposal variable (ie., myproposal) is staticly
- * initialized with "" for the language fields; we must not xfree such
- * strings.
- */
- if (myproposal[PROPOSAL_LANG_STOC] != NULL &&
- strcmp(myproposal[PROPOSAL_LANG_STOC], "") != 0)
- xfree(myproposal[PROPOSAL_LANG_STOC]);
- if (myproposal[PROPOSAL_LANG_CTOS] != NULL &&
- strcmp(myproposal[PROPOSAL_LANG_STOC], "") != 0)
- xfree(myproposal[PROPOSAL_LANG_CTOS]);
-
- kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
- kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
-#ifdef GSSAPI
- kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
-#endif /* GSSAPI */
- kex->server = 1;
- kex->client_version_string = client_version_string;
- kex->server_version_string = server_version_string;
- kex->load_host_key = &get_hostkey_by_type;
- kex->host_key_index = &get_hostkey_index;
-
- xxx_kex = kex;
- return (kex);
-}
-
-/*
- * Do SSH2 key exchange.
- */
-static void
-do_ssh2_kex(void)
-{
- Kex *kex;
-
- kex = prepare_for_ssh2_kex();
- kex_start(kex);
-
- dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
-
- if (kex->name) {
- xfree(kex->name);
- kex->name = NULL;
- }
- session_id2 = kex->session_id;
- session_id2_len = kex->session_id_len;
-
-#ifdef DEBUG_KEXDH
- /* send 1st encrypted/maced/compressed message */
- packet_start(SSH2_MSG_IGNORE);
- packet_put_cstring("markus");
- packet_send();
- packet_write_wait();
-#endif
- debug("KEX done");
-}
diff --git a/usr/src/cmd/ssh/sshd/sshlogin.c b/usr/src/cmd/ssh/sshd/sshlogin.c
deleted file mode 100644
index c21877355c..0000000000
--- a/usr/src/cmd/ssh/sshd/sshlogin.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * This file performs some of the things login(1) normally does. We cannot
- * easily use something like login -p -h host -f user, because there are
- * several different logins around, and it is hard to determined what kind of
- * login the current system has. Also, we want to be able to execute commands
- * on a tty.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- *
- * Copyright (c) 1999 Theo de Raadt. All rights reserved.
- * Copyright (c) 1999 Markus Friedl. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: sshlogin.c,v 1.5 2002/08/29 15:57:25 stevesk Exp $");
-
-#include "loginrec.h"
-#include "log.h"
-#include "buffer.h"
-#include "servconf.h"
-#include "canohost.h"
-#include "packet.h"
-
-extern u_int utmp_len;
-extern ServerOptions options;
-
-/*
- * Returns the time when the user last logged in. Returns 0 if the
- * information is not available. This must be called before record_login.
- * The host the user logged in from will be returned in buf.
- */
-u_long
-get_last_login_time(uid_t uid, const char *logname,
- char *buf, u_int bufsize)
-{
- struct logininfo li;
-
- (void) login_get_lastlog(&li, uid);
- (void) strlcpy(buf, li.hostname, bufsize);
- return li.tv_sec;
-}
-
-/*
- * Records that the user has logged in. If only these parts of operating
- * systems were more standardized.
- */
-void
-record_login(pid_t pid, const char *ttyname, const char *progname,
- const char *user)
-{
- struct logininfo *li;
- static int initialized = 0;
- static socklen_t fromlen;
- static struct sockaddr_storage from;
- static const char *remote_name_or_ip;
-
- if (pid == 0)
- pid = getpid();
- /*
- * Get IP address of client. If the connection is not a socket, let
- * the address be 0.0.0.0.
- */
- if (!initialized) {
- (void) memset(&from, 0, sizeof(from));
- if (packet_connection_is_on_socket()) {
- fromlen = sizeof(from);
- if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) &from, &fromlen) < 0) {
- debug("getpeername: %.100s", strerror(errno));
- fatal_cleanup();
- }
- }
- remote_name_or_ip = get_remote_name_or_ip(utmp_len,
- options.verify_reverse_mapping);
-
- initialized = 1;
- }
-
- li = login_alloc_entry(pid, user, remote_name_or_ip, ttyname, progname);
- login_set_addr(li, (struct sockaddr*) &from, sizeof(struct sockaddr));
- (void) login_login(li);
- login_free_entry(li);
-}
-
-/* Records that the user has logged out. */
-void
-record_logout(pid_t pid, const char *ttyname, const char *progname,
- const char *user)
-{
- struct logininfo *li;
-
- li = login_alloc_entry(pid, user, NULL, ttyname, progname);
- (void) login_logout(li);
- login_free_entry(li);
-}
diff --git a/usr/src/cmd/ssh/sshd/sshpty.c b/usr/src/cmd/ssh/sshd/sshpty.c
deleted file mode 100644
index b421798cb5..0000000000
--- a/usr/src/cmd/ssh/sshd/sshpty.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Allocating a pseudo-terminal, and making it the controlling tty.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: sshpty.c,v 1.7 2002/06/24 17:57:20 deraadt Exp $");
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifdef HAVE_UTIL_H
-# include <util.h>
-#endif /* HAVE_UTIL_H */
-
-#include "sshpty.h"
-#include "log.h"
-#include "misc.h"
-
-/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
-#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
-#undef HAVE_DEV_PTMX
-#endif
-
-#ifdef HAVE_PTY_H
-# include <pty.h>
-#endif
-#if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
-# include <sys/stropts.h>
-#endif
-
-#ifndef O_NOCTTY
-#define O_NOCTTY 0
-#endif
-
-/*
- * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
- * nonzero if a pty was successfully allocated. On success, open file
- * descriptors for the pty and tty sides and the name of the tty side are
- * returned (the buffer must be able to hold at least 64 characters).
- */
-
-int
-pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
-{
-#if defined(HAVE_OPENPTY) || defined(BSD4_4)
- /* openpty(3) exists in OSF/1 and some other os'es */
- char *name;
- int i;
-
- i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
- if (i < 0) {
- error("openpty: %.100s", strerror(errno));
- return 0;
- }
- name = ttyname(*ttyfd);
- if (!name)
- fatal("openpty returns device for which ttyname fails.");
-
- strlcpy(namebuf, name, namebuflen); /* possible truncation */
- return 1;
-#else /* HAVE_OPENPTY */
-#ifdef HAVE__GETPTY
- /*
- * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
- * pty's automagically when needed
- */
- char *slave;
-
- slave = _getpty(ptyfd, O_RDWR, 0622, 0);
- if (slave == NULL) {
- error("_getpty: %.100s", strerror(errno));
- return 0;
- }
- strlcpy(namebuf, slave, namebuflen);
- /* Open the slave side. */
- *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
- if (*ttyfd < 0) {
- error("%.200s: %.100s", namebuf, strerror(errno));
- close(*ptyfd);
- return 0;
- }
- return 1;
-#else /* HAVE__GETPTY */
-#if defined(HAVE_DEV_PTMX)
- /*
- * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
- * also has bsd-style ptys, but they simply do not work.)
- */
- int ptm;
- char *pts;
- mysig_t old_signal;
-
- ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
- if (ptm < 0) {
- error("/dev/ptmx: %.100s", strerror(errno));
- return 0;
- }
- old_signal = mysignal(SIGCHLD, SIG_DFL);
- if (grantpt(ptm) < 0) {
- error("grantpt: %.100s", strerror(errno));
- return 0;
- }
- mysignal(SIGCHLD, old_signal);
- if (unlockpt(ptm) < 0) {
- error("unlockpt: %.100s", strerror(errno));
- return 0;
- }
- pts = ptsname(ptm);
- if (pts == NULL)
- error("Slave pty side name could not be obtained.");
- strlcpy(namebuf, pts, namebuflen);
- *ptyfd = ptm;
-
- /* Open the slave side. */
- *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
- if (*ttyfd < 0) {
- error("%.100s: %.100s", namebuf, strerror(errno));
- close(*ptyfd);
- return 0;
- }
-#ifndef HAVE_CYGWIN
- /*
- * Push the appropriate streams modules, as described in Solaris pts(7).
- * HP-UX pts(7) doesn't have ttcompat module.
- */
- if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
- error("ioctl I_PUSH ptem: %.100s", strerror(errno));
- if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
- error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
-#ifndef __hpux
- if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
- error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
-#endif
-#endif
- return 1;
-#else /* HAVE_DEV_PTMX */
-#ifdef HAVE_DEV_PTS_AND_PTC
- /* AIX-style pty code. */
- const char *name;
-
- *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
- if (*ptyfd < 0) {
- error("Could not open /dev/ptc: %.100s", strerror(errno));
- return 0;
- }
- name = ttyname(*ptyfd);
- if (!name)
- fatal("Open of /dev/ptc returns device for which ttyname fails.");
- strlcpy(namebuf, name, namebuflen);
- *ttyfd = open(name, O_RDWR | O_NOCTTY);
- if (*ttyfd < 0) {
- error("Could not open pty slave side %.100s: %.100s",
- name, strerror(errno));
- close(*ptyfd);
- return 0;
- }
- return 1;
-#else /* HAVE_DEV_PTS_AND_PTC */
-#ifdef _UNICOS
- char buf[64];
- int i;
- int highpty;
-
-#ifdef _SC_CRAY_NPTY
- highpty = sysconf(_SC_CRAY_NPTY);
- if (highpty == -1)
- highpty = 128;
-#else
- highpty = 128;
-#endif
-
- for (i = 0; i < highpty; i++) {
- snprintf(buf, sizeof(buf), "/dev/pty/%03d", i);
- *ptyfd = open(buf, O_RDWR|O_NOCTTY);
- if (*ptyfd < 0)
- continue;
- snprintf(namebuf, namebuflen, "/dev/ttyp%03d", i);
- /* Open the slave side. */
- *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
- if (*ttyfd < 0) {
- error("%.100s: %.100s", namebuf, strerror(errno));
- close(*ptyfd);
- return 0;
- }
- return 1;
- }
- return 0;
-#else
- /* BSD-style pty code. */
- char buf[64];
- int i;
- const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
- const char *ptyminors = "0123456789abcdef";
- int num_minors = strlen(ptyminors);
- int num_ptys = strlen(ptymajors) * num_minors;
- struct termios tio;
-
- for (i = 0; i < num_ptys; i++) {
- snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
- ptyminors[i % num_minors]);
- snprintf(namebuf, namebuflen, "/dev/tty%c%c",
- ptymajors[i / num_minors], ptyminors[i % num_minors]);
-
- *ptyfd = open(buf, O_RDWR | O_NOCTTY);
- if (*ptyfd < 0) {
- /* Try SCO style naming */
- snprintf(buf, sizeof buf, "/dev/ptyp%d", i);
- snprintf(namebuf, namebuflen, "/dev/ttyp%d", i);
- *ptyfd = open(buf, O_RDWR | O_NOCTTY);
- if (*ptyfd < 0)
- continue;
- }
-
- /* Open the slave side. */
- *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
- if (*ttyfd < 0) {
- error("%.100s: %.100s", namebuf, strerror(errno));
- close(*ptyfd);
- return 0;
- }
- /* set tty modes to a sane state for broken clients */
- if (tcgetattr(*ptyfd, &tio) < 0)
- log("Getting tty modes for pty failed: %.100s", strerror(errno));
- else {
- tio.c_lflag |= (ECHO | ISIG | ICANON);
- tio.c_oflag |= (OPOST | ONLCR);
- tio.c_iflag |= ICRNL;
-
- /* Set the new modes for the terminal. */
- if (tcsetattr(*ptyfd, TCSANOW, &tio) < 0)
- log("Setting tty modes for pty failed: %.100s", strerror(errno));
- }
-
- return 1;
- }
- return 0;
-#endif /* CRAY */
-#endif /* HAVE_DEV_PTS_AND_PTC */
-#endif /* HAVE_DEV_PTMX */
-#endif /* HAVE__GETPTY */
-#endif /* HAVE_OPENPTY */
-}
-
-/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
-
-void
-pty_release(const char *ttyname)
-{
- if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
- error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
- if (chmod(ttyname, (mode_t) 0666) < 0)
- error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
-}
-
-/* Makes the tty the processes controlling tty and sets it to sane modes. */
-
-void
-pty_make_controlling_tty(int *ttyfd, const char *ttyname)
-{
- int fd;
-#ifdef USE_VHANGUP
- void *old;
-#endif /* USE_VHANGUP */
-
-#ifdef _UNICOS
- if (setsid() < 0)
- error("setsid: %.100s", strerror(errno));
-
- fd = open(ttyname, O_RDWR|O_NOCTTY);
- if (fd != -1) {
- mysignal(SIGHUP, SIG_IGN);
- ioctl(fd, TCVHUP, (char *)NULL);
- mysignal(SIGHUP, SIG_DFL);
- setpgid(0, 0);
- close(fd);
- } else {
- error("Failed to disconnect from controlling tty.");
- }
-
- debug("Setting controlling tty using TCSETCTTY.");
- ioctl(*ttyfd, TCSETCTTY, NULL);
- fd = open("/dev/tty", O_RDWR);
- if (fd < 0)
- error("%.100s: %.100s", ttyname, strerror(errno));
- close(*ttyfd);
- *ttyfd = fd;
-#else /* _UNICOS */
-
- /* First disconnect from the old controlling tty. */
-#ifdef TIOCNOTTY
- fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
- if (fd >= 0) {
- (void) ioctl(fd, TIOCNOTTY, NULL);
- close(fd);
- }
-#endif /* TIOCNOTTY */
- if (setsid() < 0)
- error("setsid: %.100s", strerror(errno));
-
- /*
- * Verify that we are successfully disconnected from the controlling
- * tty.
- */
- fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
- if (fd >= 0) {
- error("Failed to disconnect from controlling tty.");
- close(fd);
- }
- /* Make it our controlling tty. */
-#ifdef TIOCSCTTY
- debug("Setting controlling tty using TIOCSCTTY.");
- if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
- error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
-#endif /* TIOCSCTTY */
-#ifdef HAVE_NEWS4
- if (setpgrp(0,0) < 0)
- error("SETPGRP %s",strerror(errno));
-#endif /* HAVE_NEWS4 */
-#ifdef USE_VHANGUP
- old = mysignal(SIGHUP, SIG_IGN);
- vhangup();
- mysignal(SIGHUP, old);
-#endif /* USE_VHANGUP */
- fd = open(ttyname, O_RDWR);
- if (fd < 0) {
- error("%.100s: %.100s", ttyname, strerror(errno));
- } else {
-#ifdef USE_VHANGUP
- close(*ttyfd);
- *ttyfd = fd;
-#else /* USE_VHANGUP */
- close(fd);
-#endif /* USE_VHANGUP */
- }
- /* Verify that we now have a controlling tty. */
- fd = open(_PATH_TTY, O_WRONLY);
- if (fd < 0)
- error("open /dev/tty failed - could not set controlling tty: %.100s",
- strerror(errno));
- else
- close(fd);
-#endif /* _UNICOS */
-}
-
-/* Changes the window size associated with the pty. */
-
-void
-pty_change_window_size(int ptyfd, int row, int col,
- int xpixel, int ypixel)
-{
- struct winsize w;
-
- w.ws_row = row;
- w.ws_col = col;
- w.ws_xpixel = xpixel;
- w.ws_ypixel = ypixel;
- (void) ioctl(ptyfd, TIOCSWINSZ, &w);
-}
-
-void
-pty_setowner(struct passwd *pw, const char *ttyname)
-{
- struct group *grp;
- gid_t gid;
- mode_t mode;
- struct stat st;
-
- /* Determine the group to make the owner of the tty. */
- grp = getgrnam("tty");
- if (grp) {
- gid = grp->gr_gid;
- mode = S_IRUSR | S_IWUSR | S_IWGRP;
- } else {
- gid = pw->pw_gid;
- mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
- }
-
- /*
- * Change owner and mode of the tty as required.
- * Warn but continue if filesystem is read-only and the uids match/
- * tty is owned by root.
- */
- if (stat(ttyname, &st))
- fatal("stat(%.100s) failed: %.100s", ttyname,
- strerror(errno));
-
- if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
- if (chown(ttyname, pw->pw_uid, gid) < 0) {
- if (errno == EROFS &&
- (st.st_uid == pw->pw_uid || st.st_uid == 0))
- error("chown(%.100s, %u, %u) failed: %.100s",
- ttyname, (u_int)pw->pw_uid, (u_int)gid,
- strerror(errno));
- else
- fatal("chown(%.100s, %u, %u) failed: %.100s",
- ttyname, (u_int)pw->pw_uid, (u_int)gid,
- strerror(errno));
- }
- }
-
- if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
- if (chmod(ttyname, mode) < 0) {
- if (errno == EROFS &&
- (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
- error("chmod(%.100s, 0%o) failed: %.100s",
- ttyname, (int)mode, strerror(errno));
- else
- fatal("chmod(%.100s, 0%o) failed: %.100s",
- ttyname, (int)mode, strerror(errno));
- }
- }
-}