a cleanup of the receive_smb() usage, adding timeouts in some places
[samba.git] / source3 / smbd / server.c
index 5d8facef33fb5adb819909d202384cecd2e87202..3ececed393a6a6bada83eb4955b3e6cc834529fd 100644 (file)
 */
 
 #include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
 #include "trans2.h"
-#include "reply.h"
 
 pstring servicesf = CONFIGFILE;
-pstring OriginalDir ="/";
 extern pstring debugf;
 extern pstring sesssetup_user;
 
@@ -34,16 +30,8 @@ char *InBuffer = NULL;
 char *OutBuffer = NULL;
 char *last_inbuf = NULL;
 
-int initial_uid = 0;
-int initial_gid = 0;
-
 BOOL share_mode_pending = False;
 
-/* have I done a become_user? */
-static struct {
-  int cnum, uid;
-} last_user;
-
 /* the last message the was processed */
 int last_message = -1;
 
@@ -88,16 +76,9 @@ int unix_ERR_code=0;
 extern int extra_time_offset;
 
 extern pstring myhostname;
-extern struct in_addr myip;
-
 
 static int find_free_connection(int hash);
 
-#ifdef SMB_PASSWD
-extern void generate_next_challenge(char *challenge);
-extern void set_challenge(char *challenge);
-#endif
-
 /* for readability... */
 #define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
 #define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
@@ -148,31 +129,20 @@ mode_t unix_mode(int cnum,int dosmode)
 int dos_mode(int cnum,char *path,struct stat *sbuf)
 {
   int result = 0;
+  extern struct current_user current_user;
 
-#if OLD_DOS_MODE
-  if (!CAN_WRITE(cnum) || !((sbuf->st_mode & S_IWOTH) ||
-                           Connections[cnum].admin_user ||
-                           ((sbuf->st_mode & S_IWUSR) && 
-                            Connections[cnum].uid==sbuf->st_uid) ||
-                           ((sbuf->st_mode & S_IWGRP) && 
-                            in_group(sbuf->st_gid,Connections[cnum].gid,
-                                     Connections[cnum].ngroups,
-                                     Connections[cnum].igroups))))
-    result |= aRONLY;
-#else
   if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) {
     if (!((sbuf->st_mode & S_IWOTH) ||
          Connections[cnum].admin_user ||
-         ((sbuf->st_mode & S_IWUSR) && Connections[cnum].uid==sbuf->st_uid) ||
+         ((sbuf->st_mode & S_IWUSR) && current_user.uid==sbuf->st_uid) ||
          ((sbuf->st_mode & S_IWGRP) && 
-          in_group(sbuf->st_gid,Connections[cnum].gid,
-                   Connections[cnum].ngroups,Connections[cnum].igroups))))
+          in_group(sbuf->st_gid,current_user.gid,
+                   current_user.ngroups,current_user.igroups))))
       result |= aRONLY;
   } else {
     if ((sbuf->st_mode & S_IWUSR) == 0)
       result |= aRONLY;
   }
-#endif
 
   if ((sbuf->st_mode & S_IXUSR) != 0)
     result |= aARCH;
@@ -257,7 +227,7 @@ int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st)
     unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
     unixmode |= tmp;
   }
-    
+
   return(chmod(fname,unixmode));
 }
 
@@ -326,7 +296,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
   void *cur_dir;
   char *dname;
   BOOL mangled;
-  fstring name2;
+  pstring name2;
 
   mangled = is_mangled(name);
 
@@ -410,8 +380,12 @@ BOOL unix_convert(char *name,int cnum)
     {
       if ((! *name) || strchr(name,'/') || !is_8_3(name))
        {
+         char *s;
          fstring name2;
          sprintf(name2,"%.6s.XXXXXX",remote_machine);
+         /* sanitise the name */
+         for (s=name2 ; *s ; s++)
+           if (!issafe(*s)) *s = '_';
          strcpy(name,(char *)mktemp(name2));     
        }      
       return(True);
@@ -522,251 +496,6 @@ BOOL unix_convert(char *name,int cnum)
 }
 
 
