- Merged more OpenBSD CVS changes:
   - [auth-krb4.c auth-passwd.c] remove x11- and krb-cleanup from fatal()
     + krb-cleanup cleanup
   - [clientloop.c log-client.c log-server.c ]
     [readconf.c readconf.h servconf.c servconf.h ]
     [ssh.1 ssh.c ssh.h sshd.8]
     add LogLevel {QUIET, FATAL, ERROR, INFO, CHAT, DEBUG} to ssh/sshd,
     obsoletes QuietMode and FascistLogging in sshd.
diff --git a/ChangeLog b/ChangeLog
index a1bfb21..4971a44 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,8 +7,15 @@
    - [sshd.8] user/958: check ~/.ssh/known_hosts for rhosts-rsa, too
  - Fix integer overflow which was messing up scp's progress bar for large 
    file transfers. Fix submitted to OpenBSD developers.
- - Released 1.2pre10
-
+ - Merged more OpenBSD CVS changes:
+   - [auth-krb4.c auth-passwd.c] remove x11- and krb-cleanup from fatal() 
+     + krb-cleanup cleanup
+   - [clientloop.c log-client.c log-server.c ]
+     [readconf.c readconf.h servconf.c servconf.h ]
+     [ssh.1 ssh.c ssh.h sshd.8]
+     add LogLevel {QUIET, FATAL, ERROR, INFO, CHAT, DEBUG} to ssh/sshd,
+     obsoletes QuietMode and FascistLogging in sshd.
+     
 19991110
  - Merged several minor fixed:
    - ssh-agent commandline parsing
diff --git a/Makefile.in b/Makefile.in
index 0d239e8..bd7950a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -30,7 +30,7 @@
 
 all: $(OBJS) $(TARGETS)
 
-libssh.a: authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o hostfile.o match.o mpaux.o nchan.o packet.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o helper.o rc4.o mktemp.o strlcpy.o
+libssh.a: authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o hostfile.o match.o mpaux.o nchan.o packet.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o helper.o rc4.o mktemp.o strlcpy.o log.o
 	$(AR) rv $@ $^
 	$(RANLIB) $@
 
diff --git a/acconfig.h b/acconfig.h
index 063b917..56075fd 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -20,3 +20,17 @@
 
 /* Define is libutil has login() function */
 #undef HAVE_LIBUTIL_LOGIN
+
+
+/* Shouldn't need to edit below this line *************************** */
+#ifndef SHUT_RDWR
+enum
+{
+  SHUT_RD = 0,    /* No more receptions.  */
+#define SHUT_RD   SHUT_RD
+  SHUT_WR,    /* No more transmissions.  */
+#define SHUT_WR   SHUT_WR
+  SHUT_RDWR   /* No more receptions or transmissions.  */
+#define SHUT_RDWR SHUT_RDWR
+};
+#endif
diff --git a/auth-krb4.c b/auth-krb4.c
index 6e8a6ba..0320523 100644
--- a/auth-krb4.c
+++ b/auth-krb4.c
@@ -6,7 +6,7 @@
 
    Kerberos v4 authentication and ticket-passing routines.
 
-   $Id: auth-krb4.c,v 1.2 1999/11/08 04:49:41 damien Exp $
+   $Id: auth-krb4.c,v 1.3 1999/11/11 06:57:39 damien Exp $
 */
 
 #include "includes.h"
@@ -15,38 +15,59 @@
 #include "ssh.h"
 
 #ifdef KRB4
-int ssh_tf_init(uid_t uid)
+char *ticket = NULL;
+
+void
+krb4_cleanup_proc(void *ignore)
 {
-  extern char *ticket;
+  debug("krb4_cleanup_proc called");
+  
+  if (ticket) {
+    (void) dest_tkt();
+    xfree(ticket);
+    ticket = NULL;
+  }
+}
+
+int krb4_init(uid_t uid)
+{
+  static int cleanup_registered = 0;
   char *tkt_root = TKT_ROOT;
   struct stat st;
   int fd;
-  
-  /* Set unique ticket string manually since we're still root. */
-  ticket = xmalloc(MAXPATHLEN);
-#ifdef AFS
-  if (lstat("/ticket", &st) != -1)
-    tkt_root = "/ticket/";
-#endif /* AFS */
-  snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid());
-  (void) krb_set_tkt_string(ticket);
 
-  /* Make sure we own this ticket file, and we created it. */
-  if (lstat(ticket, &st) == -1 && errno == ENOENT) {
-    /* good, no ticket file exists. create it. */
-    if ((fd = open(ticket, O_RDWR|O_CREAT|O_EXCL, 0600)) != -1) {
-      close(fd);
-      return 1;
-    }
+  if (!ticket) {
+    /* Set unique ticket string manually since we're still root. */
+    ticket = xmalloc(MAXPATHLEN);
+#ifdef AFS
+    if (lstat("/ticket", &st) != -1)
+      tkt_root = "/ticket/";
+#endif /* AFS */
+    snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid());
+    (void) krb_set_tkt_string(ticket);
   }
-  else {
-    /* file exists. make sure server_user owns it (e.g. just passed ticket),
-       and that it isn't a symlink, and that it is mode 600. */
+  /* Register ticket cleanup in case of fatal error. */
+  if (!cleanup_registered) {
+    fatal_add_cleanup(krb4_cleanup_proc, NULL);
+    cleanup_registered = 1;
+  }
+  /* Try to create our ticket file. */
+  if ((fd = mkstemp(ticket)) != -1) {
+    close(fd);
+    return 1;
+  }
+  /* Ticket file exists - make sure user owns it (just passed ticket). */
+  if (lstat(ticket, &st) != -1) {
     if (st.st_mode == (S_IFREG|S_IRUSR|S_IWUSR) && st.st_uid == uid)
       return 1;
   }
-  /* Failure. */
+  /* Failure - cancel cleanup function, leaving bad ticket for inspection. */
   log("WARNING: bad ticket file %s", ticket);
+  fatal_remove_cleanup(krb4_cleanup_proc, NULL);
+  cleanup_registered = 0;
+  xfree(ticket);
+  ticket = NULL;
+  
   return 0;
 }
 
@@ -103,8 +124,7 @@
     reply.dat[0] = 0;
     reply.length = 0;
   }
-  else
-    reply.length = r;
+  else reply.length = r;
   
   /* Clear session key. */
   memset(&adat.session, 0, sizeof(&adat.session));
@@ -121,8 +141,6 @@
 int auth_kerberos_tgt(struct passwd *pw, const char *string)
 {
   CREDENTIALS creds;
-  extern char *ticket;
-  int r;
   
   if (!radix_to_creds(string, &creds)) {
     log("Protocol error decoding Kerberos V4 tgt");
@@ -133,37 +151,39 @@
     strlcpy(creds.service, "krbtgt", sizeof creds.service);
   
   if (strcmp(creds.service, "krbtgt")) {
-    log("Kerberos V4 tgt (%s%s%s@%s) rejected for uid %d",
-	creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
-	pw->pw_uid);
-    packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for uid %d",
+    log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname,
+	creds.pinst[0] ? "." : "", creds.pinst, creds.realm, pw->pw_name);
+    packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s",
 		      creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
-		      creds.realm, pw->pw_uid);
+		      creds.realm, pw->pw_name);
     goto auth_kerberos_tgt_failure;
   }
