diff --git a/src/configure.in b/src/configure.in
index 2a85a6167b7ae20aca59885949d3bbce275d7b3b..ff9b016154bb2dab5626088c3840c273a434b449 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.156 1998/02/01 07:07:38 hubbe Exp $")
+AC_REVISION("$Id: configure.in,v 1.157 1998/02/05 02:57:37 hubbe Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -640,7 +640,8 @@ AC_CHECK_HEADERS(sys/rusage.h time.h sys/time.h sys/types.h unistd.h stdlib.h \
 memory.h values.h string.h strings.h fcntl.h sys/filio.h sys/sockio.h crypt.h \
 locale.h sys/resource.h sys/select.h sys/mman.h setjmp.h limits.h pthread.h \
 thread.h dlfcn.h dld.h sys/times.h sched.h sys/procfs.h sys/param.h winsock2.h \
-sys/ioct.h sys/socket.h malloc.h netinet/in.h sys/wait.h winbase.h)
+sys/ioct.h sys/socket.h malloc.h netinet/in.h sys/wait.h winbase.h grp.h pwd.h \
+passwd.h group.h)
 
 AC_CHECK_SIZEOF(char *,4)
 AC_CHECK_SIZEOF(long,4)
@@ -967,6 +968,9 @@ AC_CHECK_FUNCS( \
  fork1 \
  setuid getuid seteuid geteuid \
  setgid getgid setegid getegid \
+ getpwent getpwnam getpwuid \
+ getgrent getgrnam \
+ initgroups setgroups
 )
 
 if test $ac_cv_func_crypt$ac_cv_func__crypt = nono ; then
diff --git a/src/signal_handler.c b/src/signal_handler.c
index ae3e464c0047a99a8e03ae0dff6af6dd71ca77aa..60b33816841e1021999a20f71fbc117053a887b0 100644
--- a/src/signal_handler.c
+++ b/src/signal_handler.c
@@ -21,6 +21,22 @@
 #include "builtin_functions.h"
 #include <signal.h>
 
+#ifdef HAVE_PASSWD_H
+# include <passwd.h>
+#endif
+
+#ifdef HAVE_GROUP_H
+# include <group.h>
+#endif
+
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#ifdef HAVE_GRP_H
+# include <grp.h>
+#endif
+
 #ifdef HAVE_WINBASE_H
 #include <winbase.h>
 #endif
@@ -428,7 +444,7 @@ static void report_child(int pid,
 					       pid_status_program)))
 	{
 	  p->state = PROCESS_EXITED;
-	  if(WIFEXITED(p->result))
+	  if(WIFEXITED(status))
 	    p->result = WEXITSTATUS(status);
 	  else
 	    p->result=-1;
@@ -489,7 +505,7 @@ static void f_pid_status_wait(INT32 args)
 #endif
 #endif
     THREADS_DISALLOW();
-    if(pid >= -1)
+    if(pid > -1)
       report_child(pid, status);
     check_signals(0,0,0);
   }