-
-
-#ifdef QUOTAS
-#ifdef LINUX
-/****************************************************************************
-try to get the disk space from disk quotas (LINUX version)
-****************************************************************************/
-/*
-If you didn't make the symlink to the quota package, too bad :(
-*/
-#include "quota/quotactl.c"
-#include "quota/hasquota.c"
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
-  uid_t euser_id;
-  struct dqblk D;
-  struct stat S;
-  dev_t devno ;
-  struct mntent *mnt;
-  FILE *fp;
-  int found ;
-  int qcmd, fd ;
-  char *qfpathname;
-  
-  /* find the block device file */
-  
-  if ( stat(path, &S) == -1 )
-    return(False) ;
-
-  devno = S.st_dev ;
-  
-  fp = setmntent(MOUNTED,"r");
-  found = False ;
-  
-  while ((mnt = getmntent(fp)) != (struct mntent *) 0) {
-    if ( stat(mnt->mnt_dir,&S) == -1 )
-      continue ;
-    if (S.st_dev == devno) {
-      found = True ;
-      break ;
-    }
-  }
-  endmntent(fp) ;
-  
-  if ( ! found )
-    return(False) ;
-  
-  qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
-  
-  if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA))
-    return(False) ;
-  
-  if (!hasquota(mnt, USRQUOTA, &qfpathname))
-    return(False) ;
-  
-  euser_id = geteuid();
-  seteuid(0);
-  
-  if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) {
-    if ((fd = open(qfpathname, O_RDONLY)) < 0) {
-      seteuid(euser_id);
-      return(False);
-    }
-    lseek(fd, (long) dqoff(euser_id), L_SET);
-    switch (read(fd, &D, sizeof(struct dqblk))) {
-    case 0:/* EOF */
-      memset((caddr_t)&D, 0, sizeof(struct dqblk));
-      break;
-    case sizeof(struct dqblk):   /* OK */
-      break;
-    default:   /* ERROR */
-      close(fd);
-      seteuid(euser_id);
-      return(False);
-    }
-  }
-  seteuid(euser_id);
-  *bsize=1024;
-
-  if (D.dqb_bsoftlimit==0)
-    return(False);
-  if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit))
-    {
-      *dfree = 0;
-      *dsize = D.dqb_curblocks;
-    }
-  else {
-    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
-    *dsize = D.dqb_bsoftlimit;
-  }
-  return (True);
-}
-#else
-#ifndef CRAY
-/****************************************************************************
-try to get the disk space from disk quotas
-****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
-  uid_t user_id, euser_id;
-  int r;
-  char dev_disk[256];
-  struct dqblk D;
-  struct stat S;
-  /* find the block device file */
-  if ((stat(path, &S)<0) ||
-      (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
-
-  euser_id = geteuid();
-
-#ifdef USE_SETRES
-  /* for HPUX, real uid must be same as euid to execute quotactl for euid */
-  user_id = getuid();
-  setresuid(euser_id,-1,-1);
-#endif
-  r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
-  #ifdef USE_SETRES
-  if (setresuid(user_id,-1,-1))
-    DEBUG(5,("Unable to reset uid to %d\n", user_id));
-  #endif
-  /* Use softlimit to determine disk space, except when it has been exceeded */
-  *bsize = 1024;
-  if (r)
-    {
-      if (errno == EDQUOT) 
-       {
-         *dfree =0;
-         *dsize =D.dqb_curblocks;
-         return (True);
-       }
-      else return(False);
-    }
-  /* Use softlimit to determine disk space, except when it has been exceeded */
-  if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curfiles>D.dqb_fsoftlimit)) 
-    {
-      *dfree = 0;
-      *dsize = D.dqb_curblocks;
-    }
-  else {
-    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
-    *dsize = D.dqb_bsoftlimit;
-  }
-  return (True);
-}
-#else
-/****************************************************************************
-try to get the disk space from disk quotas (CRAY VERSION)
-****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
-  struct mntent *mnt;
-  FILE *fd;
-  struct stat sbuf;
-  dev_t devno ;
-  static dev_t devno_cached = 0 ;
-  static char name[MNTMAXSTR] ;
-  struct q_request request ;
-  struct qf_header header ;
-  static int quota_default = 0 ;
-  int found ;
-  
-  if ( stat(path,&sbuf) == -1 )
-    return(False) ;
-  
-  devno = sbuf.st_dev ;
-  
-  if ( devno != devno_cached ) {
-    
-    devno_cached = devno ;
-    
-    if ((fd = setmntent(KMTAB)) == NULL)
-      return(False) ;
-    
-    found = False ;
-    
-    while ((mnt = getmntent(fd)) != NULL) {
-      
-      if ( stat(mnt->mnt_dir,&sbuf) == -1 )
-       continue ;
-      
-      if (sbuf.st_dev == devno) {
-       
-       found = True ;
-       break ;
-       
-      }
-      
-    }
-    
-    strcpy(name,mnt->mnt_dir) ;
-    endmntent(fd) ;
-    
-    if ( ! found )
-      return(False) ;
-  }
-  
-  request.qf_magic = QF_MAGIC ;
-  request.qf_entry.id = geteuid() ;
-  
-  if (quotactl(name, Q_GETQUOTA, &request) == -1)
-    return(False) ;
-  
-  if ( ! request.user )
-    return(False) ;
-  
-  if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
-    
-    if ( ! quota_default ) {
-      
-      if ( quotactl(name, Q_GETHEADER, &header) == -1 )
-       return(False) ;
-      else
-       quota_default = header.user_h.def_fq ;
-    }
-    
-    *dfree = quota_default ;
-    
-  }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
-    
-    *dfree = 0 ;
-    
-  }else{
-    
-    *dfree = request.qf_entry.user_q.f_quota ;
-    
-  }
-  
-  *dsize = request.qf_entry.user_q.f_use ;
-  
-  if ( *dfree )
-    *dfree -= *dsize ;
-  
-  if ( *dfree < 0 )
-    *dfree = 0 ;
-  
-  *bsize = 4096 ;  /* Cray blocksize */
-  
-  return(True) ;
-  
-}
-#endif /* CRAY */
-#endif /* LINUX */
-#endif /* QUOTAS */
-
-
 /****************************************************************************
 normalise for DOS usage 
 ****************************************************************************/