-  if (!ssh_tf_init(pw->pw_uid) ||
-      (r = in_tkt(creds.pname, creds.pinst)) ||
-      (r = save_credentials(creds.service, creds.instance, creds.realm,
-			    creds.session, creds.lifetime, creds.kvno,
-			    &creds.ticket_st, creds.issue_date))) {
-    xfree(ticket);
-    ticket = NULL;
+  if (!krb4_init(pw->pw_uid))
+    goto auth_kerberos_tgt_failure;
+
+  if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
+    goto auth_kerberos_tgt_failure;
+  
+  if (save_credentials(creds.service, creds.instance, creds.realm,
+		       creds.session, creds.lifetime, creds.kvno,
+		       &creds.ticket_st, creds.issue_date) != KSUCCESS) {
     packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
     goto auth_kerberos_tgt_failure;
   }
   /* Successful authentication, passed all checks. */
-  chown(ticket, pw->pw_uid, pw->pw_gid);
-  packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
-		    creds.service, creds.instance, creds.realm,
-		    creds.pname, creds.pinst[0] ? "." : "",
-		    creds.pinst, creds.realm);
+  chown(tkt_string(), pw->pw_uid, pw->pw_gid);
   
+  packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
+		    creds.service, creds.instance, creds.realm, creds.pname,
+		    creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
+  memset(&creds, 0, sizeof(creds));
   packet_start(SSH_SMSG_SUCCESS);
   packet_send();
   packet_write_wait();
   return 1;
-
-auth_kerberos_tgt_failure:
+  
+ auth_kerberos_tgt_failure:
+  krb4_cleanup_proc(NULL);
   memset(&creds, 0, sizeof(creds));
   packet_start(SSH_SMSG_FAILURE);
   packet_send();
@@ -191,10 +211,11 @@
     uid = atoi(creds.pname + 7);
   
   if (kafs_settoken(creds.realm, uid, &creds)) {
-    log("AFS token (%s@%s) rejected for uid %d", creds.pname,
-	creds.realm, uid);
-    packet_send_debug("AFS token (%s@%s) rejected for uid %d", creds.pname,
-		      creds.realm, uid);
+    log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
+	pw->pw_name);
+    packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname,
+		      creds.realm, pw->pw_name);
+    memset(&creds, 0, sizeof(creds));
     packet_start(SSH_SMSG_FAILURE);
     packet_send();
     packet_write_wait();
@@ -202,6 +223,7 @@
   }
   packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
 		    creds.realm, creds.pname, creds.realm);
+  memset(&creds, 0, sizeof(creds));
   packet_start(SSH_SMSG_SUCCESS);
   packet_send();
   packet_write_wait();
diff --git a/auth-passwd.c b/auth-passwd.c
index 61f66fe..99d0af2 100644
--- a/auth-passwd.c
+++ b/auth-passwd.c
@@ -15,17 +15,13 @@
 */
 
 #include "includes.h"
-RCSID("$Id: auth-passwd.c,v 1.2 1999/10/27 13:42:05 damien Exp $");
+RCSID("$Id: auth-passwd.c,v 1.3 1999/11/11 06:57:39 damien Exp $");
 
 #include "packet.h"
 #include "ssh.h"
 #include "servconf.h"
 #include "xmalloc.h"
 
-#ifdef KRB4
-extern char *ticket;
-#endif /* KRB4 */
-
 /* Tries to authenticate the user using password.  Returns true if
    authentication succeeds. */
 
@@ -80,9 +76,9 @@
       KTEXT_ST tkt;
       struct hostent *hp;
       unsigned long faddr;
-      char localhost[MAXHOSTNAMELEN];	/* local host name */
-      char phost[INST_SZ];		/* host instance */
-      char realm[REALM_SZ];		/* local Kerberos realm */
+      char localhost[MAXHOSTNAMELEN];
+      char phost[INST_SZ];
+      char realm[REALM_SZ];
       int r;
       
       /* Try Kerberos password authentication only for non-root
@@ -90,9 +86,8 @@
       if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
 
 	/* Set up our ticket file. */
-	if (!ssh_tf_init(pw->pw_uid)) {
-	  log("Couldn't initialize Kerberos ticket file for %s!",
-	      pw->pw_name);
+	if (!krb4_init(pw->pw_uid)) {
+	  log("Couldn't initialize Kerberos ticket file for %s!", pw->pw_name);
 	  goto kerberos_auth_failure;
 	}
 	/* Try to get TGT using our password. */
@@ -104,13 +99,12 @@
 	  goto kerberos_auth_failure;
 	}
 	/* Successful authentication. */