@@ -600,6 +616,53 @@ static HANDLE get_inheritable_handle(struct mapping *optional,
  * FIXME:
  *   Support for setresuid() and setresgid().
  */
+
+#ifdef HAVE_GETPWENT
+#ifndef HAVE_GETPWNAM
+struct passwd *getpwnam(char *name)
+{
+  struct passwd *pw;
+  setpwent();
+  while(pw=getpwent())
+    if(strcmp(pw->pw_name,name))
+      break;
+  endpwent();
+  return pw;
+}
+#define HAVE_GETPWNAM
+#endif
+
+#ifndef HAVE_GETPWUID
+struct passwd *getpwiod(int uid)
+{
+  struct passwd *pw;
+  setpwent();
+  while(pw=getpwent())
+    if(pw->pw_uid == uid)
+      break;
+  endpwent();
+  return 0;
+}
+#define HAVE_GETPWUID
+#endif
+#endif
+
+#ifdef HAVE_GETGRENT
+#ifndef HAVE_GETGRNAM
+struct group *getgrnam(char *name)
+{
+  struct group *gr;
+  setgrent();
+  while(pw=getgrent())
+    if(strcmp(gr->gr_name,name))
+      break;
+  endgrent();
+  return gr;
+}
+#define HAVE_GETGRNAM
+#endif
+#endif
+
 void f_create_process(INT32 args)
 {
   struct array *cmd=0;
@@ -769,7 +832,12 @@ void f_create_process(INT32 args)
       mapping_insert(pid_mapping,sp-1, sp-2);
       pop_n_elems(2);
     }else{
-      int euid;
+      int wanted_uid;
+      int wanted_gid;
+      int gid_request=0;
+      int do_initgroups=1;
+      struct passwd *pw=0;
+
       char **argv;
 #ifdef DECLARE_ENVIRON
       extern char **environ;
@@ -792,52 +860,108 @@ void f_create_process(INT32 args)
       
       argv[e]=0;
 
-      euid=geteuid();
+#ifdef HAVE_GETEUID
+      wanted_uid=geteuid();
+#else
+      wanted_uid=getgid();
+#endif
+
+#ifdef HAVE_GETGID
+      wanted_gid=getegid();
+#else
+      wanted_gid=getgid();
+#endif
+
+#ifdef HAVE_SETEUID
+      seteuid(0);
+#endif
 
       if(optional)
       {
 	int toclose[3];
 	int fd;
 
-#ifdef HAVE_SETGID
 	if((tmp=simple_mapping_string_lookup(optional, "gid")))
 	{
-	  if(tmp->type == T_INT)
+	  switch(tmp->type)
 	  {
-#ifdef HAVE_SETEUID
-	    seteuid(0);
-#endif
-	    if(!setgid(tmp->u.integer)
-#ifdef HAVE_SETEGID
-	       || !setegid(tmp->u.integer)
-#endif
-		 )
+	    case T_INT:
+	      wanted_gid=tmp->u.integer;
+	      gid_request=1;
+	      break;
+
+#ifdef HAVE_GETGRNAM
+	    case T_STRING:
 	    {
-	      exit(69);
+	      struct group *gr=getgrnam(tmp->u.string->str);
+	      if(!gr) exit(77);
+	      wanted_gid=tmp->u.integer;
+	      gid_request=1;
 	    }
+#endif
+
+	    default:
+	      exit(64);
 	  }
 	}
-#endif
 
-#ifdef HAVE_SETUID
 	if((tmp=simple_mapping_string_lookup(optional, "uid")))
 	{
-	  if(tmp->type == T_INT)
+	  switch(tmp->type)
 	  {
-#ifdef HAVE_SETEUID
-	    seteuid(0);
+	    case T_INT:
+	      wanted_uid=tmp->u.integer;
+#ifdef HAVE_GETPWUID
+	      if(!gid_request)
+	      {
+		pw=getpwuid(wanted_uid);
+		if(pw) wanted_gid=pw->pw_gid;
+	      }
 #endif
-	    if(!setuid(euid=tmp->u.integer) 
-#ifdef HAVE_SETEUID
-	       || ! seteuid(tmp->u.integer)
+	      break;
+
+#ifdef HAVE_GETPWNAM
+	    case T_STRING:
+	      printf("poof\n");
+	      pw=getpwnam(tmp->u.string->str);
+	      if(!pw) exit(77);
+	      wanted_uid=pw->pw_uid;
+	      if(!gid_request) 
+		wanted_gid=pw->pw_gid;  
+	      break;
 #endif
-	      )
+
+	    default:
+	      exit(64);
+	  }
+	}
+
+	if((tmp=simple_mapping_string_lookup(optional, "noinitgroups")))
+	  if(!IS_ZERO(tmp))
+	    do_initgroups=0;
+
+	if((tmp=simple_mapping_string_lookup(optional, "setgroups")))
+	{
+#ifdef HAVE_SETGROUPS
+	  if(tmp->type != T_ARRAY)
+	  {
+	    int e;
+	    gid_t *g=(gid_t *)xalloc(sizeof(gid_t) * tmp->u.array->size);
+	    for(e=0;e<tmp->u.array->size;e++)
 	    {
-	      exit(69);
+	      if(tmp->u.array->item[e].type != T_INT) exit(64);
+	      g[e]=tmp->u.array->item[e].u.integer;
 	    }
+	    if(!setgroups(tmp->u.array->size, g))  exit(77);
+	    do_initgroups=0;
+	  }else{
+	    exit(64);
 	  }
-	}
+#else
+	  exit(69);
 #endif
+	}
+
 
 	if((tmp=simple_mapping_string_lookup(optional, "cwd")))
 	  if(tmp->type == T_STRING)
@@ -908,7 +1032,13 @@ void f_create_process(INT32 args)
 	    {
 	      apply(tmp->u.object,"query_fd",0);
 	      if(sp[-1].type == T_INT)
-		dup2(toclose[fd]=sp[-1].u.integer, fd);
+	      {
+		if(sp[-1].u.integer != fd)
+		{
+		  dup2(toclose[fd]=sp[-1].u.integer, fd);
+		}
+	      }
+	      pop_stack();
 	    }
 	  }
 	}