@@ -1227,16 +956,6 @@ void close_file(int fnum)
   if (lp_share_modes(SNUM(cnum)))
     del_share_mode(fnum);
 
-  if (Files[fnum].modified) {
-    struct stat st;
-    if (fstat(Files[fnum].fd,&st) == 0) {
-      int dosmode = dos_mode(cnum,Files[fnum].name,&st);
-      if (!IS_DOS_ARCHIVE(dosmode)) {  
-       dos_chmod(cnum,Files[fnum].name,dosmode | aARCH,&st);
-      }
-    }    
-  }
-
   close(Files[fnum].fd);
 
   /* NT uses smbclose to start a print - weird */
@@ -1609,14 +1328,21 @@ int write_file(int fnum,char *data,int n)
     return(0);
   }
 
-  Files[fnum].modified = True;
+  if (!Files[fnum].modified) {
+    struct stat st;
+    Files[fnum].modified = True;
+    if (fstat(Files[fnum].fd,&st) == 0) {
+      int dosmode = dos_mode(Files[fnum].cnum,Files[fnum].name,&st);
+      if (MAP_ARCHIVE(Files[fnum].cnum) && !IS_DOS_ARCHIVE(dosmode)) { 
+       dos_chmod(Files[fnum].cnum,Files[fnum].name,dosmode | aARCH,&st);
+      }
+    }  
+  }
 
   return(write_data(Files[fnum].fd,data,n));
 }
 
 
-static int old_umask = 022;
-
 /****************************************************************************
 load parameters specific to a connection/service
 ****************************************************************************/
@@ -1661,261 +1387,6 @@ BOOL become_service(int cnum,BOOL do_chdir)
 }
 
 
