diff --git a/src/client.c b/src/client.c
index 0a304716fc3fffc5e47250a8a5cea2fdcf514db7..254743702573e63feeaa0e528f0ac7d3029f9d60 100644
--- a/src/client.c
+++ b/src/client.c
@@ -80,12 +80,12 @@ static int client_initiate(struct fd_callback **c,
   
   res = A_WRITE(connection->raw,
 		ssh_format("%lS\r\n", connection->client_version));
-  if (LSH_PROBLEMP(res))
+  if (LSH_CLOSEDP(res))
     return res;
 
-  return initiate_keyexchange(connection, CONNECTION_CLIENT,
-			      MAKE_KEXINIT(closure->init),
-			      NULL);
+  return res | initiate_keyexchange(connection, CONNECTION_CLIENT,
+				    MAKE_KEXINIT(closure->init),
+				    NULL);
 }
 
 struct client_line_handler
@@ -207,3 +207,4 @@ struct close_callback *make_client_close_handler(void)
 
   return c;
 }
+
diff --git a/src/client_keyexchange.c b/src/client_keyexchange.c
index cee5ffc76aac0728911169638e9814fd620f4972..d34f27ca3a45af7703eadde934617e74b2fb0cdc 100644
--- a/src/client_keyexchange.c
+++ b/src/client_keyexchange.c
@@ -85,7 +85,7 @@ static int do_handle_dh_reply(struct packet_handler *c,
    * handler for recieving the newkeys message. */
 
   res = A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
-  if (LSH_PROBLEMP(res))
+  if (LSH_CLOSEDP(res))
     return res;
 
   /* Record session id */
@@ -110,11 +110,11 @@ static int do_handle_dh_reply(struct packet_handler *c,
   connection->dispatch[SSH_MSG_KEXDH_REPLY] = connection->fail;
   connection->kex_state = KEX_STATE_NEWKEYS;
   
-  res = send_verbose(connection->write, "Key exchange successful!", 0);
-  if (LSH_PROBLEMP(res))
+  res |= send_verbose(connection->write, "Key exchange successful!", 0);
+  if (LSH_CLOSEDP(res))
     return res;
   
-  return SERVICE_INIT(closure->finished, connection);
+  return res | SERVICE_INIT(closure->finished, connection);
 }
 
 static int do_init_dh(struct keyexchange_algorithm *c,
@@ -148,15 +148,15 @@ static int do_init_dh(struct keyexchange_algorithm *c,
   /* Send client's message */
   res = A_WRITE(connection->write, dh_make_client_msg(&dh->dh));
 
-  if (LSH_PROBLEMP(res))
-    return res;
+  if (LSH_CLOSEDP(res))
+    return res | LSH_FAIL;
   
   /* Install handler */
   connection->dispatch[SSH_MSG_KEXDH_REPLY] = &dh->super;
   
   connection->kex_state = KEX_STATE_IN_PROGRESS;
   
-  return LSH_OK | LSH_GOON;
+  return res | LSH_OK | LSH_GOON;
 }
 
 
diff --git a/src/keyexchange.c b/src/keyexchange.c
index 61102e47ff1c6630d1a89d4fc76cc353e09428a1..513b1c1b4599337b810d241c4f2c48a47a507556 100644
--- a/src/keyexchange.c
+++ b/src/keyexchange.c
@@ -150,8 +150,8 @@ int initiate_keyexchange(struct ssh_connection *connection,
 
   res = A_WRITE(connection->write, lsh_string_dup(s));
   
-  if (!LSH_PROBLEMP(res) && first_packet)
-    return A_WRITE(connection->write, first_packet);
+  if (!LSH_CLOSEDP(res) && first_packet)
+    return res | A_WRITE(connection->write, first_packet);
   else
     return res;
 }
@@ -179,7 +179,7 @@ int disconnect_kex_failed(struct ssh_connection *connection, char *msg)
 {
   return A_WRITE(connection->write,
 		 format_disconnect(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
-				   msg));
+				   msg, ""));
 }
 
 static int do_handle_kexinit(struct packet_handler *c,
@@ -196,12 +196,13 @@ static int do_handle_kexinit(struct packet_handler *c,
   void **algorithms;
 
   int i;
+  int res = 0;
 
   MDEBUG(closure);
   MDEBUG(msg);
   
   if (!msg)
-    return 0;
+    return LSH_FAIL | LSH_DIE;
 
   /* Save value for later signing */
   connection->literal_kexinits[!closure->type] = packet;
@@ -211,7 +212,6 @@ static int do_handle_kexinit(struct packet_handler *c,
   /* Have we sent a kexinit message? */
   if (!connection->kexinits[closure->type])
     {
-      int res;
       struct lsh_string *packet;
       struct kexinit *sent = MAKE_KEXINIT(closure->init);
       connection->kexinits[closure->type] = sent;
@@ -219,7 +219,7 @@ static int do_handle_kexinit(struct packet_handler *c,
       connection->literal_kexinits[closure->type] = lsh_string_dup(packet); 
       
       res = A_WRITE(connection->write, packet);
-      if (LSH_PROBLEMP(res))
+      if (LSH_CLOSEDP(res))
 	return res;
     }
 
@@ -250,7 +250,7 @@ static int do_handle_kexinit(struct packet_handler *c,
 	  disconnect_kex_failed(connection,
 				"No common key exchange method.\r\n");
 	  
-	  return LSH_FAIL | LSH_CLOSE;
+	  return res | LSH_FAIL | LSH_CLOSE;
 	}
     }
   hostkey_algorithm
@@ -266,7 +266,7 @@ static int do_handle_kexinit(struct packet_handler *c,
       if (!parameters[i])
 	{
 	  disconnect_kex_failed(connection, "");
-	  return LSH_FAIL | LSH_CLOSE;
+	  return res | LSH_FAIL | LSH_CLOSE;
 	}
     }
   
@@ -275,13 +275,14 @@ static int do_handle_kexinit(struct packet_handler *c,
   for (i = 0; i<KEX_PARAMETERS; i++)
     algorithms[i] = ALIST_GET(closure->algorithms, parameters[i]);
       
-  return KEYEXCHANGE_INIT( (struct keyexchange_algorithm *)
-			   ALIST_GET(closure->algorithms, kex_algorithm),
-			   connection,
-			   closure->finished,
-			   hostkey_algorithm,
-			   ALIST_GET(closure->algorithms, hostkey_algorithm),
-			   algorithms);
+  return res
+    | KEYEXCHANGE_INIT( (struct keyexchange_algorithm *)
+			ALIST_GET(closure->algorithms, kex_algorithm),
+			connection,
+			closure->finished,
+			hostkey_algorithm,
+			ALIST_GET(closure->algorithms, hostkey_algorithm),
+			algorithms);
 }
 
 struct packet_handler *make_kexinit_handler(int type,
diff --git a/src/read_line.c b/src/read_line.c
index 32a77b5525b8c5eab46589f2113bfea13aba87c4..c881e6a365b01dd36e550c866b659001a65fc8e5 100644
--- a/src/read_line.c
+++ b/src/read_line.c
@@ -131,7 +131,7 @@ static int do_read_line(struct read_handler **h,
 	      while(next && (read.index < closure->pos))
 		{
 		  res = READ_HANDLER(next, &read.super);
-		  if (LSH_PROBLEMP(res))
+		  if (LSH_CLOSEDP(res))
 		    return res;
 		}
 	    }
diff --git a/src/read_packet.c b/src/read_packet.c
index fc23ff6daf87cb749b6ac451fbbefd7b4eeab653..d2b52a7f5953696f66f7af59d964228c0e77c9b4 100644
--- a/src/read_packet.c
+++ b/src/read_packet.c
@@ -290,7 +290,7 @@ static int do_read_packet(struct read_handler **h,
 	  closure->state = WAIT_START;
 	  
 	  res = A_WRITE(closure->handler, packet);
-	  if (LSH_PROBLEMP(res))
+	  if (LSH_ACTIONP(res))
 	    return res;
 	  break;
 	}
diff --git a/src/server.c b/src/server.c
index 701c79016cb8254509a206df1f1b5a6537798645..15971ac2d8240ce0833c0d57b77834cd96111c36 100644
--- a/src/server.c
+++ b/src/server.c
@@ -80,12 +80,12 @@ static int server_initiate(struct fd_callback **c,
 
   res = A_WRITE(connection->raw,
 		 ssh_format("%lS\r\n", connection->server_version));
-  if (LSH_PROBLEMP(res))
+  if (LSH_CLOSEDP(res))
     return res;
 
-  return initiate_keyexchange(connection, CONNECTION_SERVER,
-			      MAKE_KEXINIT(closure->init),
-			      NULL);
+  return res | initiate_keyexchange(connection, CONNECTION_SERVER,
+				    MAKE_KEXINIT(closure->init),
+				    NULL);
 }
 
 struct server_line_handler
diff --git a/src/server_keyexchange.c b/src/server_keyexchange.c
index cc6602a507cc78ab1865c73b11fbed342628e5b6..4361bb4028be0a7ddcec44683e2b0d09b99d01a5 100644
--- a/src/server_keyexchange.c
+++ b/src/server_keyexchange.c
@@ -73,14 +73,14 @@ static int do_handle_dh_init(struct packet_handler *c,
   res = A_WRITE(connection->write, dh_make_server_msg(&closure->dh,
 						      closure->signer));
 
-  if (LSH_PROBLEMP(res))
+  if (LSH_CLOSEDP(res))
     return res;
   
   /* Send a newkeys message, and install a handler for recieving the
    * newkeys message. */
 
-  res = A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
-  if (LSH_PROBLEMP(res))
+  res |= A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
+  if (LSH_CLOSEDP(res))
     return res;
   
   /* Record session id */
@@ -105,11 +105,11 @@ static int do_handle_dh_init(struct packet_handler *c,
   connection->kex_state = KEX_STATE_NEWKEYS;
   connection->dispatch[SSH_MSG_KEXDH_INIT] = connection->fail;
 
-  res = send_verbose(connection->write, "Key exchange successful!", 0);
-  if (LSH_PROBLEMP(res))
+  res |= send_verbose(connection->write, "Key exchange successful!", 0);
+  if (LSH_CLOSEDP(res))
     return res;
   
-  return SERVICE_INIT(closure->finished, connection);
+  return res | SERVICE_INIT(closure->finished, connection);
 }
 
 static int do_init_dh(struct keyexchange_algorithm *c,
diff --git a/src/service.h b/src/service.h
index a497c2fa351e7db724306267d94a7cfa3f2ddd09..94f3d27d36a96752de5d5da2b9fc780bbc7ab148 100644
--- a/src/service.h
+++ b/src/service.h
@@ -24,6 +24,7 @@
 #ifndef LSH_SERVICE_H_INCLUDED
 #define LSH_SERVICE_H_INCLUDED
 
+#include "alist.h"
 #include "connection.h"
 
 /* Used on both client and server side */
@@ -43,4 +44,8 @@ struct lsh_string *format_service_request(int name);
 
 int request_service(int name, struct ssh_service * service);
 
+struct lsh_string *format_service_accept(int name);
+
+struct ssh_service *make_meta_service(struct alist *services);
+
 #endif /* LSH_SERVICE_H_INCLUDED */
diff --git a/src/session.h b/src/session.h
index 43a269ff6a106d0fb1ec4651b2d00b7ee4e26cd6..85972dfc8d5f8714a1ba4f45cc59e6069e94cf98 100644
--- a/src/session.h
+++ b/src/session.h
@@ -1,73 +1,40 @@
 /* session.h
  *
  * Manage the ssh-connection service.
+ *
+ * $Id$
+ */
+
+/* lsh, an implementation of the ssh protocol
+ *
+ * Copyright (C) 1998 Niels M�ller
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef LSH_SESSION_H_INCLUDED
 #define LSH_SESSION_H_INCLUDED
 
+#include "alist.h"
 #include "connection.h"
 #include "channel.h"
+#include "parse.h"
 
-struct ssh_session
-{
 #if 0
-  /* FIXME: This is relevant only for the server side. It's probably
-   * better to store this in the connection struct */
-  uid_t user;  /* Authenticated user */
+struct ssh_service *make_session_service(struct alist *global_requests,
+					 struct alist *channel_requests);
 #endif
-  /* Channels are indexed by local number */
-  struct channel **channels;
-
-  /* Allocation of local channel numbers is managed using the same *
-   * method as is traditionally used for allocation of unix file
-   * descriptors. */
-
-  UINT32 allocated_channels;
-  UINT32 next_channel;
-  UINT32 used_channels;
-  UINT32 max_channels; /* Max number of channels allowed */
-};
-
-/* SSH_MSG_GLOBAL_REQUEST */
-struct global_request
-{
-  struct lsh_object *header;
-
-  int (*handler)(struct global_request *closure,
-		 int want_reply,
-		 struct simple_buffer *args);
-};
-
-#define GLOBAL_REQUEST(c, w, a) ((c)->handler((c), (w), (a)))
-
-/* SSH_MSG_CHANNEL_OPEN */
-struct channel_open
-{
-  struct lsh_object *header;
-
-  int (*handler)(struct channel_open *closure,
-		 UINT32 channel_number, /* Remote channel number */
-		 UINT32 rec_window_size,
-		 UINT32 rec_max_packet,
-		 struct simple_buffer *args);
-};
-
-#define CHANNEL_OPEN(c, n, w, m, a) \
-((c)->handler((c), (n), (w), (m), (a)))
-
-/* SSH_MSH_CHANNEL_REQUEST */
-struct channel_request
-{
-  struct lsh_object *header;
-
-  int (*handler)(struct channel_request *closure,
-		 struct ssh_channel *channel,
-		 int want_reply;
-		 struct simple_buffer *args);
-};
 
-#define CHANNEL_REQUEST(s, c, w, a) \
-((s)->handler((s), (c), (w), (a)))
- 
 #endif /* LSH_SESSION_H_INCLUDED */
diff --git a/src/userauth.h b/src/userauth.h
index f0e4c9a74555a2999ffa722df76d9b04aaccebe2..71c2d8670e440911c180f63b51f2cfbdee0beea3 100644
--- a/src/userauth.h
+++ b/src/userauth.h
@@ -24,7 +24,8 @@
 #ifndef LSH_USERAUTH_H_INCLUDED
 #define LSH_USERAUTH_H_INCLUDED
 
-#include "lsh_types.h"
+#include "parse.h"
+#include "service.h"
 
 /* Returns 0 if the request is somehow invalid. Otheerwise, returns 1,
  * and sets SERVICE non-NULL iff access is granted. */
@@ -35,8 +36,9 @@ struct userauth
 {
   struct lsh_object header;
   
-  int (*authenticate)(struct userauth *self,
-		      lsh_string *user,
+  int (*authenticate)(struct userauth *closure,
+		      /* The name is consumed by this function */
+		      struct lsh_string *username,
 		      int requested_service,
 		      struct simple_buffer *args,
 		      struct ssh_service **service);
@@ -45,8 +47,8 @@ struct userauth
 #define AUTHENTICATE(s, u, r, a, g) \
 ((s)->authenticate((s), (u), (r), (a), (g)))
      
-struct ssh_service *make_client_userauth(struct lsh_string username,
+struct ssh_service *make_client_userauth(struct lsh_string *username,
 					 int service_name,
 					 struct ssh_service *service);
-     
+
 #endif /* LSH_USERAUTH_H_INCLUDED */