-	chown(ticket, pw->pw_uid, pw->pw_gid);
-	
-	(void) gethostname(localhost, sizeof(localhost));
-	(void) strlcpy(phost, (char *)krb_get_phost(localhost), INST_SZ);
+	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. */
+	(void) gethostname(localhost, sizeof(localhost));
+	(void) strlcpy(phost, (char *)krb_get_phost(localhost), INST_SZ);
 	r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
 
 	if (r == KSUCCESS) {
@@ -150,10 +144,10 @@
 	return 1;
 	
       kerberos_auth_failure:
-	(void) dest_tkt();
-	xfree(ticket);
-	ticket = NULL;
-	if (!options.kerberos_or_local_passwd ) return 0;
+	krb4_cleanup_proc(NULL);
+	
+	if (!options.kerberos_or_local_passwd)
+	  return 0;
       }
       else {
 	/* Logging in as root or no local Kerberos realm. */
diff --git a/clientloop.c b/clientloop.c
index 43373b7..a236ce9 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -15,16 +15,17 @@
 */
 
 #include "includes.h"
-RCSID("$Id: clientloop.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
+RCSID("$Id: clientloop.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
 
 #include "xmalloc.h"
 #include "ssh.h"
 #include "packet.h"
 #include "buffer.h"
 #include "authfd.h"
+#include "readconf.h"
 
 /* Flag indicating whether quiet mode is on. */
-extern int quiet_flag;
+extern Options options;
 
 /* Flag indicating that stdin should be redirected from /dev/null. */
 extern int stdin_null_flag;
@@ -866,7 +867,7 @@
 
   /* In interactive mode (with pseudo tty) display a message indicating that
      the connection has been closed. */
-  if (have_pty && !quiet_flag)
+  if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET)
     {
       snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
       buffer_append(&stderr_buffer, buf, strlen(buf));
diff --git a/log-client.c b/log-client.c
index 1792ba8..63cc794 100644
--- a/log-client.c
+++ b/log-client.c
@@ -10,129 +10,54 @@
 Created: Mon Mar 20 21:13:40 1995 ylo
 
 Client-side versions of debug(), log(), etc.  These print to stderr.
+This is a stripped down version of log-server.c.
 
 */
 
 #include "includes.h"
-RCSID("$Id: log-client.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
+RCSID("$Id: log-client.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
 
 #include "xmalloc.h"
 #include "ssh.h"
 
-static int log_debug = 0;
-static int log_quiet = 0;
+static LogLevel log_level = SYSLOG_LEVEL_INFO;
 
-void log_init(char *av0, int on_stderr, int debug, int quiet,
-	      SyslogFacility facility)
+/* Initialize the log.
+     av0	program name (should be argv[0])
+     level	logging level
+     */
+
+void
+log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2)
 {
-  log_debug = debug;
-  log_quiet = quiet;
-}
-
-void log(const char *fmt, ...)
-{
-  va_list args;
-
-  if (log_quiet)
-    return;
-  va_start(args, fmt);
-  vfprintf(stderr, fmt, args);
-  fprintf(stderr, "\r\n");
-  va_end(args);
-}
-
-void debug(const char *fmt, ...)
-{
-  va_list args;
-  if (log_quiet || !log_debug)
-    return;
-  va_start(args, fmt);
-  fprintf(stderr, "debug: ");
-  vfprintf(stderr, fmt, args);
-  fprintf(stderr, "\r\n");
-  va_end(args);
-}
-
-void error(const char *fmt, ...)
-{
-  va_list args;
-  if (log_quiet)
-    return;
-  va_start(args, fmt);
-  vfprintf(stderr, fmt, args);
-  fprintf(stderr, "\r\n");
-  va_end(args);
-}
-
-struct fatal_cleanup
-{
-  struct fatal_cleanup *next;
-  void (*proc)(void *);
-  void *context;
-};
-
-static struct fatal_cleanup *fatal_cleanups = NULL;
-
-/* Registers a cleanup function to be called by fatal() before exiting. */
-
-void fatal_add_cleanup(void (*proc)(void *), void *context)
-{
-  struct fatal_cleanup *cu;
-
-  cu = xmalloc(sizeof(*cu));
-  cu->proc = proc;
-  cu->context = context;
-  cu->next = fatal_cleanups;
-  fatal_cleanups = cu;
-}
-
-/* Removes a cleanup frunction to be called at fatal(). */
-
-void fatal_remove_cleanup(void (*proc)(void *context), void *context)
-{
-  struct fatal_cleanup **cup, *cu;
-  
-  for (cup = &fatal_cleanups; *cup; cup = &cu->next)
+  switch (level)
     {
-      cu = *cup;
-      if (cu->proc == proc && cu->context == context)
-	{
-	  *cup = cu->next;
-	  xfree(cu);
-	  return;
-	}
+    case SYSLOG_LEVEL_QUIET:
+    case SYSLOG_LEVEL_ERROR:
+    case SYSLOG_LEVEL_FATAL:
+    case SYSLOG_LEVEL_INFO:
+    case SYSLOG_LEVEL_CHAT:
+    case SYSLOG_LEVEL_DEBUG:
+      log_level = level;
+      break;
+    default:
+      /* unchanged */
+      break;
     }
-  fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
-	(unsigned long)proc, (unsigned long)context);
 }
 
-/* Function to display an error message and exit.  This is in this file because
-   this needs to restore terminal modes before exiting.  See log-client.c
-   for other related functions. */
+#define MSGBUFSIZE 1024
 
-void fatal(const char *fmt, ...)
+void
+do_log(LogLevel level, const char *fmt, va_list args)
 {
-  va_list args;
-  struct fatal_cleanup *cu, *next_cu;
-  static int fatal_called = 0;
-  
-  if (!fatal_called)
-    {
-      fatal_called = 1;
+  char msgbuf[MSGBUFSIZE];
 
-      /* Call cleanup functions. */
-      for (cu = fatal_cleanups; cu; cu = next_cu)
-	{
-	  next_cu = cu->next;
-	  (*cu->proc)(cu->context);
-	}
-    }
-
-  va_start(args, fmt);
-  vfprintf(stderr, fmt, args);
+  if (level > log_level)
+    return;
+  if (level == SYSLOG_LEVEL_DEBUG)
+    fprintf(stderr, "debug: ");
+  vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+  fprintf(stderr, "%s", msgbuf);
   fprintf(stderr, "\r\n");
-  va_end(args);
-  exit(255);
 }
-
-/* fatal() is in ssh.c so that it can properly reset terminal modes. */
diff --git a/log-server.c b/log-server.c
index fce96b0..6642dbe 100644
--- a/log-server.c
+++ b/log-server.c
@@ -15,29 +15,42 @@
 */
 
 #include "includes.h"
-RCSID("$Id: log-server.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
+RCSID("$Id: log-server.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
 
 #include <syslog.h>
 #include "packet.h"
 #include "xmalloc.h"
 #include "ssh.h"
 
-static int log_debug = 0;
-static int log_quiet = 0;
+static LogLevel log_level = SYSLOG_LEVEL_INFO;
 static int log_on_stderr = 0;
 
 /* Initialize the log.
      av0	program name (should be argv[0])
      on_stderr	print also on stderr
-     debug	send debugging messages to system log
-     quiet	don\'t log anything
+     level	logging level
      */
 
-void log_init(char *av0, int on_stderr, int debug, int quiet, 
-	      SyslogFacility facility)
+void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
 {
   int log_facility;
   
+  switch (level)
+    {
+    case SYSLOG_LEVEL_QUIET:
+    case SYSLOG_LEVEL_ERROR:
+    case SYSLOG_LEVEL_FATAL:
+    case SYSLOG_LEVEL_INFO:
+    case SYSLOG_LEVEL_CHAT:
+    case SYSLOG_LEVEL_DEBUG:
+      log_level = level;
+      break;
+    default:
+      fprintf(stderr, "Unrecognized internal syslog level code %d\n",
+	      (int)level);
+      exit(1);
+    }
+
   switch (facility)
     {
     case SYSLOG_FACILITY_DAEMON:
@@ -79,8 +92,6 @@
       exit(1);
     }
 
-  log_debug = debug;
-  log_quiet = quiet;
   log_on_stderr = on_stderr;
   closelog(); /* Close any previous log. */
   openlog(av0, LOG_PID, log_facility);
@@ -88,146 +99,49 @@
 
 #define MSGBUFSIZE 1024
 
-#define DECL_MSGBUF char msgbuf[MSGBUFSIZE]
-
-/* Log this message (information that usually should go to the log). */
-
-void log(const char *fmt, ...)
+void
+do_log(LogLevel level, const char *fmt, va_list args)
 {
-  va_list args;
-  DECL_MSGBUF;
-  if (log_quiet)
+  char msgbuf[MSGBUFSIZE];
+  char fmtbuf[MSGBUFSIZE];
+  char *txt = NULL;
+  int pri = LOG_INFO;
+
+  if (level > log_level)
     return;
-  va_start(args, fmt);
-  vsnprintf(msgbuf, MSGBUFSIZE, fmt, args);
-  va_end(args);
-  if (log_on_stderr)
-    fprintf(stderr, "log: %s\n", msgbuf);
-  syslog(LOG_INFO, "log: %.500s", msgbuf);
-}
-
-/* Debugging messages that should not be logged during normal operation. */
-
-void debug(const char *fmt, ...)
-{
-  va_list args;
-  DECL_MSGBUF;
-  if (!log_debug || log_quiet)
-    return;
-  va_start(args, fmt);
-  vsnprintf(msgbuf, MSGBUFSIZE, fmt, args);
-  va_end(args);
-  if (log_on_stderr)
-    fprintf(stderr, "debug: %s\n", msgbuf);
-  syslog(LOG_DEBUG, "debug: %.500s", msgbuf);
-}
-
-/* Error messages that should be logged. */
-
-void error(const char *fmt, ...)
-{
-  va_list args;
-  DECL_MSGBUF;
-  if (log_quiet)
-    return;
-  va_start(args, fmt);
-  vsnprintf(msgbuf, MSGBUFSIZE, fmt, args);
-  va_end(args);
-  if (log_on_stderr)
-    fprintf(stderr, "error: %s\n", msgbuf);
-  syslog(LOG_ERR, "error: %.500s", msgbuf);
-}
-
-struct fatal_cleanup
-{
-  struct fatal_cleanup *next;
-  void (*proc)(void *);
-  void *context;
-};
-
-static struct fatal_cleanup *fatal_cleanups = NULL;
-
-/* Registers a cleanup function to be called by fatal() before exiting. */
-
-void fatal_add_cleanup(void (*proc)(void *), void *context)
-{
-  struct fatal_cleanup *cu;
-
-  cu = xmalloc(sizeof(*cu));
-  cu->proc = proc;
-  cu->context = context;
-  cu->next = fatal_cleanups;
-  fatal_cleanups = cu;
-}
-
-/* Removes a cleanup frunction to be called at fatal(). */
-
-void fatal_remove_cleanup(void (*proc)(void *context), void *context)
-{
-  struct fatal_cleanup **cup, *cu;
-  
-  for (cup = &fatal_cleanups; *cup; cup = &cu->next)
+  switch (level)
     {
-      cu = *cup;
-      if (cu->proc == proc && cu->context == context)
-	{
-	  *cup = cu->next;
-	  xfree(cu);
-	  return;
-	}
+    case SYSLOG_LEVEL_ERROR:
+      txt = "error";
+      pri = LOG_ERR;
+      break;
+    case SYSLOG_LEVEL_FATAL:
+      txt = "fatal";
+      pri = LOG_ERR;
+      break;
+    case SYSLOG_LEVEL_INFO:
+      pri = LOG_INFO;
+      break;
+    case SYSLOG_LEVEL_CHAT:
+      pri = LOG_INFO;
+      break;
+    case SYSLOG_LEVEL_DEBUG:
+      txt = "debug";
+      pri = LOG_DEBUG;
+      break;
+    default:
+      txt = "internal error";
+      pri = LOG_ERR;
+      break;
     }
-  fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
-	(unsigned long)proc, (unsigned long)context);
-}
 
-/* Fatal messages.  This function never returns. */
-
-void fatal(const char *fmt, ...)
-{
-  va_list args;
-  struct fatal_cleanup *cu, *next_cu;
-  static int fatal_called = 0;
-#if defined(KRB4)
-  extern char *ticket;
-#endif /* KRB4 */
-  DECL_MSGBUF;
-
-  if (log_quiet)
-    exit(1);
-  va_start(args, fmt);
-  vsnprintf(msgbuf, MSGBUFSIZE, fmt, args);
-  va_end(args);
+  if (txt != NULL) {
+    snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
+    vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
+  }else{
+    vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+  }
   if (log_on_stderr)
-    fprintf(stderr, "fatal: %s\n", msgbuf);
-  syslog(LOG_ERR, "fatal: %.500s", msgbuf);
-
-  if (fatal_called)
-    exit(1);
-  fatal_called = 1;
-
-  /* Call cleanup functions. */
-  for (cu = fatal_cleanups; cu; cu = next_cu)
-    {
-      next_cu = cu->next;
-      debug("Calling cleanup 0x%lx(0x%lx)",
-	    (unsigned long)cu->proc, (unsigned long)cu->context);
-      (*cu->proc)(cu->context);
-    }
-#if defined(KRB4)
-  /* If you forwarded a ticket you get one shot for proper
-     authentication. */
-  /* If tgt was passed unlink file */
-  if (ticket)
-    {
-      if (strcmp(ticket,"none"))
-	unlink(ticket);
-      else
-	ticket = NULL;
-    }
-#endif /* KRB4 */
-
-  /* If local XAUTHORITY was created, remove it. */
-  if (xauthfile) unlink(xauthfile);
-
-  exit(1);
+    fprintf(stderr, "%s\n", msgbuf);
+  syslog(pri, "%.500s", msgbuf);
 }
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..3e840ec
--- /dev/null
+++ b/log.c
@@ -0,0 +1,135 @@
+/*
+
+Shared versions of debug(), log(), etc.
+
+*/
+
+#include "includes.h"
+RCSID("$OpenBSD: log.c,v 1.1 1999/11/10 23:36:44 markus Exp $");
+
+#include "ssh.h"
+#include "xmalloc.h"
+
+/* Fatal messages.  This function never returns. */
+
+void
+fatal(const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  do_log(SYSLOG_LEVEL_FATAL, fmt, args);
+  va_end(args);
+  fatal_cleanup();
+}
+
+/* Error messages that should be logged. */
+
+void
+error(const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  do_log(SYSLOG_LEVEL_ERROR, fmt, args);
+  va_end(args);
+}
+
+/* Log this message (information that usually should go to the log). */
+
+void
+log(const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  do_log(SYSLOG_LEVEL_INFO, fmt, args);
+  va_end(args);
+}
+
+/* More detailed messages (information that does not need to go to the log). */
+
+void
+chat(const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  do_log(SYSLOG_LEVEL_CHAT, fmt, args);
+  va_end(args);
+}
+
+/* Debugging messages that should not be logged during normal operation. */
+
+void
+debug(const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  do_log(SYSLOG_LEVEL_DEBUG, fmt, args);
+  va_end(args);
+}
+
+/* Fatal cleanup */
+
+struct fatal_cleanup
+{
+  struct fatal_cleanup *next;
+  void (*proc)(void *);
+  void *context;
+};
+
+static struct fatal_cleanup *fatal_cleanups = NULL;
+
+/* Registers a cleanup function to be called by fatal() before exiting. */
+
+void
+fatal_add_cleanup(void (*proc)(void *), void *context)
+{
+  struct fatal_cleanup *cu;
+
+  cu = xmalloc(sizeof(*cu));
+  cu->proc = proc;
+  cu->context = context;
+  cu->next = fatal_cleanups;
+  fatal_cleanups = cu;
+}
+
+/* Removes a cleanup frunction to be called at fatal(). */
+
+void
+fatal_remove_cleanup(void (*proc)(void *context), void *context)
+{
+  struct fatal_cleanup **cup, *cu;
+  
+  for (cup = &fatal_cleanups; *cup; cup = &cu->next)
+    {
+      cu = *cup;
+      if (cu->proc == proc && cu->context == context)
+	{
+	  *cup = cu->next;
+	  xfree(cu);
+	  return;
+	}
+    }
+  fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
+	(unsigned long)proc, (unsigned long)context);
+}
+
+/* Cleanup and exit */
+void
+fatal_cleanup(void)
+{
+  struct fatal_cleanup *cu, *next_cu;
+  static int called = 0;
+  if (called)
+    exit(255);
+  called = 1;
+
+  /* Call cleanup functions. */
+  for (cu = fatal_cleanups; cu; cu = next_cu)
+    {
+      next_cu = cu->next;
+      debug("Calling cleanup 0x%lx(0x%lx)",
+	    (unsigned long)cu->proc, (unsigned long)cu->context);
+      (*cu->proc)(cu->context);
+    }
+
+  exit(255);
+}
diff --git a/readconf.c b/readconf.c
index 281548d..2a99266 100644
--- a/readconf.c
+++ b/readconf.c
@@ -14,7 +14,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: readconf.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
+RCSID("$Id: readconf.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
 
 #include "ssh.h"
 #include "cipher.h"
@@ -101,7 +101,7 @@
   oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
   oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
   oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
-  oUsePrivilegedPort
+  oUsePrivilegedPort, oLogLevel
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -150,6 +150,24 @@
   { "keepalive", oKeepAlives },
   { "numberofpasswordprompts", oNumberOfPasswordPrompts },
   { "tisauthentication", oTISAuthentication },
+  { "loglevel", oLogLevel },
+  { NULL, 0 }
+};
+
+/* textual representation of log-levels */
+
+static struct 
+{
+  const char *name;
+  LogLevel level;
+} log_levels[] =
+{
+  { "QUIET", SYSLOG_LEVEL_QUIET },
+  { "FATAL", SYSLOG_LEVEL_FATAL },
+  { "ERROR", SYSLOG_LEVEL_ERROR },
+  { "INFO",  SYSLOG_LEVEL_INFO },
+  { "CHAT",  SYSLOG_LEVEL_CHAT },
+  { "DEBUG", SYSLOG_LEVEL_DEBUG },
   { NULL, 0 }
 };
 
@@ -218,7 +236,7 @@
 			 int *activep)
 {
   char buf[256], *cp, *string, **charptr;
-  int opcode, *intptr, value, fwd_port, fwd_host_port;
+  int opcode, *intptr, value, fwd_port, fwd_host_port, i;
 
   /* Skip leading whitespace. */
   cp = line + strspn(line, WHITESPACE);
@@ -445,6 +463,27 @@
       if (*activep && *intptr == -1)
 	*intptr = value;
       break;
+
+    case oLogLevel:
+      cp = strtok(NULL, WHITESPACE);
+      if (!cp)
+        {
+          fprintf(stderr, "%s line %d: missing level name.\n",
+	          filename, linenum);
+          exit(1);
+        }
+      for (i = 0; log_levels[i].name; i++)
+        if (strcasecmp(log_levels[i].name, cp) == 0)
+          break;
+      if (!log_levels[i].name)
+        {
+          fprintf(stderr, "%s line %d: unsupported log level %s\n",
+	          filename, linenum, cp);
+          exit(1);
+        }
+      if (options->log_level == (LogLevel)(-1))
+        options->log_level = log_levels[i].level;
+      break;
       
     case oRemoteForward:
       cp = strtok(NULL, WHITESPACE);
@@ -607,6 +646,7 @@
   options->user_hostfile = NULL;
   options->num_local_forwards = 0;
   options->num_remote_forwards = 0;
+  options->log_level = (LogLevel)-1;
 }
 
 /* Called after processing other sources of option data, this fills those
@@ -677,6 +717,8 @@
     options->system_hostfile = SSH_SYSTEM_HOSTFILE;
   if (options->user_hostfile == NULL)
     options->user_hostfile = SSH_USER_HOSTFILE;
+  if (options->log_level == (LogLevel)-1)
+    options->log_level = SYSLOG_LEVEL_INFO;
   /* options->proxy_command should not be set by default */
   /* options->user will be set in the main program if appropriate */
   /* options->hostname will be set in the main program if appropriate */
diff --git a/readconf.h b/readconf.h
index 71655bd..8839a1b 100644
--- a/readconf.h
+++ b/readconf.h
@@ -13,7 +13,7 @@
 
 */
 
-/* RCSID("$Id: readconf.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
+/* RCSID("$Id: readconf.h,v 1.2 1999/11/11 06:57:39 damien Exp $"); */
 
 #ifndef READCONF_H
 #define READCONF_H
@@ -54,6 +54,7 @@
   int compression;		/* Compress packets in both directions. */
   int compression_level;	/* Compression level 1 (fast) to 9 (best). */
   int keepalives;		/* Set SO_KEEPALIVE. */
+  LogLevel log_level;		/* Level for logging. */
 
   int port;			/* Port to connect. */
   int connection_attempts;	/* Max attempts (seconds) before giving up */
diff --git a/servconf.c b/servconf.c
index 5fa4879..d7f54a6 100644
--- a/servconf.c
+++ b/servconf.c
@@ -12,7 +12,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: servconf.c,v 1.1 1999/10/27 03:42:45 damien Exp $");
+RCSID("$Id: servconf.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
 
 #include "ssh.h"
 #include "servconf.h"
@@ -31,8 +31,6 @@
   options->key_regeneration_time = -1;
   options->permit_root_login = -1;
   options->ignore_rhosts = -1;
-  options->quiet_mode = -1;
-  options->fascist_logging = -1;
   options->print_motd = -1;
   options->check_mail = -1;
   options->x11_forwarding = -1;
@@ -40,6 +38,7 @@
   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->rsa_authentication = -1;
@@ -89,12 +88,8 @@
     options->permit_root_login = 1;		 /* yes */
   if (options->ignore_rhosts == -1)
     options->ignore_rhosts = 0;
-  if (options->quiet_mode == -1)
-    options->quiet_mode = 0;
   if (options->check_mail == -1)
     options->check_mail = 0;
-  if (options->fascist_logging == -1)
-    options->fascist_logging = 1;
   if (options->print_motd == -1)
     options->print_motd = 1;
   if (options->x11_forwarding == -1)
@@ -107,6 +102,8 @@
     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)
@@ -145,7 +142,7 @@
 typedef enum 
 {
   sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
-  sPermitRootLogin, sQuietMode, sFascistLogging, sLogFacility,
+  sPermitRootLogin, sLogFacility, sLogLevel,
   sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
 #ifdef KRB4
   sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
@@ -176,9 +173,8 @@
   { "logingracetime", sLoginGraceTime },
   { "keyregenerationinterval", sKeyRegenerationTime },
   { "permitrootlogin", sPermitRootLogin },
-  { "quietmode", sQuietMode },
-  { "fascistlogging", sFascistLogging },
   { "syslogfacility", sLogFacility },
+  { "loglevel", sLogLevel },
   { "rhostsauthentication", sRhostsAuthentication },
   { "rhostsrsaauthentication", sRhostsRSAAuthentication },
   { "rsaauthentication", sRSAAuthentication },
@@ -233,6 +229,21 @@
   { NULL, 0 }
 };
 
+static struct 
+{
+  const char *name;
+  LogLevel level;
+} log_levels[] =
+{
+  { "QUIET", SYSLOG_LEVEL_QUIET },
+  { "FATAL", SYSLOG_LEVEL_FATAL },
+  { "ERROR", SYSLOG_LEVEL_ERROR },
+  { "INFO",  SYSLOG_LEVEL_INFO },
+  { "CHAT",  SYSLOG_LEVEL_CHAT },
+  { "DEBUG", SYSLOG_LEVEL_DEBUG },
+  { NULL, 0 }
+};
+
 /* Returns the number of the token pointed to by cp of length len.
    Never returns if the token is not known. */
 
@@ -392,14 +403,6 @@
 	    *intptr = value;
 	  break;
 	  
-	case sQuietMode:
-	  intptr = &options->quiet_mode;
-	  goto parse_flag;
-
-	case sFascistLogging:
-	  intptr = &options->fascist_logging;
-	  goto parse_flag;
-
 	case sRhostsAuthentication:
 	  intptr = &options->rhosts_authentication;
 	  goto parse_flag;
@@ -487,7 +490,7 @@
 	      exit(1);
 	    }
 	  for (i = 0; log_facilities[i].name; i++)
-	    if (strcmp(log_facilities[i].name, cp) == 0)
+	    if (strcasecmp(log_facilities[i].name, cp) == 0)
 	      break;
 	  if (!log_facilities[i].name)
 	    {
@@ -498,6 +501,27 @@
 	  if (options->log_facility == (SyslogFacility)(-1))
 	    options->log_facility = log_facilities[i].facility;
 	  break;
+
+	case sLogLevel:
+	  cp = strtok(NULL, WHITESPACE);
+	  if (!cp)
+	    {
+	      fprintf(stderr, "%s line %d: missing level name.\n",
+		      filename, linenum);
+	      exit(1);
+	    }
+	  for (i = 0; log_levels[i].name; i++)
+	    if (strcasecmp(log_levels[i].name, cp) == 0)
+	      break;
+	  if (!log_levels[i].name)
+	    {
+	      fprintf(stderr, "%s line %d: unsupported log level %s\n",
+		      filename, linenum, cp);
+	      exit(1);
+	    }
+	  if (options->log_level == (LogLevel)(-1))
+	    options->log_level = log_levels[i].level;
+	  break;
 	  
 	case sAllowUsers:
 	  while ((cp = strtok(NULL, WHITESPACE)))
diff --git a/servconf.h b/servconf.h
index 22c73fd..584935b 100644
--- a/servconf.h
+++ b/servconf.h
@@ -13,7 +13,7 @@
 
 */
 
-/* RCSID("$Id: servconf.h,v 1.1 1999/10/27 03:42:45 damien Exp $"); */
+/* RCSID("$Id: servconf.h,v 1.2 1999/11/11 06:57:40 damien Exp $"); */
 
 #ifndef SERVCONF_H
 #define SERVCONF_H
@@ -33,8 +33,6 @@
   int key_regeneration_time;	/* Server key lifetime (seconds). */
   int permit_root_login;	/* If true, permit root login. */
   int ignore_rhosts;		/* Ignore .rhosts and .shosts. */
-  int quiet_mode;		/* If true, don't log anything but fatals. */
-  int fascist_logging;		/* Perform very verbose logging. */
   int print_motd;		/* If true, print /etc/motd. */
   int check_mail;               /* If true, check for new mail. */
   int x11_forwarding;		/* If true, permit inet (spoofing) X11 fwd. */
@@ -42,6 +40,7 @@
   int strict_modes;		/* If true, require string home dir modes. */
   int keepalives;		/* If true, set SO_KEEPALIVE. */
   SyslogFacility log_facility;	/* Facility for system logging. */
+  LogLevel log_level;		/* Level for system logging. */
   int rhosts_authentication;	/* If true, permit rhosts authentication. */
   int rhosts_rsa_authentication;/* If true, permit rhosts RSA authentication.*/
   int rsa_authentication;	/* If true, permit RSA authentication. */
diff --git a/ssh.1 b/ssh.1
index 3ea1c27..34a8ce9 100644
--- a/ssh.1
+++ b/ssh.1
@@ -9,7 +9,7 @@
 .\"
 .\" Created: Sat Apr 22 21:55:14 1995 ylo
 .\"
-.\" $Id: ssh.1,v 1.5 1999/11/11 00:43:13 damien Exp $
+.\" $Id: ssh.1,v 1.6 1999/11/11 06:57:40 damien Exp $
 .\"
 .Dd September 25, 1999
 .Dt SSH 1
@@ -602,6 +602,12 @@
 .Dq yes
 or
 .Dq no .
+.It Cm LogLevel
+Gives the verbosity level that is used when logging messages from
+.Nm ssh .
+The possible values are:
+QUIET, FATAL, ERROR, INFO, CHAT and DEBUG.
+The default is INFO.
 .It Cm NumberOfPasswordPrompts
 Specifies the number of password prompts before giving up. The
 argument to this keyword must be an integer. Default is 3.
diff --git a/ssh.c b/ssh.c
index 7630048..be5ad2c 100644
--- a/ssh.c
+++ b/ssh.c
@@ -18,7 +18,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: ssh.c,v 1.4 1999/10/30 01:39:56 damien Exp $");
+RCSID("$Id: ssh.c,v 1.5 1999/11/11 06:57:40 damien Exp $");
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -32,9 +32,6 @@
    command line. */
 int debug_flag = 0;
 
-/* Flag indicating whether quiet mode is on. */
-int quiet_flag = 0;
-
 /* Flag indicating whether to allocate a pseudo tty.  This can be set on the
    command line, and is automatically set if no command is given on the command
    line. */
@@ -306,16 +303,17 @@
 
 	case 'v':
 	case 'V':
-	  debug_flag = 1;
 	  fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
 		  SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
 	  fprintf(stderr, "Compiled with SSL.\n");
 	  if (opt == 'V')
 	    exit(0);
+	  debug_flag = 1;
+	  options.log_level = SYSLOG_LEVEL_DEBUG;
 	  break;
 
 	case 'q':
-	  quiet_flag = 1;
+	  options.log_level = SYSLOG_LEVEL_QUIET;
 	  break;
 
 	case 'e':
@@ -466,7 +464,7 @@
 
   /* Initialize "log" output.  Since we are the client all output actually
      goes to the terminal. */
-  log_init(av[0], 1, debug_flag, quiet_flag, SYSLOG_FACILITY_USER);
+  log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
 
   /* Read per-user configuration file. */
   snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);
@@ -477,6 +475,10 @@
 
   /* Fill configuration defaults. */
   fill_default_options(&options);
+
+  /* reinit */
+  log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
+
   if (options.user == NULL)
     options.user = xstrdup(pw->pw_name);
 
diff --git a/ssh.h b/ssh.h
index a91312a..da818b2 100644
--- a/ssh.h
+++ b/ssh.h
@@ -13,26 +13,14 @@
 
 */
 
-/* RCSID("$Id: ssh.h,v 1.9 1999/11/10 23:40:23 damien Exp $"); */
+/* RCSID("$Id: ssh.h,v 1.10 1999/11/11 06:57:40 damien Exp $"); */
 
 #ifndef SSH_H
 #define SSH_H
 
 #include <netinet/in.h> /* For struct sockaddr_in */
 #include <pwd.h> /* For struct pw */
-
-#ifndef SHUT_RDWR
-enum
-{
-  SHUT_RD = 0,    /* No more receptions.  */
-#define SHUT_RD   SHUT_RD
-  SHUT_WR,    /* No more transmissions.  */
-#define SHUT_WR   SHUT_WR
-  SHUT_RDWR   /* No more receptions or transmissions.  */
-#define SHUT_RDWR SHUT_RDWR
-};
-#endif
-
+#include <stdarg.h> /* For va_list */
 
 #include "rsa.h"
 #include "cipher.h"
@@ -234,9 +222,58 @@
 #define SSH_CMSG_HAVE_AFS_TOKEN			65	/* token (s) */
 
 
-/* Includes that need definitions above. */
+/*------------ Definitions for logging. -----------------------*/
 
-#include "readconf.h"
+/* Supported syslog facilities and levels. */
+typedef enum
+{
+  SYSLOG_FACILITY_DAEMON,
+  SYSLOG_FACILITY_USER,
+  SYSLOG_FACILITY_AUTH,
+  SYSLOG_FACILITY_LOCAL0,
+  SYSLOG_FACILITY_LOCAL1,
+  SYSLOG_FACILITY_LOCAL2,
+  SYSLOG_FACILITY_LOCAL3,
+  SYSLOG_FACILITY_LOCAL4,
+  SYSLOG_FACILITY_LOCAL5,
+  SYSLOG_FACILITY_LOCAL6,
+  SYSLOG_FACILITY_LOCAL7
+} SyslogFacility;
+
+typedef enum
+{
+  SYSLOG_LEVEL_QUIET,
+  SYSLOG_LEVEL_FATAL,
+  SYSLOG_LEVEL_ERROR,
+  SYSLOG_LEVEL_INFO,
+  SYSLOG_LEVEL_CHAT,
+  SYSLOG_LEVEL_DEBUG
+} LogLevel;
+
+/* Initializes logging. */
+void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
+
+/* Logging implementation, depending on server or client */
+void do_log(LogLevel level, const char *fmt, va_list args);
+
+/* Output a message to syslog or stderr */
+void fatal(const char *fmt, ...);
+void error(const char *fmt, ...);
+void log(const char *fmt, ...);
+void chat(const char *fmt, ...);
+void debug(const char *fmt, ...);
+
+/* same as fatal() but w/o logging */
+void fatal_cleanup(void);
+
+/* Registers a cleanup function to be called by fatal()/fatal_cleanup() before exiting. 
+   It is permissible to call fatal_remove_cleanup for the function itself
+   from the function. */
+void fatal_add_cleanup(void (*proc)(void *context), void *context);
+
+/* Removes a cleanup function to be called at fatal(). */
+void fatal_remove_cleanup(void (*proc)(void *context), void *context);
+
 
 /*------------ definitions for login.c -------------*/
 
@@ -276,6 +313,10 @@
    If login fails, this function prints an error and never returns. 
    This initializes the random state, and leaves it initialized (it will also
    have references from the packet module). */
+
+/* for Options */
+#include "readconf.h"
+
 void ssh_login(int host_key_valid, RSA *host_key, const char *host,
 	       struct sockaddr_in *hostaddr, Options *options,
 	       uid_t original_real_uid);
@@ -381,59 +422,6 @@
 int load_private_key(const char *filename, const char *passphrase,
 		     RSA *private_key, char **comment_return);
 
-/*------------ Definitions for logging. -----------------------*/
-
-/* Supported syslog facilities. */
-typedef enum
-{
-  SYSLOG_FACILITY_DAEMON,
-  SYSLOG_FACILITY_USER,
-  SYSLOG_FACILITY_AUTH,
-  SYSLOG_FACILITY_LOCAL0,
-  SYSLOG_FACILITY_LOCAL1,
-  SYSLOG_FACILITY_LOCAL2,
-  SYSLOG_FACILITY_LOCAL3,
-  SYSLOG_FACILITY_LOCAL4,
-  SYSLOG_FACILITY_LOCAL5,
-  SYSLOG_FACILITY_LOCAL6,
-  SYSLOG_FACILITY_LOCAL7
-} SyslogFacility;
-
-/* Initializes logging.  If debug is non-zero, debug() will output something.
-   If quiet is non-zero, none of these will log send anything to syslog
-   (but maybe to stderr). */
-void log_init(char *av0, int on_stderr, int debug, int quiet,
-	      SyslogFacility facility);
-
-/* Outputs a message to syslog or stderr, depending on the implementation. 
-   The format must guarantee that the final message does not exceed 1024 
-   characters.  The message should not contain newline. */
-void log(const char *fmt, ...);
-
-/* Outputs a message to syslog or stderr, depending on the implementation. 
-   The format must guarantee that the final message does not exceed 1024 
-   characters.  The message should not contain newline. */
-void debug(const char *fmt, ...);
-
-/* Outputs a message to syslog or stderr, depending on the implementation. 
-   The format must guarantee that the final message does not exceed 1024 
-   characters.  The message should not contain newline. */
-void error(const char *fmt, ...);
-
-/* Outputs a message to syslog or stderr, depending on the implementation. 
-   The format must guarantee that the final message does not exceed 1024 
-   characters.  The message should not contain newline.  
-   This call never returns. */
-void fatal(const char *fmt, ...);
-
-/* Registers a cleanup function to be called by fatal() before exiting. 
-   It is permissible to call fatal_remove_cleanup for the function itself
-   from the function. */
-void fatal_add_cleanup(void (*proc)(void *context), void *context);
-
-/* Removes a cleanup frunction to be called at fatal(). */
-void fatal_remove_cleanup(void (*proc)(void *context), void *context);
-
 /*---------------- definitions for channels ------------------*/
 
 /* Sets specific protocol options. */
@@ -547,9 +535,6 @@
    This should be called in the client only.  */
 void x11_request_forwarding_with_spoofing(const char *proto, const char *data);
 
-/* Local Xauthority file (server only). */
-extern char *xauthfile;
-
 /* Sends a message to the server to request authentication fd forwarding. */
 void auth_request_forwarding(void);
 
@@ -596,7 +581,8 @@
    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_krb4(const char *server_user, KTEXT auth, char **client);
-int ssh_tf_init(uid_t uid);
+int krb4_init(uid_t uid);
+void krb4_cleanup_proc(void *ignore);
 
 #ifdef AFS
 #include <kafs.h>
diff --git a/sshd.8 b/sshd.8
index fd1f7f0..20e9712 100644
--- a/sshd.8
+++ b/sshd.8
@@ -9,7 +9,7 @@
 .\"
 .\" Created: Sat Apr 22 21:55:14 1995 ylo
 .\"
-.\" $Id: sshd.8,v 1.5 1999/11/11 00:43:13 damien Exp $
+.\" $Id: sshd.8,v 1.6 1999/11/11 06:57:40 damien Exp $
 .\"
 .Dd September 25, 1999
 .Dt SSHD 8
@@ -231,15 +231,6 @@
 wildcards in the patterns.  Only user names are valid, a numerical user
 id isn't recognized.  By default login is allowed regardless of
 the user name.
-.Pp
-.It Cm FascistLogging
-Specifies whether to use verbose logging.  Verbose logging violates
-the privacy of users and is not recommended.  The argument must be
-.Dq yes
-or
-.Dq no .
-The default is
-.Dq no .
 .It Cm HostKey
 Specifies the file containing the private host key (default
 .Pa /etc/ssh/ssh_host_key ) .
@@ -312,6 +303,14 @@
 The server disconnects after this time if the user has not
 successfully logged in.  If the value is 0, there is no time limit.
 The default is 600 (seconds).
+.It Cm LogLevel
+Gives the verbosity level that is used when logging messages from
+.Nm sshd .
+The possible values are:
+QUIET, FATAL, ERROR, INFO, CHAT and DEBUG.
+The default is INFO.
+Logging with level DEBUG violates the privacy of users
+and is not recommended.
 .It Cm PasswordAuthentication
 Specifies whether password authentication is allowed.
 The default is
@@ -355,11 +354,6 @@
 .Pa /etc/profile ,
 or equivalent.)  The default is
 .Dq yes .
-.It Cm QuietMode
-Specifies whether the system runs in quiet mode.  In quiet mode,
-nothing is logged in the system log, except fatal errors.  The default
-is
-.Dq no .
 .It Cm RandomSeed
 Obsolete.  Random number generation uses other techniques.
 .It Cm RhostsAuthentication
@@ -622,8 +616,8 @@
 it being world-readable if the user's home directory resides on an NFS
 volume).  It is recommended that it not be accessible by others.  The
 format of this file is described above.