-/****************************************************************************
-  become the specified uid 
-****************************************************************************/
-static BOOL become_uid(int uid)
-{
-  if (initial_uid != 0)
-    return(True);
-
-#ifdef AIX
-  {
-    /* AIX 3 stuff - inspired by a code fragment in wu-ftpd */
-    priv_t priv;
-
-    priv.pv_priv[0] = 0;
-    priv.pv_priv[1] = 0;
-    if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
-               &priv, sizeof(priv_t)) < 0 ||
-       setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 ||
-       seteuid((uid_t)uid) < 0) 
-      DEBUG(1,("Can't set uid (AIX3)"));
-  }
-#endif
-
-#ifdef USE_SETRES
-  if (setresuid(-1,uid,-1) != 0)
-#else
-    if ((seteuid(uid) != 0) && 
-       (setuid(uid) != 0))
-#endif
-      {
-       DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n",
-                uid,getuid(), geteuid()));
-       if (uid > 32000)
-         DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n"));
-       return(False);
-      }
-
-  if (((uid == -1) || (uid == 65535)) && geteuid() != uid)
-    {
-      DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n"));
-      return(False);
-    }
-
-  return(True);
-}
-
-
-/****************************************************************************
-  become the specified gid
-****************************************************************************/
-static BOOL become_gid(int gid)
-{
-  if (initial_uid != 0)
-    return(True);
-  
-#ifdef USE_SETRES 
-  if (setresgid(-1,gid,-1) != 0)
-#else
-    if (setgid(gid) != 0)
-#endif
-      {
-       DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n",
-                gid,getgid(),getegid()));
-       if (gid > 32000)
-         DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n"));
-       return(False);
-      }
-
-  return(True);
-}
-
-
-/****************************************************************************
-  become the specified uid and gid
-****************************************************************************/
-static BOOL become_id(int uid,int gid)
-{
-  return(become_gid(gid) && become_uid(uid));
-}
-
-/****************************************************************************
-become the guest user
-****************************************************************************/
-static BOOL become_guest(void)
-{
-  BOOL ret;
-  static struct passwd *pass=NULL;
-
-  if (initial_uid != 0) 
-    return(True);
-
-  if (!pass)
-    pass = Get_Pwnam(lp_guestaccount(-1),True);
-  if (!pass) return(False);
-
-  ret = become_id(pass->pw_uid,pass->pw_gid);
-
-  if (!ret)
-    DEBUG(1,("Failed to become guest. Invalid guest account?\n"));
-
-  last_user.cnum = -2;
-
-  return(ret);
-}
-
-/*******************************************************************
-check if a username is OK
-********************************************************************/
-static BOOL check_user_ok(int cnum,user_struct *vuser,int snum)
-{
-  int i;
-  for (i=0;i<Connections[cnum].uid_cache.entries;i++)
-    if (Connections[cnum].uid_cache.list[i] == vuser->uid) return(True);
-
-  if (!user_ok(vuser->name,snum)) return(False);
-
-  i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE;
-  Connections[cnum].uid_cache.list[i] = vuser->uid;
-
-  if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE)
-    Connections[cnum].uid_cache.entries++;
-
-  return(True);
-}
-
-
-/****************************************************************************
-  become the user of a connection number
-****************************************************************************/
-BOOL become_user(int cnum, int uid)
-{
-  int new_umask;
-  user_struct *vuser;
-  int snum,gid;
-  int ngroups;
-  gid_t *groups;
-
-  if (last_user.cnum == cnum && last_user.uid == uid) {
-    DEBUG(4,("Skipping become_user - already user\n"));
-    return(True);
-  }
-
-  unbecome_user();
-
-  if (!OPEN_CNUM(cnum)) {
-    DEBUG(2,("Connection %d not open\n",cnum));
-    return(False);
-  }
-
-  snum = Connections[cnum].service;
-
-  if (Connections[cnum].force_user || 
-      lp_security() == SEC_SHARE ||
-      !(vuser = get_valid_user_struct(uid)) ||
-      !check_user_ok(cnum,vuser,snum)) {
-    uid = Connections[cnum].uid;
-    gid = Connections[cnum].gid;
-    groups = Connections[cnum].groups;
-    ngroups = Connections[cnum].ngroups;
-  } else {
-    if (!vuser) {
-      DEBUG(2,("Invalid vuid used %d\n",uid));
-      return(False);
-    }
-    uid = vuser->uid;
-    if(!*lp_force_group(snum))
-      gid = vuser->gid;
-    else
-      gid = Connections[cnum].gid;
-    groups = vuser->user_groups;
-    ngroups = vuser->user_ngroups;
-  }
-
-  if (initial_uid == 0)
-    {
-      if (!become_gid(gid)) return(False);
-
-#ifndef NO_SETGROUPS      
-      if (!IS_IPC(cnum)) {
-       /* groups stuff added by ih/wreu */
-       if (ngroups > 0)
-         if (setgroups(ngroups,groups)<0)
-           DEBUG(0,("setgroups call failed!\n"));
-      }
-#endif
-
-      if (!Connections[cnum].admin_user && !become_uid(uid))
-       return(False);
-    }
-
-  new_umask = 0777 & ~CREATE_MODE(cnum);
-  old_umask = umask(new_umask);
-
-  last_user.cnum = cnum;
-  last_user.uid = uid;
-  
-  DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n",
-          getuid(),geteuid(),getgid(),getegid(),new_umask));
-  
-  return(True);
-}
-
-/****************************************************************************
-  unbecome the user of a connection number
-****************************************************************************/
-BOOL unbecome_user(void )
-{
-  if (last_user.cnum == -1)
-    return(False);
-
-  ChDir(OriginalDir);
-
-  umask(old_umask);
-
-  if (initial_uid == 0)
-    {
-#ifdef USE_SETRES
-      setresuid(-1,getuid(),-1);
-      setresgid(-1,getgid(),-1);
-#else
-      if (seteuid(initial_uid) != 0) 
-       setuid(initial_uid);
-      setgid(initial_gid);
-#endif
-    }
-#ifdef NO_EID
-  if (initial_uid == 0)
-    DEBUG(2,("Running with no EID\n"));
-  initial_uid = getuid();
-  initial_gid = getgid();
-#else
-  if (geteuid() != initial_uid)
-    {
-      DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
-      initial_uid = geteuid();
-    }
-  if (getegid() != initial_gid)
-    {
-      DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
-      initial_gid = getegid();
-    }
-#endif
-  
-  if (ChDir(OriginalDir) != 0)
-    DEBUG(0,("%s chdir(%s) failed in unbecome_user\n",
-            timestring(),OriginalDir));  
-
-  DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
-       getuid(),geteuid(),getgid(),getegid()));
-
-  last_user.cnum = -1;
-
-  return(True);
-}
-
 /****************************************************************************
   find a service entry
 ****************************************************************************/
