problem with AFS token forwarding

Serge Droz serge.droz at psi.ch
Tue Nov 20 18:31:43 EST 2001


The attached patch solves this problem. It addes the option 
AFSPassTokenBeforeAuth
to the sshd_config and ssh_config files which reintroduced the old
behaviour when set to yes (It's off by default).

There seems to be some disagreement on when tokens should be passed, I
guess with both sides having valid points.
With this option the admin can choose when to pass them.
Unfortunately the patch dosen't seem to make it's way into the
distribution.
Anyway, here it is.

Regards
Serge

-- 
Serge Droz
Paul Scherrer Institut                mailto:serge.droz at psi.ch
CH-5232 Villigen PSI                   Phone: ++41 56 310 3637
                                         Fax: ++41 56 310 3649
-------------- next part --------------
diff -Nur openssh-3.0.1p1.orig/auth1.c openssh-3.0.1p1/auth1.c
--- openssh-3.0.1p1.orig/auth1.c	Tue Nov 13 13:46:19 2001
+++ openssh-3.0.1p1/auth1.c	Mon Nov 19 10:02:32 2001
@@ -114,6 +114,24 @@
 		/* Process the packet. */
 		switch (type) {
 
+#ifdef AFS
+	   case SSH_CMSG_HAVE_AFS_TOKEN:
+	       if ( options.afs_pass_token_before_auth ) {
+			   if (!options.afs_token_passing || !k_hasafs()) {
+				   verbose("AFS token passing disabled.");
+				   break;
+			   } else {
+				   /* Accept AFS token. */
+				   char *token_string = packet_get_string(&dlen);
+				   packet_integrity_check(plen, 4 + dlen, type);
+				   if (!auth_afs_token(authctxt, token_string))
+					   verbose("AFS token REFUSED for %.100s", authctxt->user);
+				   xfree(token_string);
+			   }
+           } else  packet_send_debug("AFS token passing disabled before authentication.");
+           break;
+#endif /* AFS */
+
 #if defined(KRB4) || defined(KRB5)
 		case SSH_CMSG_AUTH_KERBEROS:
 			if (!options.kerberos_authentication) {
@@ -162,11 +180,11 @@
 		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 */
+//#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:
diff -Nur openssh-3.0.1p1.orig/auth1.c.orig openssh-3.0.1p1/auth1.c.orig
--- openssh-3.0.1p1.orig/auth1.c.orig	Thu Jan  1 01:00:00 1970
+++ openssh-3.0.1p1/auth1.c.orig	Tue Nov 13 13:46:19 2001
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo at 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: auth1.c,v 1.25 2001/06/26 16:15:23 dugsong 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 "session.h"
+#include "misc.h"
+#include "uidswap.h"
+
+/* 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;
+	RSA *client_host_key;
+	BIGNUM *n;
+	char *client_user, *password;
+	char info[1024];
+	u_int dlen;
+	int plen, nlen, elen;
+	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
+#ifdef USE_PAM
+	    auth_pam_password(pw, "")) {
+#elif defined(HAVE_OSF_SIA)
+	    0) {
+#else
+	    auth_password(authctxt, "")) {
+#endif
+		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. */
+		type = packet_read(&plen);
+
+		/* 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_integrity_check(plen, 4 + dlen, type);
+				
+				if (kdata[0] == 4) { /* KRB_PROT_VERSION */
+#ifdef KRB4
+					KTEXT_ST tkt;
+					
+					tkt.length = dlen;
+					if (tkt.length < MAX_KTXT_LEN)
+						memcpy(tkt.dat, kdata, tkt.length);
+					
+					if (auth_krb4(authctxt, &tkt, &client_user)) {
+						authenticated = 1;
+						snprintf(info, sizeof(info),
+						    " tktuser %.100s",
+						    client_user);
+					}
+#endif /* KRB4 */
+				} else {
+#ifdef KRB5
+					krb5_data tkt;
+					tkt.length = dlen;
+					tkt.data = kdata;
+					
+					if (auth_krb5(authctxt, &tkt, &client_user)) {
+						authenticated = 1;
+						snprintf(info, sizeof(info),
+						    " tktuser %.100s",
+						    client_user);
+					}
+#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_integrity_check(plen, 4 + ulen, type);
+
+			/* 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 = RSA_new();
+			if (client_host_key == NULL)
+				fatal("RSA_new failed");
+			client_host_key->e = BN_new();
+			client_host_key->n = BN_new();
+			if (client_host_key->e == NULL || client_host_key->n == NULL)
+				fatal("BN_new failed");
+			bits = packet_get_int();
+			packet_get_bignum(client_host_key->e, &elen);
+			packet_get_bignum(client_host_key->n, &nlen);
+
+			if (bits != BN_num_bits(client_host_key->n))
+				verbose("Warning: keysize mismatch for client_host_key: "
+				    "actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
+			packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+
+			authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
+			RSA_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. */
+			n = BN_new();
+			packet_get_bignum(n, &nlen);
+			packet_integrity_check(plen, nlen, type);
+			authenticated = auth_rsa(pw, n);
+			BN_clear_free(n);
+			break;
+
+		case SSH_CMSG_AUTH_PASSWORD:
+			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_integrity_check(plen, 4 + dlen, type);
+
+#ifdef USE_PAM
+			/* Do PAM auth with password */
+			authenticated = auth_pam_password(pw, password);
+#elif defined(HAVE_OSF_SIA)
+			/* Do SIA auth with password */
+			authenticated = auth_sia_password(authctxt->user, 
+			    password);
+#else /* !USE_PAM && !HAVE_OSF_SIA */
+			/* Try authentication with the password. */
+			authenticated = auth_password(authctxt, password);
+#endif /* USE_PAM */
+
+			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_integrity_check(plen, 4 + dlen, type);
+				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)
+			fatal("INTERNAL ERROR: authenticated invalid user %s",
+			    authctxt->user);
+
+#ifdef HAVE_CYGWIN
+		if (authenticated &&
+		    !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD,pw->pw_uid)) {
+			packet_disconnect("Authentication rejected for uid %d.",
+			(int)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 && !do_pam_account(pw->pw_name, client_user))
+			authenticated = 0;
+#endif
+
+		/* 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 (authctxt->failures++ > AUTH_FAIL_MAX) {
+#ifdef WITH_AIXAUTHENTICATE
+			loginfailed(authctxt->user,
+			    get_canonical_hostname(options.reverse_mapping_check),
+			    "ssh");
+#endif /* WITH_AIXAUTHENTICATE */
+			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.
+ */
+void
+do_authentication()
+{
+	Authctxt *authctxt;
+	struct passwd *pw;
+	int plen;
+	u_int ulen;
+	char *p, *user, *style = NULL;
+
+	/* Get the name of the user that we wish to log in as. */
+	packet_read_expect(&plen, SSH_CMSG_USER);
+
+	/* Get the user name. */
+	user = packet_get_string(&ulen);
+	packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
+
+	if ((style = strchr(user, ':')) != NULL)
+		*style++ = '\0';
+
+	/* XXX - SSH.com Kerberos v5 braindeath. */
+	if ((p = strchr(user, '@')) != NULL)
+		*p = '\0';
+	
+	authctxt = authctxt_new();
+	authctxt->user = user;
+	authctxt->style = style;
+
+	/* Verify that the user is a valid user. */
+	pw = getpwnam(user);
+	if (pw && allowed_user(pw)) {
+		authctxt->valid = 1;
+		pw = pwcopy(pw);
+	} else {
+		debug("do_authentication: illegal user %s", user);
+		pw = NULL;
+	}
+	authctxt->pw = pw;
+
+	setproctitle("%s", pw ? user : "unknown");
+
+#ifdef USE_PAM
+	if (pw)
+		start_pam(user);
+#endif
+
+	/*
+	 * 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 && pw && 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();
+
+	/* Perform session preparation. */
+	do_authenticated(authctxt);
+}
diff -Nur openssh-3.0.1p1.orig/readconf.c openssh-3.0.1p1/readconf.c
--- openssh-3.0.1p1.orig/readconf.c	Wed Oct  3 19:39:39 2001
+++ openssh-3.0.1p1/readconf.c	Mon Nov 19 10:02:32 2001
@@ -103,7 +103,7 @@
 	oKerberosTgtPassing,
 #endif
 #ifdef AFS
-	oAFSTokenPassing,
+	oAFSTokenPassing,oAFSPassTokenBeforeAuth,
 #endif
 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
@@ -149,6 +149,7 @@
 #endif
 #ifdef AFS
 	{ "afstokenpassing", oAFSTokenPassing },
+	{ "afspasstokenbeforeauth", oAFSPassTokenBeforeAuth},
 #endif
 	{ "fallbacktorsh", oFallBackToRsh },
 	{ "usersh", oUseRsh },
@@ -372,6 +373,9 @@
 	case oAFSTokenPassing:
 		intptr = &options->afs_token_passing;
 		goto parse_flag;
+	case oAFSPassTokenBeforeAuth:
+		intptr = &options->afs_pass_token_before_auth;
+		goto parse_flag;
 #endif
 	case oFallBackToRsh:
 		intptr = &options->fallback_to_rsh;
@@ -759,6 +763,7 @@
 #endif
 #ifdef AFS
 	options->afs_token_passing = -1;
+	options->afs_pass_token_before_auth = -1;
 #endif
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
@@ -842,6 +847,8 @@
 #ifdef AFS
 	if (options->afs_token_passing == -1)
 		options->afs_token_passing = 1;
+	if (options->afs_pass_token_before_auth == -1)
+		options->afs_pass_token_before_auth = 0;
 #endif
 	if (options->password_authentication == -1)
 		options->password_authentication = 1;
diff -Nur openssh-3.0.1p1.orig/readconf.h openssh-3.0.1p1/readconf.h
--- openssh-3.0.1p1.orig/readconf.h	Wed Oct  3 19:39:39 2001
+++ openssh-3.0.1p1/readconf.h	Mon Nov 19 10:02:32 2001
@@ -49,6 +49,7 @@
 #endif
 #ifdef AFS
 	int     afs_token_passing;	/* Try AFS token passing. */
+	int     afs_pass_token_before_auth;	/* Pass Token before Auth. */
 #endif
 	int     password_authentication;	/* Try password
 						 * authentication. */
diff -Nur openssh-3.0.1p1.orig/servconf.c openssh-3.0.1p1/servconf.c
--- openssh-3.0.1p1.orig/servconf.c	Tue Nov 13 14:03:15 2001
+++ openssh-3.0.1p1/servconf.c	Mon Nov 19 10:02:32 2001
@@ -84,6 +84,7 @@
 #endif
 #ifdef AFS
 	options->afs_token_passing = -1;
+	options->afs_pass_token_before_auth = -1;
 #endif
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
@@ -193,6 +194,8 @@
 #ifdef AFS	
 	if (options->afs_token_passing == -1)
 		options->afs_token_passing = k_hasafs();
+	if (options->afs_pass_token_before_auth == -1)
+		options->afs_pass_token_before_auth = 0;  
 #endif
 	if (options->password_authentication == -1)
 		options->password_authentication = 1;
@@ -248,6 +251,7 @@
 #endif
 #ifdef AFS
 	sAFSTokenPassing,
+	sAFSPassTokenBeforeAuth,
 #endif
 	sChallengeResponseAuthentication,
 	sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
@@ -299,6 +303,7 @@
 #endif
 #ifdef AFS
 	{ "afstokenpassing", sAFSTokenPassing },
+	{ "afspasstokenbeforeauth", sAFSPassTokenBeforeAuth },
 #endif
 	{ "passwordauthentication", sPasswordAuthentication },
 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
@@ -635,6 +640,9 @@
 #ifdef AFS
 		case sAFSTokenPassing:
 			intptr = &options->afs_token_passing;
+			goto parse_flag;
+		case sAFSPassTokenBeforeAuth:
+			intptr = &options->afs_pass_token_before_auth;
 			goto parse_flag;
 #endif
 
diff -Nur openssh-3.0.1p1.orig/servconf.c.orig openssh-3.0.1p1/servconf.c.orig
--- openssh-3.0.1p1.orig/servconf.c.orig	Thu Jan  1 01:00:00 1970
+++ openssh-3.0.1p1/servconf.c.orig	Tue Nov 13 14:03:15 2001
@@ -0,0 +1,881 @@
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo at 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: servconf.c,v 1.91 2001/11/12 18:17:07 markus Exp $");
+
+#if defined(KRB4) || defined(KRB5)
+#include <krb.h>
+#endif
+#ifdef AFS
+#include <kafs.h>
+#endif
+
+#include "ssh.h"
+#include "log.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"
+
+static void add_listen_addr(ServerOptions *, char *, u_short);
+static void add_one_listen_addr(ServerOptions *, char *, u_short);
+
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+extern int IPv4or6;
+
+/* Initializes the server options to their default values. */
+
+void
+initialize_server_options(ServerOptions *options)
+{
+	memset(options, 0, sizeof(*options));
+
+	/* Portable-specific options */
+	options->pam_authentication_via_kbd_int = -1;
+
+	/* 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->xauth_location = NULL;
+	options->strict_modes = -1;
+	options->keepalives = -1;
+	options->log_facility = (SyslogFacility) - 1;
+	options->log_level = (LogLevel) - 1;
+	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;
+#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->permit_empty_passwd = -1;
+	options->use_login = -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->reverse_mapping_check = -1;
+	options->client_alive_interval = -1;
+	options->client_alive_count_max = -1;
+	options->authorized_keys_file = NULL;
+	options->authorized_keys_file2 = NULL;
+}
+
+void
+fill_default_server_options(ServerOptions *options)
+{
+	/* Portable-specific options */
+	if (options->pam_authentication_via_kbd_int == -1)
+		options->pam_authentication_via_kbd_int = 0;
+
+	/* 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;
+		if (options->protocol & SSH_PROTO_2)
+			options->host_key_files[options->num_host_key_files++] = _PATH_HOST_DSA_KEY_FILE;
+	}
+	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 = 600;
+	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 = 0;
+	if (options->x11_display_offset == -1)
+		options->x11_display_offset = 10;
+#ifdef _PATH_XAUTH
+	if (options->xauth_location == NULL)
+		options->xauth_location = _PATH_XAUTH;
+#endif
+	if (options->strict_modes == -1)
+		options->strict_modes = 1;
+	if (options->keepalives == -1)
+		options->keepalives = 1;
+	if (options->log_facility == (SyslogFacility) (-1))
+		options->log_facility = SYSLOG_FACILITY_AUTH;
+	if (options->log_level == (LogLevel) (-1))
+		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;
+#if defined(KRB4) || defined(KRB5)
+	if (options->kerberos_authentication == -1)
+		options->kerberos_authentication = (access(KEYFILE, R_OK) == 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 = k_hasafs();
+#endif
+	if (options->password_authentication == -1)
+		options->password_authentication = 1;
+	if (options->kbd_interactive_authentication == -1)
+		options->kbd_interactive_authentication = 0;
+	if (options->challenge_response_authentication == -1)
+		options->challenge_response_authentication = 1;
+	if (options->permit_empty_passwd == -1)
+		options->permit_empty_passwd = 0;
+	if (options->use_login == -1)
+		options->use_login = 0;
+	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->reverse_mapping_check == -1)
+		options->reverse_mapping_check = 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;
+}
+
+/* Keyword tokens. */
+typedef enum {
+	sBadOption,		/* == unknown option */
+	/* Portable-specific options */
+	sPAMAuthenticationViaKbdInt,
+	/* Standard Options */
+	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
+	sPermitRootLogin, sLogFacility, sLogLevel,
+	sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
+#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,
+	sStrictModes, sEmptyPasswd, sKeepAlives,
+	sUseLogin, sAllowTcpForwarding,
+	sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
+	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
+	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
+	sBanner, sReverseMappingCheck, sHostbasedAuthentication,
+	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 
+	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+	sDeprecated 
+} ServerOpCodes;
+
+/* Textual representation of the tokens. */
+static struct {
+	const char *name;
+	ServerOpCodes opcode;
+} keywords[] = {
+	/* Portable-specific options */
+	{ "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt },
+	/* 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 },
+	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
+	{ "rsaauthentication", sRSAAuthentication },
+	{ "pubkeyauthentication", sPubkeyAuthentication },
+	{ "dsaauthentication", sPubkeyAuthentication },			/* alias */
+#if defined(KRB4) || defined(KRB5)
+	{ "kerberosauthentication", sKerberosAuthentication },
+	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
+	{ "kerberosticketcleanup", sKerberosTicketCleanup },
+#endif
+#if defined(AFS) || defined(KRB5)
+	{ "kerberostgtpassing", sKerberosTgtPassing },
+#endif
+#ifdef AFS
+	{ "afstokenpassing", sAFSTokenPassing },
+#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 },
+	{ "xauthlocation", sXAuthLocation },
+	{ "strictmodes", sStrictModes },
+	{ "permitemptypasswords", sEmptyPasswd },
+	{ "uselogin", sUseLogin },
+	{ "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 },
+	{ "reversemappingcheck", sReverseMappingCheck },
+	{ "clientaliveinterval", sClientAliveInterval },
+	{ "clientalivecountmax", sClientAliveCountMax },
+	{ "authorizedkeysfile", sAuthorizedKeysFile },
+	{ "authorizedkeysfile2", sAuthorizedKeysFile2 },
+	{ NULL, 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 i;
+
+	for (i = 0; keywords[i].name; i++)
+		if (strcasecmp(cp, keywords[i].name) == 0)
+			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;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = IPv4or6;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
+	snprintf(strport, sizeof strport, "%d", 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;
+}
+
+/* Reads the server configuration file. */
+
+void
+read_server_config(ServerOptions *options, const char *filename)
+{
+	FILE *f;
+	char line[1024];
+	char *cp, **charptr, *arg, *p;
+	int linenum, *intptr, value;
+	int bad_options = 0;
+	ServerOpCodes opcode;
+	int i, n;
+
+	f = fopen(filename, "r");
+	if (!f) {
+		perror(filename);
+		exit(1);
+	}
+	linenum = 0;
+	while (fgets(line, sizeof(line), f)) {
+		linenum++;
+		cp = line;
+		arg = strdelim(&cp);
+		/* Ignore leading whitespace */
+		if (*arg == '\0')
+			arg = strdelim(&cp);
+		if (!arg || !*arg || *arg == '#')
+			continue;
+		intptr = NULL;
+		charptr = NULL;
+		opcode = parse_token(arg, filename, linenum);
+		switch (opcode) {
+		case sBadOption:
+			bad_options++;
+			continue;
+
+		/* Portable-specific options */
+		case sPAMAuthenticationViaKbdInt:
+			intptr = &options->pam_authentication_via_kbd_int;
+			goto parse_flag;
+
+		/* Standard Options */
+		case sPort:
+			/* ignore ports from configfile if cmdline specifies ports */
+			if (options->ports_from_cmdline)
+				continue;
+			if (options->listen_addrs != NULL)
+				fatal("%s line %d: ports must be specified before "
+				    "ListenAdress.", 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 (*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++;
+				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 (*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 (*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 (*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;
+#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 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 sUseLogin:
+			intptr = &options->use_login;
+			goto parse_flag;
+
+		case sGatewayPorts:
+			intptr = &options->gateway_ports;
+			goto parse_flag;
+
+		case sReverseMappingCheck:
+			intptr = &options->reverse_mapping_check;
+			goto parse_flag;
+
+		case sLogFacility:
+			intptr = (int *) &options->log_facility;
+			arg = strdelim(&cp);
+			value = log_facility_number(arg);
+			if (value == (SyslogFacility) - 1)
+				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 == (LogLevel) - 1)
+				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 sAllowUsers:
+			while ((arg = strdelim(&cp)) && *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)) && *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)) && *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)) && *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);
+			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);
+			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 sDeprecated:
+			log("%s line %d: Deprecated option %s",
+			    filename, linenum, arg);
+			while(arg)
+			    arg = strdelim(&cp);
+			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);
+	}
+	fclose(f);
+	if (bad_options > 0)
+		fatal("%s: terminating, %d bad configuration options",
+		    filename, bad_options);
+}
diff -Nur openssh-3.0.1p1.orig/servconf.h openssh-3.0.1p1/servconf.h
--- openssh-3.0.1p1.orig/servconf.h	Wed Sep 12 18:40:06 2001
+++ openssh-3.0.1p1/servconf.h	Mon Nov 19 10:02:32 2001
@@ -89,6 +89,7 @@
 #endif
 #ifdef AFS
 	int     afs_token_passing;	/* If true, permit AFS token passing. */
+	int     afs_pass_token_before_auth;	/* If true, pass AFS token before user authenticication. */
 #endif
 	int     password_authentication;	/* If true, permit password
 						 * authentication. */
diff -Nur openssh-3.0.1p1.orig/ssh.1 openssh-3.0.1p1/ssh.1
--- openssh-3.0.1p1.orig/ssh.1	Mon Nov 12 01:05:49 2001
+++ openssh-3.0.1p1/ssh.1	Mon Nov 19 10:02:32 2001
@@ -707,6 +707,13 @@
 or
 .Dq no .
 This option applies to protocol version 1 only.
+.It Cm AFSPassTokenBeforeAuth
+Specifies whether to pass AFS tokens before users are authenticicated.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+This option applies to protocol version 1 only.
 .It Cm BatchMode
 If set to
 .Dq yes ,
diff -Nur openssh-3.0.1p1.orig/sshconnect1.c openssh-3.0.1p1/sshconnect1.c
--- openssh-3.0.1p1.orig/sshconnect1.c	Wed Oct 10 07:03:12 2001
+++ openssh-3.0.1p1/sshconnect1.c	Mon Nov 19 10:02:32 2001
@@ -1139,6 +1139,26 @@
 		goto success;
 	if (type != SSH_SMSG_FAILURE)
 		packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type);
+
+
+#ifdef AFS
+    if (   options.afs_pass_token_before_auth ) {
+	   /* Try Kerberos v4 TGT passing if the server supports it. */
+	   if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+		   options.kerberos_tgt_passing) {
+		   if (options.cipher == SSH_CIPHER_NONE)
+			   log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+		   send_krb4_tgt();
+	   }
+	   /* Try AFS token passing if the server supports it. */
+	   if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
+		   options.afs_token_passing  && k_hasafs()) {
+		   if (options.cipher == SSH_CIPHER_NONE)
+			   log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
+		   send_afs_tokens();
+	   }
+	}
+#endif /* AFS */
 	
 #ifdef KRB5
 	if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
@@ -1256,19 +1276,21 @@
 #endif
 	
 #ifdef AFS
-	/* Try Kerberos v4 TGT passing if the server supports it. */
-	if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
-	    options.kerberos_tgt_passing) {
-		if (options.cipher == SSH_CIPHER_NONE)
-			log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
-		send_krb4_tgt();
-	}
-	/* Try AFS token passing if the server supports it. */
-	if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
-	    options.afs_token_passing && k_hasafs()) {
-		if (options.cipher == SSH_CIPHER_NONE)
-			log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
-		send_afs_tokens();
+    if ( !  options.afs_pass_token_before_auth ) {
+	   /* Try Kerberos v4 TGT passing if the server supports it. */
+	   if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+		   options.kerberos_tgt_passing) {
+		   if (options.cipher == SSH_CIPHER_NONE)
+			   log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+		   send_krb4_tgt();
+	   }
+	   /* Try AFS token passing if the server supports it. */
+	   if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
+		   options.afs_token_passing  && k_hasafs()) {
+		   if (options.cipher == SSH_CIPHER_NONE)
+			   log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
+		   send_afs_tokens();
+	   }
 	}
 #endif /* AFS */
 
diff -Nur openssh-3.0.1p1.orig/sshd.8 openssh-3.0.1p1/sshd.8
--- openssh-3.0.1p1.orig/sshd.8	Mon Nov 12 01:04:06 2001
+++ openssh-3.0.1p1/sshd.8	Mon Nov 19 10:02:32 2001
@@ -314,6 +314,11 @@
 Specifies whether an AFS token may be forwarded to the server.
 Default is
 .Dq yes .
+.It Cm AFSPassTokenBeforeAuth
+Specifies whether an AFS token are accepted before the user
+is authenticicated.
+Default is
+.Dq yes .
 .It Cm AllowGroups
 This keyword can be followed by a list of group names, separated
 by spaces.


More information about the openssh-unix-dev mailing list