-.It Pa "/etc/ssh/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
-This file is consulted when using rhosts with RSA host
+.It Pa "/etc/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
+These files are consulted when using rhosts with RSA host
 authentication to check the public key of the host.  The key must be
 listed in one of these files to be accepted.
 The client uses the same files
diff --git a/sshd.c b/sshd.c
index a1f9449..75ea61e 100644
--- a/sshd.c
+++ b/sshd.c
@@ -18,7 +18,7 @@
 */
 
 #include "includes.h"
-RCSID("$Id: sshd.c,v 1.12 1999/11/08 05:15:55 damien Exp $");
+RCSID("$Id: sshd.c,v 1.13 1999/11/11 06:57:40 damien Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -43,12 +43,8 @@
 #define O_NOCTTY	0
 #endif
 
-#ifdef KRB4
-char *ticket = NULL;
-#endif /* KRB4 */
-
 /* Local Xauthority file. */
-char *xauthfile = NULL;
+static char *xauthfile = NULL;
 
 /* Server configuration options. */
 ServerOptions options;
@@ -65,6 +61,9 @@
 /* Flag indicating that the daemon is being started from inetd. */
 int inetd_flag = 0;
 
+/* debug goes to stderr unless inetd_flag is set */
+int log_stderr = 0;
+
 /* argv[0] without path. */
 char *av0;
 
@@ -400,6 +399,7 @@
 	  break;
 	case 'd':
 	  debug_flag = 1;
+	  options.log_level = SYSLOG_LEVEL_DEBUG;
 	  break;
 	case 'i':
 	  inetd_flag = 1;
@@ -408,7 +408,7 @@
           silentrsa = 1;
 	  break;
 	case 'q':
-	  options.quiet_mode = 1;
+	  options.log_level = SYSLOG_LEVEL_QUIET;
 	  break;
 	case 'b':
 	  options.server_key_bits = atoi(optarg);
@@ -479,9 +479,11 @@
     }
 
   /* Initialize the log (it is reinitialized below in case we forked). */