@@ -2222,6 +1693,9 @@ static BOOL open_sockets(BOOL is_daemon,int port)
              signal(SIGPIPE, SIGNAL_CAST sig_pipe);
              signal(SIGCLD, SIGNAL_CAST SIG_DFL);
 #endif
+             /* close the listening socket */
+             close(s);
+
              /* close our standard file descriptors */
              close_low_fds();
   
@@ -2299,6 +1773,8 @@ BOOL reload_services(BOOL test)
 
   reopen_logs();
 
+  load_interfaces();
+
   {
     extern int Client;
     if (Client != -1) {      
@@ -2633,7 +2109,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
 
   if (ChDir(pcon->connectpath) != 0)
     {
-      DEBUG(0,("Can't change directory to %s\n",pcon->connectpath));
+      DEBUG(0,("Can't change directory to %s (%s)\n",
+              pcon->connectpath,strerror(errno)));
       pcon->open = False;
       unbecome_user();
       if (!IS_IPC(cnum)) {
@@ -2694,6 +2171,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
 int find_free_file(void )
 {
   int i;
+  /* we start at 1 here for an obscure reason I can't now remember,
+     but I think is important :-) */
   for (i=1;i<MAX_OPEN_FILES;i++)
     if (!Files[i].open)
       return(i);
@@ -2864,6 +2343,7 @@ int reply_nt1(char *outbuf)
   int capabilities=0x300; /* has dual names + lock_and_read */
   int secword=0;
   BOOL doencrypt = SMBENCRYPT();
+  time_t t = time(NULL);
 
   if (lp_security()>=SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
@@ -2898,8 +2378,8 @@ int reply_nt1(char *outbuf)
   SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */
   SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */
   SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
-  put_long_date(outbuf+smb_vwv11+1,time(NULL));
-  SSVALS(outbuf,smb_vwv15+1,TimeDiff(time(NULL))/60);
+  put_long_date(outbuf+smb_vwv11+1,t);
+  SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
 
   return (smb_len(outbuf)+4);
 }
@@ -3884,7 +3364,7 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
 /****************************************************************************
   process commands from the client
 ****************************************************************************/
-void process(void )
+static void process(void)
 {
   static int trans_num = 0;
   int nread;
@@ -3908,12 +3388,10 @@ void process(void )
     ip = *interpret_addr2("localhost");
     if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1");
     *OutBuffer = 0;
-    send_one_packet(OutBuffer,1,ip,137,SOCK_DGRAM);
+    send_one_packet(OutBuffer,1,ip,NMB_PORT,SOCK_DGRAM);
   }
 #endif    
 
-  last_user.cnum = -1;
-  
   while (True)
     {
       int32 len;      
@@ -3960,13 +3438,34 @@ void process(void )
          extern int keepalive;
 
          /* check for socket failure */
-         if (errno == EBADF) {
-           DEBUG(3,("%s Bad file descriptor - exiting\n",timestring()));
+         if (errno) {
+           DEBUG(3,("receive_smb error (%s) exiting\n",strerror(errno)));
            return;
          }
 
          t = time(NULL);
 
+         {
+           /* the following bit of code was added to combat smbd
+               looping chewing lots of CPU time. It should never
+               actually be needed, but it seems that some systems
+               don't set error correctly, which is used to distinguish
+               a select() timeout from a read error 
+              
+              we exit if receive_smb() returns false 3 times in one second. 
+              */
+           static int error_count=0;
+           static time_t error_time=0;
+           if (error_count==0) {
+             error_time = t;
+           } else if (error_time != t) {
+             error_count = 0;
+           } else if (error_count++ > 2) {
+             exit_server("looping in process()\n");
+           }
+         }
+
+
          /* become root again if waiting */
          unbecome_user();
 
@@ -3989,10 +3488,15 @@ void process(void )
          }
 
          if (keepalive && (counter-last_keepalive)>keepalive) {
+           extern int password_client;
            if (!send_keepalive(Client)) {
              DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
              return;
-           }
+           }       
+           /* also send a keepalive to the password server if its still
+              connected */
+           if (password_client != -1)
+             send_keepalive(password_client);
            last_keepalive = counter;
          }
 
@@ -4064,7 +3568,7 @@ void process(void )
 static void init_structs(void )
 {
   int i;
-  get_myname(myhostname,&myip);
+  get_myname(myhostname,NULL);
 
   for (i=0;i<MAX_CONNECTIONS;i++)
     {
@@ -4090,7 +3594,7 @@ static void init_structs(void )
 /****************************************************************************
 usage on the program
 ****************************************************************************/
-void usage(char *pname)
+static void usage(char *pname)
 {
   DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
 
@@ -4110,12 +3614,12 @@ void usage(char *pname)
 /****************************************************************************
   main program
 ****************************************************************************/
-int main(int argc,char *argv[])
+ int main(int argc,char *argv[])
 {
   extern BOOL append_log;
   /* shall I run as a daemon */
   BOOL is_daemon = False;
-  int port = 139;
+  int port = SMB_PORT;
   int opt;
   extern char *optarg;
 
@@ -4152,22 +3656,7 @@ int main(int argc,char *argv[])
 
   umask(0777 & ~DEF_CREATE_MASK);
 
-  initial_uid = geteuid();
-  initial_gid = getegid();
-
-  if (initial_gid != 0 && initial_uid == 0)
-    {
-#ifdef HPUX
-      setresgid(0,0,0);
-#else
-      setgid(0);
-      setegid(0);
-#endif
-    }
-
-  initial_uid = geteuid();
-  initial_gid = getegid();
-
+  init_uid();
 
   /* this is for people who can't start the program correctly */
   while (argc > 1 && (*argv[1] != '-'))
@@ -4229,8 +3718,6 @@ int main(int argc,char *argv[])
   DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION));
   DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n"));
 
-  GetWd(OriginalDir);
-
 #ifndef NO_GETRLIMIT
 #ifdef RLIMIT_NOFILE
   {
@@ -4277,22 +3764,23 @@ int main(int argc,char *argv[])
       become_daemon();
     }
 
-  if (open_sockets(is_daemon,port))
-    {      
-      /* possibly reload the services file. */
-      reload_services(True);
+  if (!open_sockets(is_daemon,port))
+    exit(1);
 
-      maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
+  /* possibly reload the services file. */
+  reload_services(True);
 
-      if (*lp_rootdir())
-       {
-         if (sys_chroot(lp_rootdir()) == 0)
-           DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
-       }
+  maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
 
-      process();
-      close_sockets();
+  if (*lp_rootdir())
+    {
+      if (sys_chroot(lp_rootdir()) == 0)
+       DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
     }
+
+  process();
+  close_sockets();
+
   exit_server("normal exit");
   return(0);
 }