@@ -916,7 +1046,7 @@ void f_create_process(INT32 args)
 	for(fd=0;fd<3;fd++)
 	{
 	  int f2;
-	  if(toclose[fd]<0) continue;
+	  if(toclose[fd]<3) continue;
 
 	  for(f2=0;f2<fd;f2++)
 	    if(toclose[fd]==toclose[f2])
@@ -929,18 +1059,75 @@ void f_create_process(INT32 args)
 	/* Left to do: cleanup? */
       }
 
-#if defined(HAVE_SETEUID) && defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_SETEUID)
-      /* Protect us from harm */
-      seteuid(0);
-      setgid(geteuid());
-      setuid(euid);
-      seteuid(euid);
+      printf("foo\n");
+#ifdef HAVE_SETGID
+#ifdef HAVE_GETGID
+      if(wanted_gid != getgid())
+#endif
+      {
+	if(setgid(wanted_gid))
+#ifdef _HPUX_SOURCE
+          /* Kluge for HP-(S)UX */
+	  if(wanted_gid > 60000 && setgid(-2) && setgid(65534) && setgid(60001))
+#endif
+	    exit(77);
+      }
 #endif
 
+      printf("bar\n");
+
+#ifdef HAVE_SETUID
+#ifdef HAVE_GETUID
+      if(wanted_uid != getuid())
+#endif
+      {
+#ifdef HAVE_INITGROUPS
+	if(do_initgroups)
+	{
+	  int initgroupgid;
+	  if(!pw) pw=getpwuid(wanted_uid);
+	  if(!pw) exit(77);
+	  initgroupgid=pw->pw_gid;
+	  printf("uid=%d euid=%d initgroups(%s,%d)\n",getuid(),geteuid(),pw->pw_name, initgroupgid);
+	  if(initgroups(pw->pw_name, initgroupgid))
+#ifdef _HPUX_SOURCE
+	    /* Kluge for HP-(S)UX */
+	    if(initgroupgid>60000 &&
+	       initgroups(wanted_uid,-2) &&
+	       initgroups(wanted_uid,65534)
+	       initgroups(wanted_uid,60001))
+#endif /* _HPUX_SOURCE */
+	    {
+#ifdef HAVE_SETGROUPS
+	      gid_t x[]={ 65534 };
+	      if(setgroups(0,x))
+#endif /* SETGROUPS */
+		exit(77);
+	    }
+	}
+#endif /* INITGROUPS */
+	printf("uid=%d gid=%d euid=%d egid=%d setuid(%d)\n",getuid(),getgid(),geteuid(),getegid(),wanted_uid);
+	if(setuid(wanted_uid))
+	{
+	  perror("setuid");
+	  exit(77);
+	}
+      }
+#endif /* SETUID */
+
+      printf("gazonk\n");
+
+#ifdef HAVE_SETEUID
+      seteuid(wanted_uid);
+#endif
+	
       my_set_close_on_exec(0,0);
       my_set_close_on_exec(1,0);
       my_set_close_on_exec(2,0);
       do_set_close_on_exec();
+      set_close_on_exec(0,0);
+      set_close_on_exec(1,0);
+      set_close_on_exec(2,0);
       
       execvp(argv[0],argv);
       exit(69);
@@ -1276,10 +1463,10 @@ void init_signals(void)
 
 #ifdef DEBUG
 #ifdef SIGSEGV
-  my_signal(SIGSEGV, fatal_signal);
+/*  my_signal(SIGSEGV, fatal_signal); */
 #endif
 #ifdef SIGBUS
-  my_signal(SIGBUS, fatal_signal);
+/*  my_signal(SIGBUS, fatal_signal); */
 #endif
 #endif