--- gdomap.c.org	Tue Aug  5 22:39:51 2003
+++ gdomap.c	Sat Aug 23 12:18:47 2003
@@ -823,7 +823,11 @@
 static unsigned long	prb_size = 0;
 typedef struct	{
   struct in_addr	sin;
+#ifdef __FreeBSD__
+  time_t		when;
+#else /* __FreeBSD__ */
   long			when;
+#endif /* __FreeBSD__ */
 } prb_type;
 static prb_type	**prb = 0;
 
@@ -4598,64 +4602,148 @@
 #endif
     }
 
-#if	!defined(__svr4__)
   /*
    * As another level of paranoia - restrict this process to /tmp
    */
-  if (chdir("/tmp") < 0)
+  
+  {
+    //
+    // Try to get the UID and GID first
+    //
+    
+#ifndef __MINGW__
+#ifdef __FreeBSD__
+    uid_t	uid = 65534; // setuid(2) expects an unsigned int
+    gid_t	gid = 65534; // dito for getgid(2)
+#else /* __FreeBSD__ */
+    int		uid = -2;
+    int		gid = -2;
+#endif /* __FreeBSD__ */
+    
+    //
+    // If we are not 'root' simply use our own UID and GID so we can
+    // later kill it again if needed
+    //
+    
+    if( 0 != getuid() )
+    {
+      uid = getuid();
+      gid = getgid();
+    }
+    else // gdomap runs as 'root' so we try to switch to 'nobody'
+    {
+#ifdef	HAVE_PWD_H
+#ifdef	HAVE_GETPWNAM
+      const char	*name = "nobody";
+      struct passwd	*pwd;
+      
+#ifdef __FreeBSD__
+      // rewind the PWD database to the beginning and make sure it says open
+      setpassent(1);
+#endif
+      
+      //
+      // Translate name into a PWD pointer
+      //
+      
+      pwd = (struct passwd *) getpwnam(name);
+      
+      if( pwd )
+      {
+        uid = pwd->pw_uid;
+        gid = pwd->pw_gid;
+      }
+      else // Failed, let's try as a number
+      {
+        long	id;
+        char	*p;
+        
+        id = strtol(name, &p, 10);
+        
+        if( *name && !*p && (pwd = getpwuid(id)) )
+        {
+          uid = pwd->pw_uid;
+          gid = pwd->pw_gid;
+        }
+        else // Failed as well, dump a warning
+        {
+          sprintf(ebuf, "Cannot get UID and GID, assuming default values.");
+          gdomap_log(LOG_WARNING);
+        }
+      }
+#ifdef __FreeBSD__
+      // close the PWD database
+      endpwent();
+#endif /* __FreeBSD__ */
+#endif /* HAVE_GETPWNAM */
+#endif /* HAVE_PWD_H */
+    }
+#endif /* __MINGW__ */
+  
+    //
+    // Now that we got the UID and GID, we can jail gdomap to /tmp
+    //
+    
+#if !defined(__svr4__)
+    if (chdir("/tmp") < 0)
     {
       sprintf(ebuf, "Unable to change directory to /tmp");
       gdomap_log(LOG_CRIT);
+      
+      // What about trying /var/tmp or /usr/tmp ?
+      
       exit(EXIT_FAILURE);
     }
+    
+    //
+    // Looks like /tmp exists, so if we are root, set it as root directory
+    // to jail gdomap, then make sure we're at the top level
+    //
+    
 #ifndef __MINGW__
-  if (geteuid() == 0)
+    if( 0 == geteuid() )
     {
-      if (chroot("/tmp") < 0)
-	{
-	  sprintf(ebuf, "Unable to change root to /tmp");
-	  gdomap_log(LOG_CRIT);
-	  exit(EXIT_FAILURE);
-	}
+      if( chroot("/tmp") < 0 )
+      {
+        sprintf(ebuf, "Unable to change root to /tmp");
+        gdomap_log(LOG_CRIT);
+        exit(EXIT_FAILURE);
+      }
+      
       chdir("/");
     }
 #endif /* __MINGW__ */
 #endif /* __svr4__ */
-
+  
 #ifndef __MINGW__
-  /*
-   * Try to become a 'safe' user now that we have
-   * done everything that needs root priv.
-   */
-  if (getuid () != 0)
-    {
-      /*
-       * Try to be the user who launched us ... so they can kill us too.
-       */
-      setuid (getuid ());
-      setgid (getgid ());
-    }
-  else
-    {
-      int	uid = -2;
-      int	gid = -2;
-#ifdef	HAVE_PWD_H
-#ifdef	HAVE_GETPWNAM
-      struct passwd *pw = getpwnam("nobody");
-
-      if (pw != 0)
-	{
-	  uid = pw->pw_uid;
-	  gid = pw->pw_gid;
-	}
-#endif
-#endif
-      setuid (uid);
-      setgid (gid);
-      setgroups (0, 0);	/* Empty additional groups list */
-    }
+    //
+    // Try to become a 'safe' user now that we have
+    // done everything that needs root priv.
+    //
+    
+    if( 0 == getuid )
+    {
+      //
+      // On FreeBSD, setgroups(2) only works correctly for root, therefor
+      // we clear the group access list before the actual switch and dump
+      // a warning if it fails
+      //
+      
+      errno = 0;
+      
+      if( setgroups (0, NULL) < 0 )
+      {
+        sprintf(ebuf, "Cannot clear the group access list: %s",
+                strerror(errno));
+        gdomap_log(LOG_WARNING);
+      }
+    }
+    
+    setuid(uid);
+    setgid(gid);
 #endif /* __MINGW__ */
-
+  }
+  
   if (getuid() == 0)
     {
       sprintf(ebuf, "Still running as root after trying to change");
