summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorHuie-Ying Lee <Huie-Ying.Lee@Sun.COM>2009-11-11 16:01:18 -0800
committerHuie-Ying Lee <Huie-Ying.Lee@Sun.COM>2009-11-11 16:01:18 -0800
commitb07b2f5c1a9b43b43daa3f5087f57ede3d664810 (patch)
tree7040e12414e5c172ebe7a7924ecc5f2e3e39a686 /usr/src
parentb7fbedc2072fd071d2ea5044dcedc840f7d03749 (diff)
downloadillumos-gate-b07b2f5c1a9b43b43daa3f5087f57ede3d664810.tar.gz
6655613 resync server's conditional Match block from OpenSSH
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/ssh/include/groupaccess.h3
-rw-r--r--usr/src/cmd/ssh/include/match.h5
-rw-r--r--usr/src/cmd/ssh/include/servconf.h10
-rw-r--r--usr/src/cmd/ssh/libssh/Makefile.com17
-rw-r--r--usr/src/cmd/ssh/libssh/common/addrmatch.c424
-rw-r--r--usr/src/cmd/ssh/libssh/common/uidswap.c1
-rw-r--r--usr/src/cmd/ssh/sshd/auth-pam.c3
-rw-r--r--usr/src/cmd/ssh/sshd/auth.c7
-rw-r--r--usr/src/cmd/ssh/sshd/auth2-gss.c6
-rw-r--r--usr/src/cmd/ssh/sshd/groupaccess.c26
-rw-r--r--usr/src/cmd/ssh/sshd/servconf.c487
-rw-r--r--usr/src/cmd/ssh/sshd/sshd.c11
-rw-r--r--usr/src/cmd/ssh/sshd/sshlogin.c1
13 files changed, 872 insertions, 129 deletions
diff --git a/usr/src/cmd/ssh/include/groupaccess.h b/usr/src/cmd/ssh/include/groupaccess.h
index 19553054d5..bc40898888 100644
--- a/usr/src/cmd/ssh/include/groupaccess.h
+++ b/usr/src/cmd/ssh/include/groupaccess.h
@@ -3,8 +3,6 @@
#ifndef _GROUPACCESS_H
#define _GROUPACCESS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -38,6 +36,7 @@ extern "C" {
int ga_init(const char *, gid_t);
int ga_match(char * const *, int);
+int ga_match_pattern_list(const char *);
void ga_free(void);
#ifdef __cplusplus
diff --git a/usr/src/cmd/ssh/include/match.h b/usr/src/cmd/ssh/include/match.h
index 6e3611dfa8..81729c33da 100644
--- a/usr/src/cmd/ssh/include/match.h
+++ b/usr/src/cmd/ssh/include/match.h
@@ -3,8 +3,6 @@
#ifndef _MATCH_H
#define _MATCH_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -29,6 +27,9 @@ int match_host_and_ip(const char *, const char *, const char *);
int match_user(const char *, const char *, const char *, const char *);
char *match_list(const char *, const char *, u_int *);
+/* addrmatch.c */
+int addr_match_list(const char *, const char *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/ssh/include/servconf.h b/usr/src/cmd/ssh/include/servconf.h
index f222b8596d..1058d00b47 100644
--- a/usr/src/cmd/ssh/include/servconf.h
+++ b/usr/src/cmd/ssh/include/servconf.h
@@ -167,9 +167,15 @@ typedef struct {
} ServerOptions;
void initialize_server_options(ServerOptions *);
-void read_server_config(ServerOptions *, const char *);
void fill_default_server_options(ServerOptions *);
-int process_server_config_line(ServerOptions *, char *, const char *, int);
+int process_server_config_line(ServerOptions *, char *, const char *, int,
+ int *, const char *, const char *, const char *);
+void load_server_config(const char *, Buffer *);
+void parse_server_config(ServerOptions *, const char *, Buffer *,
+ const char *, const char *, const char *);
+void parse_server_match_config(ServerOptions *, const char *, const char *,
+ const char *);
+void copy_set_server_options(ServerOptions *, ServerOptions *, int);
int chroot_requested(char *chroot_directory);
#ifdef __cplusplus
diff --git a/usr/src/cmd/ssh/libssh/Makefile.com b/usr/src/cmd/ssh/libssh/Makefile.com
index 990c704732..32461911bf 100644
--- a/usr/src/cmd/ssh/libssh/Makefile.com
+++ b/usr/src/cmd/ssh/libssh/Makefile.com
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -26,6 +26,7 @@ LIBRARY = libssh.a
VERS = .1
OBJECTS = \
+ addrmatch.o \
atomicio.o \
authfd.o \
authfile.o \
@@ -42,10 +43,9 @@ OBJECTS = \
dh.o \
dispatch.o \
engine.o \
+ entropy.o \
fatal.o \
g11n.o \
- mac.o \
- msg.o \
hostfile.o \
key.o \
kex.o \
@@ -58,16 +58,20 @@ OBJECTS = \
kexgssc.o \
kexgsss.o \
log.o \
+ mac.o \
match.o \
misc.o \
mpaux.o \
+ msg.o \
nchan.o \
packet.o \
progressmeter.o \
+ proxy-io.o \
radix.o \
- entropy.o \
+ readconf.o \
readpass.o \
rsa.o \
+ sftp-common.o \
ssh-dss.o \
ssh-gss.o \
ssh-rsa.o \
@@ -76,10 +80,7 @@ OBJECTS = \
uidswap.o \
uuencode.o \
xlist.o \
- xmalloc.o \
- readconf.o \
- sftp-common.o \
- proxy-io.o
+ xmalloc.o
include $(SRC)/lib/Makefile.lib
diff --git a/usr/src/cmd/ssh/libssh/common/addrmatch.c b/usr/src/cmd/ssh/libssh/common/addrmatch.c
new file mode 100644
index 0000000000..d39885b7bd
--- /dev/null
+++ b/usr/src/cmd/ssh/libssh/common/addrmatch.c
@@ -0,0 +1,424 @@
+/* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */
+
+/*
+ * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "match.h"
+#include "log.h"
+#include "xmalloc.h"
+
+struct xaddr {
+ sa_family_t af;
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ u_int8_t addr8[16];
+ u_int32_t addr32[4];
+ } xa; /* 128-bit address */
+ u_int32_t scope_id; /* iface scope id for v6 */
+#define v4 xa.v4
+#define v6 xa.v6
+#define addr8 xa.addr8
+#define addr32 xa.addr32
+};
+
+static int
+addr_unicast_masklen(int af)
+{
+ switch (af) {
+ case AF_INET:
+ return 32;
+ case AF_INET6:
+ return 128;
+ default:
+ return -1;
+ }
+}
+
+static inline int
+masklen_valid(int af, u_int masklen)
+{
+ switch (af) {
+ case AF_INET:
+ return masklen <= 32 ? 0 : -1;
+ case AF_INET6:
+ return masklen <= 128 ? 0 : -1;
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Convert struct sockaddr to struct xaddr
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
+{
+ struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
+
+ memset(xa, '\0', sizeof(*xa));
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (slen < sizeof(*in4))
+ return -1;
+ xa->af = AF_INET;
+ memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
+ break;
+ case AF_INET6:
+ if (slen < sizeof(*in6))
+ return -1;
+ xa->af = AF_INET6;
+ memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ xa->scope_id = in6->sin6_scope_id;
+#endif
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Calculate a netmask of length 'l' for address family 'af' and
+ * store it in 'n'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_netmask(int af, u_int l, struct xaddr *n)
+{
+ int i;
+
+ if (masklen_valid(af, l) != 0 || n == NULL)
+ return -1;
+
+ memset(n, '\0', sizeof(*n));
+ switch (af) {
+ case AF_INET:
+ n->af = AF_INET;
+ n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
+ return 0;
+ case AF_INET6:
+ n->af = AF_INET6;
+ for (i = 0; i < 4 && l >= 32; i++, l -= 32)
+ n->addr32[i] = 0xffffffffU;
+ if (i < 4 && l != 0)
+ n->addr32[i] = htonl((0xffffffff << (32 - l)) &
+ 0xffffffff);
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
+{
+ int i;
+
+ if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
+ return -1;
+
+ memcpy(dst, a, sizeof(*dst));
+ switch (a->af) {
+ case AF_INET:
+ dst->v4.s_addr &= b->v4.s_addr;
+ return 0;
+ case AF_INET6:
+ dst->scope_id = a->scope_id;
+ for (i = 0; i < 4; i++)
+ dst->addr32[i] &= b->addr32[i];
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Compare addresses 'a' and 'b'
+ * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b)
+ */
+static int
+addr_cmp(const struct xaddr *a, const struct xaddr *b)
+{
+ int i;
+
+ if (a->af != b->af)
+ return a->af == AF_INET6 ? 1 : -1;
+
+ switch (a->af) {
+ case AF_INET:
+ if (a->v4.s_addr == b->v4.s_addr)
+ return 0;
+ return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1;
+ case AF_INET6:
+ for (i = 0; i < 16; i++)
+ if (a->addr8[i] - b->addr8[i] != 0)
+ return a->addr8[i] > b->addr8[i] ? 1 : -1;
+ if (a->scope_id == b->scope_id)
+ return 0;
+ return a->scope_id > b->scope_id ? 1 : -1;
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Parse string address 'p' into 'n'
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_pton(const char *p, struct xaddr *n)
+{
+ struct addrinfo hints, *ai;
+
+ memset(&hints, '\0', sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
+ return -1;
+
+ if (ai == NULL || ai->ai_addr == NULL)
+ return -1;
+
+ if (n != NULL &&
+ addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
+ freeaddrinfo(ai);
+ return -1;
+ }
+
+ freeaddrinfo(ai);
+ return 0;
+}
+
+/*
+ * Perform bitwise negation of address
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_invert(struct xaddr *n)
+{
+ int i;
+
+ if (n == NULL)
+ return (-1);
+
+ switch (n->af) {
+ case AF_INET:
+ n->v4.s_addr = ~n->v4.s_addr;
+ return (0);
+ case AF_INET6:
+ for (i = 0; i < 4; i++)
+ n->addr32[i] = ~n->addr32[i];
+ return (0);
+ default:
+ return (-1);
+ }
+}
+
+/*
+ * Calculate a netmask of length 'l' for address family 'af' and
+ * store it in 'n'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_hostmask(int af, u_int l, struct xaddr *n)
+{
+ if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)
+ * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.
+ */
+static int
+addr_is_all0s(const struct xaddr *a)
+{
+ int i;
+
+ switch (a->af) {
+ case AF_INET:
+ return (a->v4.s_addr == 0 ? 0 : -1);
+ case AF_INET6:;
+ for (i = 0; i < 4; i++)
+ if (a->addr32[i] != 0)
+ return (-1);
+ return (0);
+ default:
+ return (-1);
+ }
+}
+
+/*
+ * Test whether host portion of address 'a', as determined by 'masklen'
+ * is all zeros.
+ * Returns 0 on if host portion of address is all-zeros,
+ * -1 if not all zeros or on failure.
+ */
+static int
+addr_host_is_all0s(const struct xaddr *a, u_int masklen)
+{
+ struct xaddr tmp_addr, tmp_mask, tmp_result;
+
+ memcpy(&tmp_addr, a, sizeof(tmp_addr));
+ if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
+ return (-1);
+ if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
+ return (-1);
+ return (addr_is_all0s(&tmp_result));
+}
+
+/*
+ * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
+ * Return -1 on parse error, -2 on inconsistency or 0 on success.
+ */
+static int
+addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
+{
+ struct xaddr tmp;
+ long unsigned int masklen = 999;
+ char addrbuf[64], *mp, *cp;
+
+ /* Don't modify argument */
+ if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) > sizeof(addrbuf))
+ return -1;
+
+ if ((mp = strchr(addrbuf, '/')) != NULL) {
+ *mp = '\0';
+ mp++;
+ masklen = strtoul(mp, &cp, 10);
+ if (*mp == '\0' || *cp != '\0' || masklen > 128)
+ return -1;
+ }
+
+ if (addr_pton(addrbuf, &tmp) == -1)
+ return -1;
+
+ if (mp == NULL)
+ masklen = addr_unicast_masklen(tmp.af);
+ if (masklen_valid(tmp.af, masklen) == -1)
+ return -2;
+ if (addr_host_is_all0s(&tmp, masklen) != 0)
+ return -2;
+
+ if (n != NULL)
+ memcpy(n, &tmp, sizeof(*n));
+ if (l != NULL)
+ *l = masklen;
+
+ return 0;
+}
+
+static int
+addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
+{
+ struct xaddr tmp_mask, tmp_result;
+
+ if (host->af != net->af)
+ return -1;
+
+ if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
+ return -1;
+ if (addr_and(&tmp_result, host, &tmp_mask) == -1)
+ return -1;
+ return addr_cmp(&tmp_result, net);
+}
+
+/*
+ * Match "addr" against list pattern list "_list", which may contain a
+ * mix of CIDR addresses and old-school wildcards.
+ *
+ * If addr is NULL, then no matching is performed, but _list is parsed
+ * and checked for well-formedness.
+ *
+ * Returns 1 on match found (never returned when addr == NULL).
+ * Returns 0 on if no match found, or no errors found when addr == NULL.
+ * Returns -1 on negated match found (never returned when addr == NULL).
+ * Returns -2 on invalid list entry.
+ */
+int
+addr_match_list(const char *addr, const char *_list)
+{
+ char *list, *cp, *o;
+ struct xaddr try_addr, match_addr;
+ u_int masklen, neg;
+ int ret = 0, r;
+
+ if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
+ debug2("%s: couldn't parse address %.100s", __func__, addr);
+ return 0;
+ }
+ if ((o = list = strdup(_list)) == NULL)
+ return -1;
+ while ((cp = strsep(&list, ",")) != NULL) {
+ neg = *cp == '!';
+ if (neg)
+ cp++;
+ if (*cp == '\0') {
+ ret = -2;
+ break;
+ }
+ /* Prefer CIDR address matching */
+ r = addr_pton_cidr(cp, &match_addr, &masklen);
+ if (r == -2) {
+ error("Inconsistent mask length for "
+ "network \"%.100s\"", cp);
+ ret = -2;
+ break;
+ } else if (r == 0) {
+ if (addr != NULL && addr_netmatch(&try_addr,
+ &match_addr, masklen) == 0) {
+ foundit:
+ if (neg) {
+ ret = -1;
+ break;
+ }
+ ret = 1;
+ }
+ continue;
+ } else {
+ /* If CIDR parse failed, try wildcard string match */
+ if (addr != NULL && match_pattern(addr, cp) == 1)
+ goto foundit;
+ }
+ }
+ xfree(o);
+
+ return ret;
+}
diff --git a/usr/src/cmd/ssh/libssh/common/uidswap.c b/usr/src/cmd/ssh/libssh/common/uidswap.c
index f5892ee2ac..32256b4718 100644
--- a/usr/src/cmd/ssh/libssh/common/uidswap.c
+++ b/usr/src/cmd/ssh/libssh/common/uidswap.c
@@ -22,6 +22,7 @@ RCSID("$OpenBSD: uidswap.c,v 1.23 2002/07/15 17:15:31 stevesk Exp $");
#include "log.h"
#include "uidswap.h"
+#include "buffer.h"
#include "servconf.h"
/*
diff --git a/usr/src/cmd/ssh/sshd/auth-pam.c b/usr/src/cmd/ssh/sshd/auth-pam.c
index 960e4d595f..01c34c7c9a 100644
--- a/usr/src/cmd/ssh/sshd/auth-pam.c
+++ b/usr/src/cmd/ssh/sshd/auth-pam.c
@@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,6 +34,7 @@
#include "auth.h"
#include "auth-options.h"
#include "auth-pam.h"
+#include "buffer.h"
#include "servconf.h"
#include "canohost.h"
#include "compat.h"
diff --git a/usr/src/cmd/ssh/sshd/auth.c b/usr/src/cmd/ssh/sshd/auth.c
index e9712d855a..9df2117ea8 100644
--- a/usr/src/cmd/ssh/sshd/auth.c
+++ b/usr/src/cmd/ssh/sshd/auth.c
@@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,11 +44,11 @@ RCSID("$OpenBSD: auth.c,v 1.45 2002/09/20 18:41:29 stevesk Exp $");
#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 "buffer.h"
#include "bufaux.h"
#include "uidswap.h"
#include "tildexpand.h"
@@ -582,6 +582,9 @@ getpwnamallow(const char *user)
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",
diff --git a/usr/src/cmd/ssh/sshd/auth2-gss.c b/usr/src/cmd/ssh/sshd/auth2-gss.c
index d43d78d021..8525707c1e 100644
--- a/usr/src/cmd/ssh/sshd/auth2-gss.c
+++ b/usr/src/cmd/ssh/sshd/auth2-gss.c
@@ -22,23 +22,21 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "includes.h"
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#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 "buffer.h"
#include "bufaux.h"
#include "packet.h"
diff --git a/usr/src/cmd/ssh/sshd/groupaccess.c b/usr/src/cmd/ssh/sshd/groupaccess.c
index 728466112b..2d8aa3ca80 100644
--- a/usr/src/cmd/ssh/sshd/groupaccess.c
+++ b/usr/src/cmd/ssh/sshd/groupaccess.c
@@ -25,8 +25,6 @@
#include "includes.h"
RCSID("$OpenBSD: groupaccess.c,v 1.5 2002/03/04 17:27:39 stevesk Exp $");
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "groupaccess.h"
#include "xmalloc.h"
#include "match.h"
@@ -75,6 +73,30 @@ ga_match(char * const *groups, int n)
}
/*
+ * 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
diff --git a/usr/src/cmd/ssh/sshd/servconf.c b/usr/src/cmd/ssh/sshd/servconf.c
index 6d91626b13..983f0fb5ab 100644
--- a/usr/src/cmd/ssh/sshd/servconf.c
+++ b/usr/src/cmd/ssh/sshd/servconf.c
@@ -38,6 +38,7 @@ RCSID("$OpenBSD: servconf.c,v 1.115 2002/09/04 18:52:42 stevesk Exp $");
#include "ssh.h"
#include "log.h"
+#include "buffer.h"
#include "servconf.h"
#include "xmalloc.h"
#include "compat.h"
@@ -48,10 +49,14 @@ RCSID("$OpenBSD: servconf.c,v 1.115 2002/09/04 18:52:42 stevesk Exp $");
#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;
@@ -415,103 +420,111 @@ typedef enum {
sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
sMaxAuthTries, sMaxAuthTriesLog, sUsePrivilegeSeparation,
sLookupClientHostnames, sUseOpenSSLEngine, sChrootDirectory,
+ sMatch,
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 },
+ { "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt, SSHCFG_GLOBAL },
/* Standard Options */
- { "port", sPort },
- { "hostkey", sHostKeyFile },
- { "hostdsakey", sHostKeyFile }, /* alias */
- { "pidfile", sPidFile },
- { "serverkeybits", sServerKeyBits },
- { "logingracetime", sLoginGraceTime },
- { "keyregenerationinterval", sKeyRegenerationTime },
- { "permitrootlogin", sPermitRootLogin },
- { "syslogfacility", sLogFacility },
- { "loglevel", sLogLevel },
- { "rhostsauthentication", sRhostsAuthentication },
- { "rhostsrsaauthentication", sRhostsRSAAuthentication },
- { "hostbasedauthentication", sHostbasedAuthentication },
+ { "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 },
- { "pubkeyauthentication", sPubkeyAuthentication },
- { "dsaauthentication", sPubkeyAuthentication }, /* alias */
+ { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
+ { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
+ { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
#ifdef GSSAPI
- { "gssapiauthentication", sGssAuthentication },
- { "gssapikeyexchange", sGssKeyEx },
- { "gssapistoredelegatedcredentials", sGssStoreDelegCreds },
- { "gssauthentication", sGssAuthentication }, /* alias */
- { "gsskeyex", sGssKeyEx }, /* alias */
- { "gssstoredelegcreds", sGssStoreDelegCreds }, /* alias */
+ { "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 },
- { "gssusesessioncredcache", sGssUseSessionCredCache },
- { "gsscleanupcreds", sGssCleanupCreds },
+ { "gssusesessionccache", sGssUseSessionCredCache, SSHCFG_GLOBAL },
+ { "gssusesessioncredcache", sGssUseSessionCredCache, SSHCFG_GLOBAL },
+ { "gsscleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
#endif /* SUNW_GSSAPI */
#endif
#if defined(KRB4) || defined(KRB5)
- { "kerberosauthentication", sKerberosAuthentication },
- { "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
- { "kerberosticketcleanup", sKerberosTicketCleanup },
+ { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
+ { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
+ { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
#endif
#if defined(AFS) || defined(KRB5)
- { "kerberostgtpassing", sKerberosTgtPassing },
+ { "kerberostgtpassing", sKerberosTgtPassing, SSHCFG_GLOBAL },
#endif
#ifdef AFS
- { "afstokenpassing", sAFSTokenPassing },
+ { "afstokenpassing", sAFSTokenPassing, SSHCFG_GLOBAL },
#endif
- { "passwordauthentication", sPasswordAuthentication },
- { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
- { "challengeresponseauthentication", sChallengeResponseAuthentication },
- { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
- { "checkmail", sDeprecated },
- { "listenaddress", sListenAddress },
- { "printmotd", sPrintMotd },
- { "printlastlog", sPrintLastLog },
- { "ignorerhosts", sIgnoreRhosts },
- { "ignoreuserknownhosts", sIgnoreUserKnownHosts },
- { "x11forwarding", sX11Forwarding },
- { "x11displayoffset", sX11DisplayOffset },
- { "x11uselocalhost", sX11UseLocalhost },
- { "xauthlocation", sXAuthLocation },
- { "strictmodes", sStrictModes },
- { "permitemptypasswords", sEmptyPasswd },
- { "permituserenvironment", sPermitUserEnvironment },
- { "uselogin", sUseLogin },
- { "compression", sCompression },
- { "keepalive", sKeepAlives },
- { "allowtcpforwarding", sAllowTcpForwarding },
- { "allowusers", sAllowUsers },
- { "denyusers", sDenyUsers },
- { "allowgroups", sAllowGroups },
- { "denygroups", sDenyGroups },
- { "ciphers", sCiphers },
- { "macs", sMacs },
- { "protocol", sProtocol },
- { "gatewayports", sGatewayPorts },
- { "subsystem", sSubsystem },
- { "maxstartups", sMaxStartups },
- { "banner", sBanner },
- { "verifyreversemapping", sVerifyReverseMapping },
- { "reversemappingcheck", sVerifyReverseMapping },
- { "clientaliveinterval", sClientAliveInterval },
- { "clientalivecountmax", sClientAliveCountMax },
- { "authorizedkeysfile", sAuthorizedKeysFile },
- { "authorizedkeysfile2", sAuthorizedKeysFile2 },
- { "maxauthtries", sMaxAuthTries },
- { "maxauthtrieslog", sMaxAuthTriesLog },
- { "useprivilegeseparation", sUsePrivilegeSeparation},
- { "lookupclienthostnames", sLookupClientHostnames},
- { "useopensslengine", sUseOpenSSLEngine},
- { "chrootdirectory", sChrootDirectory},
- { NULL, sBadOption }
+ { "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 },
+ { "keepalive", sKeepAlives, SSHCFG_GLOBAL },
+ { "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 },
+ { "match", sMatch, SSHCFG_ALL },
+
+ { NULL, sBadOption, 0 }
};
/*
@@ -520,13 +533,15 @@ static struct {
static ServerOpCodes
parse_token(const char *cp, const char *filename,
- int linenum)
+ int linenum, u_int *flags)
{
u_int i;
for (i = 0; keywords[i].name; i++)
- if (strcasecmp(cp, keywords[i].name) == 0)
+ 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);
@@ -569,13 +584,150 @@ add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
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)) && *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)
+ const char *filename, int linenum, int *activep, const char *user,
+ const char *host, const char *address)
{
char *cp, **charptr, *arg, *p;
- int *intptr, value, i, n;
+ int cmdline = 0, *intptr, value, n;
ServerOpCodes opcode;
+ u_int i, flags = 0;
size_t len;
cp = line;
@@ -587,7 +739,25 @@ process_server_config_line(ServerOptions *options, char *line,
return 0;
intptr = NULL;
charptr = NULL;
- opcode = parse_token(arg, filename, linenum);
+ 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:
@@ -625,7 +795,7 @@ parse_int:
fatal("%s line %d: missing integer value.",
filename, linenum);
value = atoi(arg);
- if (*intptr == -1)
+ if (*activep && *intptr == -1)
*intptr = value;
break;
@@ -695,7 +865,7 @@ parse_filename:
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
- if (*charptr == NULL) {
+ if (*activep && *charptr == NULL) {
*charptr = tilde_expand_filename(arg, getuid());
/* increase optional counter */
if (intptr != NULL)
@@ -727,7 +897,7 @@ parse_filename:
fatal("%s line %d: Bad yes/"
"without-password/forced-commands-only/no "
"argument: %s", filename, linenum, arg);
- if (*intptr == -1)
+ if (*activep && *intptr == -1)
*intptr = value;
break;
@@ -746,7 +916,7 @@ parse_flag:
else
fatal("%s line %d: Bad yes/no argument: %s",
filename, linenum, arg);
- if (*intptr == -1)
+ if (*activep && *intptr == -1)
*intptr = value;
break;
@@ -884,16 +1054,23 @@ parse_flag:
goto parse_flag;
case sGatewayPorts:
+ intptr = &options->gateway_ports;
arg = strdelim(&cp);
- if (get_yes_no_flag(&options->gateway_ports, arg, filename,
- linenum, 1) == 1)
- break;
-
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing yes/no/clientspecified "
+ "argument.", filename, linenum);
+ value = 0; /* silence compiler */
if (strcmp(arg, "clientspecified") == 0)
- options->gateway_ports = 2;
+ value = 2;
+ else if (strcmp(arg, "yes") == 0)
+ value = 1;
+ else if (strcmp(arg, "no") == 0)
+ value = 0;
else
- fatal("%.200s line %d: Bad yes/no/clientspecified "
- "argument.", filename, linenum);
+ fatal("%s line %d: Bad yes/no/clientspecified "
+ "argument: %s", filename, linenum, arg);
+ if (*activep && *intptr == -1)
+ *intptr = value;
break;
case sVerifyReverseMapping:
@@ -1016,6 +1193,10 @@ parse_flag:
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.",
@@ -1113,10 +1294,21 @@ parse_flag:
if (arg == NULL || *arg == '\0')
fatal("%s line %d: missing directory name for "
"ChrootDirectory.", filename, linenum);
- if (*charptr == NULL)
+ if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
+ 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);
@@ -1134,33 +1326,122 @@ parse_flag:
return 0;
}
+
/* Reads the server configuration file. */
void
-read_server_config(ServerOptions *options, const char *filename)
+load_server_config(const char *filename, Buffer *conf)
{
- int linenum, bad_options = 0;
- char line[1024];
+ char line[1024], *cp;
FILE *f;
- f = fopen(filename, "r");
- if (!f) {
+ debug2("%s: filename %s", __func__, filename);
+ if ((f = fopen(filename, "r")) == NULL) {
perror(filename);
exit(1);
}
- linenum = 0;
+ buffer_clear(conf);
while (fgets(line, sizeof(line), f)) {
- /* Update line number counter. */
- linenum++;
- if (process_server_config_line(options, line, filename, linenum) != 0)
+ /*
+ * 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++;
}
- (void) fclose(f);
+ 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.
diff --git a/usr/src/cmd/ssh/sshd/sshd.c b/usr/src/cmd/ssh/sshd/sshd.c
index 44ab561920..98e5570fee 100644
--- a/usr/src/cmd/ssh/sshd/sshd.c
+++ b/usr/src/cmd/ssh/sshd/sshd.c
@@ -223,6 +223,9 @@ u_int utmp_len = MAXHOSTNAMELEN;
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 */
@@ -939,7 +942,7 @@ main(int ac, char **av)
break;
case 'o':
if (process_server_config_line(&options, optarg,
- "command-line", 0) != 0)
+ "command-line", 0, NULL, NULL, NULL, NULL) != 0)
exit(1);
break;
case '?':
@@ -974,8 +977,10 @@ main(int ac, char **av)
drop_cray_privs();
#endif
- /* Read server configuration options from the configuration file. */
- read_server_config(&options, config_file_name);
+ /* Fetch our configuration */
+ buffer_init(&cfg);
+ load_server_config(config_file_name, &cfg);
+ parse_server_config(&options, config_file_name, &cfg, NULL, NULL, NULL);
/* Fill in default values for those options not explicitly set. */
fill_default_server_options(&options);
diff --git a/usr/src/cmd/ssh/sshd/sshlogin.c b/usr/src/cmd/ssh/sshd/sshlogin.c
index 53a3d6e299..c21877355c 100644
--- a/usr/src/cmd/ssh/sshd/sshlogin.c
+++ b/usr/src/cmd/ssh/sshd/sshlogin.c
@@ -47,6 +47,7 @@ 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"