-  log_init(av0, debug_flag && !inetd_flag, 
-	   debug_flag || options.fascist_logging, 
-	   options.quiet_mode, options.log_facility);
+
+  if (debug_flag && !inetd_flag)
+    log_stderr = 1;
+
+  log_init(av0, options.log_level, options.log_facility, log_stderr);
 
   debug("sshd version %.100s", SSH_VERSION);
 
@@ -496,7 +498,8 @@
       else
 	{
 	  int err = errno;
-	  log_init(av0, !inetd_flag, 1, 0, options.log_facility);
+ 	  /* force logging */
+          log_init(av0, SYSLOG_LEVEL_DEBUG, options.log_facility, log_stderr);
 	  error("Could not load host key: %.200s: %.100s", 
 		options.host_key_file, strerror(err));
 	}
@@ -526,9 +529,7 @@
     }
 
   /* Reinitialize the log (because of the fork above). */
-  log_init(av0, debug_flag && !inetd_flag, 
-	   debug_flag || options.fascist_logging, 
-	   options.quiet_mode, options.log_facility);
+  log_init(av0, options.log_level, options.log_facility, log_stderr);
 
   /* Check that server and host key lengths differ sufficiently.  This is
      necessary to make double encryption work with rsaref.  Oh, I hate
@@ -696,9 +697,7 @@
 		  close(listen_sock);
 		  sock_in = newsock;
 		  sock_out = newsock;
-		  log_init(av0, debug_flag && !inetd_flag, 
-			   options.fascist_logging || debug_flag, 
-			   options.quiet_mode, options.log_facility);
+                  log_init(av0, options.log_level, options.log_facility, log_stderr);
 		  break;
 		}
 	    }
@@ -1605,6 +1604,19 @@
   abort();
 }
 
+/* Remove local Xauthority file. */
+static void
+xauthfile_cleanup_proc(void *ignore)
+{
+  debug("xauthfile_cleanup_proc called");
+
+  if (xauthfile != NULL) {
+    unlink(xauthfile);
+    xfree(xauthfile);
+    xauthfile = NULL;
+  }
+}
+
 /* 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
@@ -1760,6 +1772,7 @@
 	  if ((xauthfd = mkstemp(xauthfile)) != -1) {
 	    fchown(xauthfd, pw->pw_uid, pw->pw_gid);
 	    close(xauthfd);
+            fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
 	  }
 	  else {
 	    xfree(xauthfile);
@@ -1905,8 +1918,7 @@
   if ((pid = fork()) == 0)
     {
       /* Child.  Reinitialize the log since the pid has changed. */
-      log_init(av0, debug_flag && !inetd_flag, debug_flag, 
-	       options.quiet_mode, options.log_facility);
+      log_init(av0, 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. */
@@ -1988,11 +2000,6 @@
 
   debug("pty_cleanup_proc called");
 
-#if defined(KRB4)
-  /* Destroy user's ticket cache file. */
-  (void) dest_tkt();
-#endif /* KRB4 */
-  
   /* Record that the user has logged out. */
   record_logout(cu->pid, cu->ttyname);
 
@@ -2040,8 +2047,7 @@
       pid = getpid();
 
       /* Child.  Reinitialize the log because the pid has changed. */
-      log_init(av0, debug_flag && !inetd_flag, debug_flag, options.quiet_mode, 
-	       options.log_facility);
+      log_init(av0, options.log_level, options.log_facility, log_stderr);
 
       /* Close the master side of the pseudo tty. */
       close(ptyfd);
@@ -2395,8 +2401,12 @@
     child_set_env(&env, &envsize, "DISPLAY", display);
 
 #ifdef KRB4
-  if (ticket)
-    child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+  {
+	 extern char *ticket;
+	 
+	 if (ticket)
+		child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+  }
 #endif /* KRB4 */
 
 #ifdef HAVE_LIBPAM