locking.c: Added lock type to is_locked() and do_lock()
[ira/wip.git] / source / smbd / server.c
index f51342d0e512daa6144ab92f22bd2b8700d54fb5..62ee75db0a57dafe07b2d2245674aa6594ce82d2 100644 (file)
@@ -25,7 +25,8 @@
 pstring servicesf = CONFIGFILE;
 extern pstring debugf;
 extern pstring sesssetup_user;
-extern fstring myworkgroup;
+extern fstring global_myworkgroup;
+extern pstring global_myname;
 
 char *InBuffer = NULL;
 char *OutBuffer = NULL;
@@ -49,6 +50,7 @@ extern BOOL use_mangled_map;
 extern BOOL short_case_preserve;
 extern BOOL case_mangle;
 time_t smb_last_time=(time_t)0;
+extern BOOL global_machine_pasword_needs_changing;
 
 extern int smb_read_error;
 
@@ -58,8 +60,14 @@ extern pstring user_socket_options;
 extern int dcelogin_atmost_once;
 #endif /* DFS_AUTH */
 
+/*
+ * This is set on startup - it defines the SID for this
+ * machine.
+ */
+extern DOM_SID global_machine_sid;
+
 connection_struct Connections[MAX_CONNECTIONS];
-files_struct Files[MAX_OPEN_FILES];
+files_struct Files[MAX_FNUMS];
 
 /*
  * Indirection for file fd's. Needed as POSIX locking
@@ -101,7 +109,7 @@ extern fstring remote_machine;
 extern pstring OriginalDir;
 
 /* these can be set by some functions to override the error codes */
-int unix_ERR_class=SUCCESS;
+int unix_ERR_class=SMB_SUCCESS;
 int unix_ERR_code=0;
 
 
@@ -426,8 +434,8 @@ static BOOL mangled_equal(char *name1, char *name2)
   if (is_8_3(name2, True))
     return(False);
 
-  strcpy(tmpname,name2);
-  mangle_name_83(tmpname);
+  pstrcpy(tmpname,name2);
+  mangle_name_83(tmpname,sizeof(tmpname));
 
   return(strequal(name1,tmpname));
 }
@@ -452,7 +460,7 @@ static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
     path = ".";
 
   if (docache && (dname = DirCacheCheck(path,name,SNUM(cnum)))) {
-    strcpy(name, dname);       
+    pstrcpy(name, dname);      
     return(True);
   }      
 
@@ -464,7 +472,7 @@ static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
    * (JRA).
    */
   if (mangled)
-    mangled = !check_mangled_stack(name);
+    mangled = !check_mangled_cache( name );
 
   /* open the directory */
   if (!(cur_dir = OpenDir(cnum, path, True))) 
@@ -488,7 +496,7 @@ static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
        {
          /* we've found the file, change it's name and return */
          if (docache) DirCacheAdd(path,name,dname,SNUM(cnum));
-         strcpy(name, dname);
+         pstrcpy(name, dname);
          CloseDir(cur_dir);
          return(True);
        }
@@ -546,9 +554,9 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_pa
   if(saved_last_component) {
     end = strrchr(name, '/');
     if(end)
-      strcpy(saved_last_component, end + 1);
+      pstrcpy(saved_last_component, end + 1);
     else
-      strcpy(saved_last_component, name);
+      pstrcpy(saved_last_component, name);
   }
 
   if (!case_sensitive && 
@@ -562,11 +570,11 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_pa
        {
          char *s;
          fstring name2;
-         sprintf(name2,"%.6s.XXXXXX",remote_machine);
+         slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine);
          /* sanitise the name */
          for (s=name2 ; *s ; s++)
            if (!issafe(*s)) *s = '_';
-         strcpy(name,(char *)mktemp(name2));     
+         pstrcpy(name,(char *)mktemp(name2));    
        }      
       return(True);
     }
@@ -603,7 +611,7 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_pa
       if (end)         *end = 0;
 
       if(saved_last_component != 0)
-        strcpy(saved_last_component, end ? end + 1 : start);
+        pstrcpy(saved_last_component, end ? end + 1 : start);
 
       /* check if the name exists up to this point */
       if (sys_stat(name, &st) == 0) 
@@ -659,7 +667,7 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_pa
              /* check on the mangled stack to see if we can recover the 
                 base of the filename */
              if (is_mangled(start))
-               check_mangled_stack(start);
+               check_mangled_cache( start );
 
              DEBUG(5,("New file %s\n",start));
              return(True); 
@@ -668,14 +676,14 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_pa
          /* restore the rest of the string */
          if (end) 
            {
-             strcpy(start+strlen(start)+1,rest);
+             pstrcpy(start+strlen(start)+1,rest);
              end = start + strlen(start);
            }
        }
 
       /* add to the dirpath that we have resolved so far */
-      if (*dirpath) strcat(dirpath,"/");
-      strcat(dirpath,start);
+      if (*dirpath) pstrcat(dirpath,"/");
+      pstrcat(dirpath,start);
 
       /* restore the / that we wiped out earlier */
       if (end) *end = '/';
@@ -753,8 +761,8 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize)
       pstring syscmd;
       pstring outfile;
          
-      sprintf(outfile,"%s/dfree.smb.%d",tmpdir(),(int)getpid());
-      sprintf(syscmd,"%s %s",df_command,path);
+      slprintf(outfile,sizeof(outfile)-1, "%s/dfree.smb.%d",tmpdir(),(int)getpid());
+      slprintf(syscmd,sizeof(syscmd)-1,"%s %s",df_command,path);
       standard_sub_basic(syscmd);
 
       ret = smbrun(syscmd,outfile,False);
@@ -989,7 +997,7 @@ static int fd_attempt_open(char *fname, int flags, int mode)
   if((fd == -1) && (errno == ENOENT) &&
      (strchr(fname,'.')==NULL))
     {
-      strcat(fname,".");
+      pstrcat(fname,".");
       fd = sys_open(fname,flags,mode);
     }
 
@@ -1029,6 +1037,47 @@ static int fd_attempt_open(char *fname, int flags, int mode)
   return fd;
 }
 
+/****************************************************************************
+Cache a uid_t currently with this file open. This is an optimization only
+used when multiple sessionsetup's have been done to one smbd.
+****************************************************************************/
+static void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u)
+{
+  if(fd_ptr->uid_cache_count >= sizeof(fd_ptr->uid_users_cache)/sizeof(uid_t))
+    return;
+  fd_ptr->uid_users_cache[fd_ptr->uid_cache_count++] = u;
+}
+
+/****************************************************************************
+Remove a uid_t that currently has this file open. This is an optimization only
+used when multiple sessionsetup's have been done to one smbd.
+****************************************************************************/
+static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u)
+{
+  int i;
+  for(i = 0; i < fd_ptr->uid_cache_count; i++)
+    if(fd_ptr->uid_users_cache[i] == u) {
+      if(i < (fd_ptr->uid_cache_count-1))
+        memmove((char *)&fd_ptr->uid_users_cache[i], (char *)&fd_ptr->uid_users_cache[i+1],
+               sizeof(uid_t)*(fd_ptr->uid_cache_count-1-i) );
+      fd_ptr->uid_cache_count--;
+    }
+  return;
+}
+
+/****************************************************************************
+Check if a uid_t that currently has this file open is present. This is an
+optimization only used when multiple sessionsetup's have been done to one smbd.
+****************************************************************************/
+static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u)
+{
+  int i;
+  for(i = 0; i < fd_ptr->uid_cache_count; i++)
+    if(fd_ptr->uid_users_cache[i] == u)
+      return True;
+  return False;
+}
+
 /****************************************************************************
 fd support routines - attempt to find an already open file by dev
 and inode - increments the ref_count of the returned file_fd_struct *.
@@ -1060,8 +1109,9 @@ static file_fd_struct *fd_get_already_open(struct stat *sbuf)
 fd support routines - attempt to find a empty slot in the FileFd array.
 Increments the ref_count of the returned entry.
 ****************************************************************************/
-static file_fd_struct *fd_get_new()
+static file_fd_struct *fd_get_new(void)
 {
+  extern struct current_user current_user;
   int i;
   file_fd_struct *fd_ptr;
 
@@ -1074,9 +1124,11 @@ static file_fd_struct *fd_get_new()
       fd_ptr->fd_readonly = -1;
       fd_ptr->fd_writeonly = -1;
       fd_ptr->real_open_flags = -1;
+      fd_ptr->uid_cache_count = 0;
+      fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
       fd_ptr->ref_count++;
       /* Increment max used counter if neccessary, cuts down
-        on search time when re-using */
+         on search time when re-using */
       if(i > max_file_fd_used)
         max_file_fd_used = i;
       DEBUG(3,("Allocated new file_fd_struct %d, dev = %x, inode = %x\n",
@@ -1084,8 +1136,7 @@ static file_fd_struct *fd_get_new()
       return fd_ptr;
     }
   }
-  DEBUG(1,("ERROR! Out of file_fd structures - perhaps increase MAX_OPEN_FILES?\
-n"));
+  DEBUG(1,("ERROR! Out of file_fd structures - perhaps increase MAX_OPEN_FILES?\n"));
   return 0;
 }
 
@@ -1115,31 +1166,105 @@ Decrements the ref_count and returns it.
 ****************************************************************************/
 static int fd_attempt_close(file_fd_struct *fd_ptr)
 {
+  extern struct current_user current_user;
+
   DEBUG(3,("fd_attempt_close on file_fd_struct %d, fd = %d, dev = %x, inode = %x, open_flags = %d, ref_count = %d.\n",
-          fd_ptr - &FileFd[0],
-          fd_ptr->fd, fd_ptr->dev, fd_ptr->inode,
-          fd_ptr->real_open_flags,
-          fd_ptr->ref_count));
+          fd_ptr - &FileFd[0],
+          fd_ptr->fd, fd_ptr->dev, fd_ptr->inode,
+          fd_ptr->real_open_flags,
+          fd_ptr->ref_count));
   if(fd_ptr->ref_count > 0) {
     fd_ptr->ref_count--;
     if(fd_ptr->ref_count == 0) {
       if(fd_ptr->fd != -1)
         close(fd_ptr->fd);
       if(fd_ptr->fd_readonly != -1)
-       close(fd_ptr->fd_readonly);
+        close(fd_ptr->fd_readonly);
       if(fd_ptr->fd_writeonly != -1)
-       close(fd_ptr->fd_writeonly);
+        close(fd_ptr->fd_writeonly);
       fd_ptr->fd = -1;
       fd_ptr->fd_readonly = -1;
       fd_ptr->fd_writeonly = -1;
       fd_ptr->real_open_flags = -1;
       fd_ptr->dev = (uint32)-1;
       fd_ptr->inode = (uint32)-1;
-    }
+      fd_ptr->uid_cache_count = 0;
+    } else
+      fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid);
   } 
  return fd_ptr->ref_count;
 }
 
+/****************************************************************************
+fd support routines - check that current user has permissions
+to open this file. Used when uid not found in optimization cache.
+This is really ugly code, as due to POSIX locking braindamage we must
+fork and then attempt to open the file, and return success or failure
+via an exit code.
+****************************************************************************/
+static BOOL check_access_allowed_for_current_user( char *fname, int accmode )
+{
+  pid_t child_pid;
+
+  if((child_pid = fork()) < 0) {
+    DEBUG(0,("check_access_allowed_for_current_user: fork failed.\n"));
+    return False;
+  }
+
+  if(child_pid) {
+    /*
+     * Parent.
+     */
+    pid_t wpid;
+    int status_code;
+    if ((wpid = sys_waitpid(child_pid, &status_code, 0)) < 0) {
+      DEBUG(0,("check_access_allowed_for_current_user: The process is no longer waiting!\n"));
+      return(False);
+    }
+
+    if (child_pid != wpid) {
+      DEBUG(0,("check_access_allowed_for_current_user: We were waiting for the wrong process ID\n"));
+      return(False);
+    }
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+    if (WIFEXITED(status_code) == 0) {
+      DEBUG(0,("check_access_allowed_for_current_user: The process exited while we were waiting\n"));
+      return(False);
+    }
+    if (WEXITSTATUS(status_code) != 0) {
+      DEBUG(9,("check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access denied.\n", status_code));
+      return(False);
+    }
+#else /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+    if(status_code != 0) {
+      DEBUG(9,("check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access denied.\n", status_code));
+      return(False);
+    }
+#endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+
+    /*
+     * Success - the child could open the file.
+     */
+    DEBUG(9,("check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access allowed.\n", status_code));
+    return True;
+  } else {
+    /*
+     * Child.
+     */
+    int fd;
+    DEBUG(9,("check_access_allowed_for_current_user: Child - attempting to open %s with mode %d.\n", fname, accmode ));
+    if((fd = fd_attempt_open( fname, accmode, 0)) < 0) {
+      /* Access denied. */
+      _exit(EACCES);
+    }
+    close(fd);
+    DEBUG(9,("check_access_allowed_for_current_user: Child - returning ok.\n"));
+    _exit(0);
+  }
+
+  return False;
+}
+
 /****************************************************************************
 open a file
 ****************************************************************************/
@@ -1202,7 +1327,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
    * open fd table.
    */
   if(sbuf == 0) {
-    if(stat(fname, &statbuf) < 0) {
+    if(sys_stat(fname, &statbuf) < 0) {
       if(errno != ENOENT) {
         DEBUG(3,("Error doing stat on file %s (%s)\n",
                  fname,strerror(errno)));
@@ -1222,14 +1347,41 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
    * reference count (fd_get_already_open increments the ref_count).
    */
   if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
+    /*
+     * File was already open.
+     */
 
-    /* File was already open. */
+    /* 
+     * Check it wasn't open for exclusive use.
+     */
     if((flags & O_CREAT) && (flags & O_EXCL)) {
       fd_ptr->ref_count--;
       errno = EEXIST;
       return;
     }
 
+    /*
+     * Ensure that the user attempting to open
+     * this file has permissions to do so, if
+     * the user who originally opened the file wasn't
+     * the same as the current user.
+     */
+
+    if(!fd_is_in_uid_cache(fd_ptr, (uid_t)current_user.uid)) {
+      if(!check_access_allowed_for_current_user( fname, accmode )) {
+        /* Error - permission denied. */
+        DEBUG(3,("Permission denied opening file %s (flags=%d, accmode = %d)\n",
+              fname, flags, accmode));
+        /* Ensure the ref_count is decremented. */
+        fd_ptr->ref_count--;
+        fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid);
+        errno = EACCES;
+        return;
+      }
+    }
+
+    fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
+
     /* 
      * If not opened O_RDWR try
      * and do that here - a chmod may have been done
@@ -1249,6 +1401,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
       DEBUG(3,("Error opening (already open for flags=%d) file %s (%s) (flags=%d)\n",
                fd_ptr->real_open_flags, fname,strerror(EACCES),flags));
       check_for_pipe(fname);
+      fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid);
       fd_ptr->ref_count--;
       return;
     }
@@ -1286,7 +1439,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
         fd_ptr->fd = fd_attempt_open(fname, open_flags|O_WRONLY, mode);
         fd_ptr->real_open_flags = O_WRONLY;
       } else {
-       fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDONLY, mode);
+        fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDONLY, mode);
         fd_ptr->real_open_flags = O_RDONLY;
       }
     }
@@ -1312,90 +1465,99 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   }
     
   if (fd_ptr->fd < 0)
-    {
-      DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
-              fname,strerror(errno),flags));
-      /* Ensure the ref_count is decremented. */
-      fd_attempt_close(fd_ptr);
-      check_for_pipe(fname);
-      return;
-    }
+  {
+    DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
+      fname,strerror(errno),flags));
+    /* Ensure the ref_count is decremented. */
+    fd_attempt_close(fd_ptr);
+    check_for_pipe(fname);
+    return;
+  }
 
   if (fd_ptr->fd >= 0)
-    {
-      if(sbuf == 0) {
-        /* Do the fstat */
-        if(fstat(fd_ptr->fd, &statbuf) == -1) {
-          /* Error - backout !! */
-          DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n",
-                   fd_ptr->fd, fname,strerror(errno)));
-          /* Ensure the ref_count is decremented. */
-          fd_attempt_close(fd_ptr);
-          return;
-        }
-        sbuf = &statbuf;
+  {
+    if(sbuf == 0) {
+      /* Do the fstat */
+      if(fstat(fd_ptr->fd, &statbuf) == -1) {
+        /* Error - backout !! */
+        DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n",
+                 fd_ptr->fd, fname,strerror(errno)));
+        /* Ensure the ref_count is decremented. */
+        fd_attempt_close(fd_ptr);
+        return;
       }
-      /* Set the correct entries in fd_ptr. */
-      fd_ptr->dev = (uint32)sbuf->st_dev;
-      fd_ptr->inode = (uint32)sbuf->st_ino;
-
-      fsp->fd_ptr = fd_ptr;
-      Connections[cnum].num_files_open++;
-      fsp->mode = sbuf->st_mode;
-      GetTimeOfDay(&fsp->open_time);
-      fsp->vuid = current_user.vuid;
-      fsp->size = 0;
-      fsp->pos = -1;
-      fsp->open = True;
-      fsp->mmap_ptr = NULL;
-      fsp->mmap_size = 0;
-      fsp->can_lock = True;
-      fsp->can_read = ((flags & O_WRONLY)==0);
-      fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
-      fsp->share_mode = 0;
-      fsp->print_file = Connections[cnum].printer;
-      fsp->modified = False;
-      fsp->granted_oplock = False;
-      fsp->sent_oplock_break = False;
-      fsp->cnum = cnum;
-      string_set(&fsp->name,dos_to_unix(fname,False));
-      fsp->wbmpx_ptr = NULL;      
+      sbuf = &statbuf;
+    }
 
-      /*
-       * If the printer is marked as postscript output a leading
-       * file identifier to ensure the file is treated as a raw
-       * postscript file.
-       * This has a similar effect as CtrlD=0 in WIN.INI file.
-       * tim@fsg.com 09/06/94
-       */
-      if (fsp->print_file && POSTSCRIPT(cnum) && 
-         fsp->can_write) 
-       {
-         DEBUG(3,("Writing postscript line\n"));
-         write_file(fnum,"%!\n",3);
-       }
-      
-      DEBUG(2,("%s %s opened file %s read=%s write=%s (numopen=%d fnum=%d)\n",
-              timestring(),Connections[cnum].user,fname,
-              BOOLSTR(fsp->can_read),BOOLSTR(fsp->can_write),
-              Connections[cnum].num_files_open,fnum));
+    /* Set the correct entries in fd_ptr. */
+    fd_ptr->dev = (uint32)sbuf->st_dev;
+    fd_ptr->inode = (uint32)sbuf->st_ino;
+
+    fsp->fd_ptr = fd_ptr;
+    Connections[cnum].num_files_open++;
+    fsp->mode = sbuf->st_mode;
+    GetTimeOfDay(&fsp->open_time);
+    fsp->vuid = current_user.vuid;
+    fsp->size = 0;
+    fsp->pos = -1;
+    fsp->open = True;
+    fsp->mmap_ptr = NULL;
+    fsp->mmap_size = 0;
+    fsp->can_lock = True;
+    fsp->can_read = ((flags & O_WRONLY)==0);
+    fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
+    fsp->share_mode = 0;
+    fsp->print_file = Connections[cnum].printer;
+    fsp->modified = False;
+    fsp->granted_oplock = False;
+    fsp->sent_oplock_break = False;
+    fsp->is_directory = False;
+    fsp->cnum = cnum;
+    /*
+     * Note that the file name here is the *untranslated* name
+     * ie. it is still in the DOS codepage sent from the client.
+     * All use of this filename will pass though the sys_xxxx
+     * functions which will do the dos_to_unix translation before
+     * mapping into a UNIX filename. JRA.
+     */
+    string_set(&fsp->name,fname);
+    fsp->wbmpx_ptr = NULL;      
 
+    /*
+     * If the printer is marked as postscript output a leading
+     * file identifier to ensure the file is treated as a raw
+     * postscript file.
+     * This has a similar effect as CtrlD=0 in WIN.INI file.
+     * tim@fsg.com 09/06/94
+     */
+    if (fsp->print_file && POSTSCRIPT(cnum) && fsp->can_write) 
+    {
+      DEBUG(3,("Writing postscript line\n"));
+      write_file(fnum,"%!\n",3);
     }
+      
+    DEBUG(2,("%s %s opened file %s read=%s write=%s (numopen=%d fnum=%d)\n",
+          timestring(),
+          *sesssetup_user ? sesssetup_user : Connections[cnum].user,fname,
+          BOOLSTR(fsp->can_read),BOOLSTR(fsp->can_write),
+          Connections[cnum].num_files_open,fnum));
+
+  }
 
 #if USE_MMAP
   /* mmap it if read-only */
   if (!fsp->can_write)
-    {
-      fsp->mmap_size = file_size(fname);
-      fsp->mmap_ptr = (char *)mmap(NULL,fsp->mmap_size,
-                                         PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,0);
+  {
+    fsp->mmap_size = file_size(fname);
+    fsp->mmap_ptr = (char *)mmap(NULL,fsp->mmap_size,
+                                 PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,0);
 
-      if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr)
-       {
-         DEBUG(3,("Failed to mmap() %s - %s\n",fname,strerror(errno)));
-         fsp->mmap_ptr = NULL;
-       }
+    if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr)
+    {
+      DEBUG(3,("Failed to mmap() %s - %s\n",fname,strerror(errno)));
+      fsp->mmap_ptr = NULL;
     }
+  }
 #endif
 }
 
@@ -1439,7 +1601,7 @@ static void check_magic(int fnum,int cnum)
     if (*lp_magicoutput(SNUM(cnum)))
       pstrcpy(magic_output,lp_magicoutput(SNUM(cnum)));
     else
-      sprintf(magic_output,"%s.out",fname);
+      slprintf(magic_output,sizeof(fname)-1, "%s.out",fname);
 
     chmod(fname,0755);
     ret = smbrun(fname,magic_output,False);
@@ -1448,15 +1610,43 @@ static void check_magic(int fnum,int cnum)
   }
 }
 
+/****************************************************************************
+  Common code to close a file or a directory.
+****************************************************************************/
+    
+static void close_filestruct(files_struct *fs_p)
+{   
+  int cnum = fs_p->cnum;
+    
+  fs_p->reserved = False; 
+  fs_p->open = False;
+  fs_p->is_directory = False; 
+    
+  Connections[cnum].num_files_open--;
+  if(fs_p->wbmpx_ptr)
+  {  
+    free((char *)fs_p->wbmpx_ptr);
+    fs_p->wbmpx_ptr = NULL; 
+  }  
+     
+#if USE_MMAP
+  if(fs_p->mmap_ptr) 
+  {
+    munmap(fs_p->mmap_ptr,fs_p->mmap_size);
+    fs_p->mmap_ptr = NULL;
+  }  
+#endif 
+}    
 
 /****************************************************************************
-close a file - possibly invalidating the read prediction
+ Close a file - possibly invalidating the read prediction.
 
-If normal_close is 1 then this came from a normal SMBclose (or equivalent)
-operation otherwise it came as the result of some other operation such as
-the closing of the connection. In the latter case printing and
-magic scripts are not run
+ If normal_close is 1 then this came from a normal SMBclose (or equivalent)
+ operation otherwise it came as the result of some other operation such as
+ the closing of the connection. In the latter case printing and
+ magic scripts are not run.
 ****************************************************************************/
+
 void close_file(int fnum, BOOL normal_close)
 {
   files_struct *fs_p = &Files[fnum];
@@ -1465,28 +1655,12 @@ void close_file(int fnum, BOOL normal_close)
   uint32 inode = fs_p->fd_ptr->inode;
   int token;
 
-  Files[fnum].reserved = False;
+  close_filestruct(fs_p);
 
 #if USE_READ_PREDICTION
   invalidate_read_prediction(fs_p->fd_ptr->fd);
 #endif
 
-  fs_p->open = False;
-  Connections[cnum].num_files_open--;
-  if(fs_p->wbmpx_ptr) 
-  {
-    free((char *)fs_p->wbmpx_ptr);
-    fs_p->wbmpx_ptr = NULL;
-  }
-
-#if USE_MMAP
-  if(fs_p->mmap_ptr) 
-  {
-    munmap(fs_p->mmap_ptr,fs_p->mmap_size);
-    fs_p->mmap_ptr = NULL;
-  }
-#endif
-
   if (lp_share_modes(SNUM(cnum)))
   {
     lock_share_entry( cnum, dev, inode, &token);
@@ -1514,6 +1688,76 @@ void close_file(int fnum, BOOL normal_close)
   DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
           timestring(),Connections[cnum].user,fs_p->name,
           Connections[cnum].num_files_open));
+
+  if (fs_p->name) {
+         string_free(&fs_p->name);
+  }
+
+  /* we will catch bugs faster by zeroing this structure */
+  memset(fs_p, 0, sizeof(*fs_p));
+}
+
+/****************************************************************************
+ Close a directory opened by an NT SMB call. 
+****************************************************************************/
+  
+void close_directory(int fnum)
+{
+  files_struct *fs_p = &Files[fnum];
+
+  /*
+   * Do the code common to files and directories.
+   */
+  close_filestruct(fs_p);
+
+  if (fs_p->name) {
+      string_free(&fs_p->name);
+  }
+
+  /* we will catch bugs faster by zeroing this structure */
+  memset(fs_p, 0, sizeof(*fs_p));
+}
+
+/****************************************************************************
+ Open a directory from an NT SMB call.
+****************************************************************************/
+
+void open_directory(int fnum,int cnum,char *fname, int *action)
+{
+  extern struct current_user current_user;
+  files_struct *fsp = &Files[fnum];
+
+  fsp->fd_ptr = NULL;
+  Connections[cnum].num_files_open++;
+  fsp->mode = 0;
+  GetTimeOfDay(&fsp->open_time);
+  fsp->vuid = current_user.vuid;
+  fsp->size = 0;
+  fsp->pos = -1;
+  fsp->open = True;
+  fsp->mmap_ptr = NULL;
+  fsp->mmap_size = 0;
+  fsp->can_lock = True;
+  fsp->can_read = False;
+  fsp->can_write = False;
+  fsp->share_mode = 0;
+  fsp->print_file = False;
+  fsp->modified = False;
+  fsp->granted_oplock = False;
+  fsp->sent_oplock_break = False;
+  fsp->is_directory = True;
+  fsp->cnum = cnum;
+  /*
+   * Note that the file name here is the *untranslated* name
+   * ie. it is still in the DOS codepage sent from the client.
+   * All use of this filename will pass though the sys_xxxx
+   * functions which will do the dos_to_unix translation before
+   * mapping into a UNIX filename. JRA.
+   */
+  string_set(&fsp->name,fname);
+  fsp->wbmpx_ptr = NULL;
+
+  *action = FILE_WAS_OPENED;
 }
 
 enum {AFAIL,AREAD,AWRITE,AALL};
@@ -1587,7 +1831,7 @@ BOOL check_file_sharing(int cnum,char *fname, BOOL rename_op)
   if(!lp_share_modes(SNUM(cnum)))
     return True;
 
-  if (stat(fname,&sbuf) == -1) return(True);
+  if (sys_stat(fname,&sbuf) == -1) return(True);
 
   dev = (uint32)sbuf.st_dev;
   inode = (uint32)sbuf.st_ino;
@@ -1704,7 +1948,7 @@ static void truncate_unless_locked(int fnum, int cnum, int token,
                                   BOOL *share_locked)
 {
   if (Files[fnum].can_write){
-    if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
+    if (is_locked(fnum,cnum,0x3FFFFFFF,0,F_WRLCK)){
       /* If share modes are in force for this connection we
          have the share entry locked. Unlock it before closing. */
       if (*share_locked && lp_share_modes(SNUM(cnum)))
@@ -1790,7 +2034,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
   {
     unix_ERR_class = ERRDOS;
     /* OS/2 Workplace shell fix may be main code stream in a later release. */ 
-#ifdef OS2_WPS_FIX
+#if 1 /* OS2_WPS_FIX - Recent versions of OS/2 need this. */
     unix_ERR_code = ERRcannotopen;
 #else /* OS2_WPS_FIX */
     unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
@@ -1829,6 +2073,12 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
       flags = O_RDONLY;
       break;
   }
+
+#if defined(O_SYNC)
+  if (share_mode&(1<<14)) {
+         flags2 |= O_SYNC;
+  }
+#endif /* O_SYNC */
   
   if (flags != O_RDONLY && file_existed && 
       (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) 
@@ -1979,9 +2229,9 @@ dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
 
     if (action) 
     {
-      if (file_existed && !(flags2 & O_TRUNC)) *action = 1;
-      if (!file_existed) *action = 2;
-      if (file_existed && (flags2 & O_TRUNC)) *action = 3;
+      if (file_existed && !(flags2 & O_TRUNC)) *action = FILE_WAS_OPENED;
+      if (!file_existed) *action = FILE_WAS_CREATED;
+      if (file_existed && (flags2 & O_TRUNC)) *action = FILE_WAS_OVERWRITTEN;
     }
     /* We must create the share mode entry before truncate as
        truncate can fail due to locking and have to close the
@@ -2058,7 +2308,8 @@ int read_file(int fnum,char *data,uint32 pos,int n)
 #if USE_MMAP
   if (Files[fnum].mmap_ptr)
     {
-      int num = MIN(n,(int)(Files[fnum].mmap_size-pos));
+      int num = (Files[fnum].mmap_size > pos) ? (Files[fnum].mmap_size - pos) : -1;
+      num = MIN(n,num);
       if (num > 0)
        {
          memcpy(data,Files[fnum].mmap_ptr+pos,num);
@@ -2172,16 +2423,28 @@ int find_service(char *service)
    if (iService < 0)
    {
       char *phome_dir = get_home_dir(service);
+
+      if(!phome_dir)
+      {
+        /*
+         * Try mapping the servicename, it may
+         * be a Windows to unix mapped user name.
+         */
+        if(map_username(service))
+          phome_dir = get_home_dir(service);
+      }
+
       DEBUG(3,("checking for home directory %s gave %s\n",service,
-           phome_dir?phome_dir:"(NULL)"));
+            phome_dir?phome_dir:"(NULL)"));
+
       if (phome_dir)
       {   
-        int iHomeService;
-        if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0)
-        {
-           lp_add_home(service,iHomeService,phome_dir);
-           iService = lp_servicenumber(service);
-        }
+        int iHomeService;
+        if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0)
+        {
+          lp_add_home(service,iHomeService,phome_dir);
+          iService = lp_servicenumber(service);
+        }
       }
    }
 
@@ -2212,26 +2475,36 @@ int find_service(char *service)
 
    /* just possibly it's a default service? */
    if (iService < 0) 
+   {
+     char *pdefservice = lp_defaultservice();
+     if (pdefservice && *pdefservice && !strequal(pdefservice,service))
      {
-       char *defservice = lp_defaultservice();
-       if (defservice && *defservice && !strequal(defservice,service)) {
-        iService = find_service(defservice);
-        if (iService >= 0) {
-          string_sub(service,"_","/");
-          iService = lp_add_service(service,iService);
-        }
+       /*
+        * We need to do a local copy here as lp_defaultservice() 
+        * returns one of the rotating lp_string buffers that
+        * could get overwritten by the recursive find_service() call
+        * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
+        */
+       pstring defservice;
+       pstrcpy(defservice, pdefservice);
+       iService = find_service(defservice);
+       if (iService >= 0)
+       {
+         string_sub(service,"_","/");
+         iService = lp_add_service(service,iService);
        }
      }
+   }
 
    if (iService >= 0)
-      if (!VALID_SNUM(iService))
-      {
-         DEBUG(0,("Invalid snum %d for %s\n",iService,service));
-        iService = -1;
-      }
+     if (!VALID_SNUM(iService))
+     {
+       DEBUG(0,("Invalid snum %d for %s\n",iService,service));
+       iService = -1;
+     }
 
    if (iService < 0)
-      DEBUG(3,("find_service() failed to find service %s\n", service));
+     DEBUG(3,("find_service() failed to find service %s\n", service));
 
    return (iService);
 }
@@ -2294,11 +2567,11 @@ int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int
   int ecode=def_code;
   int i=0;
 
-  if (unix_ERR_class != SUCCESS)
+  if (unix_ERR_class != SMB_SUCCESS)
     {
       eclass = unix_ERR_class;
       ecode = unix_ERR_code;
-      unix_ERR_class = SUCCESS;
+      unix_ERR_class = SMB_SUCCESS;
       unix_ERR_code = 0;
     }
   else
@@ -2325,13 +2598,21 @@ int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int
 int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line)
 {
   int outsize = set_message(outbuf,0,0,True);
-  int cmd;
-  cmd = CVAL(inbuf,smb_com);
-  
-  CVAL(outbuf,smb_rcls) = error_class;
-  SSVAL(outbuf,smb_err,error_code);  
-  
-  DEBUG(3,("%s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n",
+  int cmd = CVAL(inbuf,smb_com);
+  int flgs2 = SVAL(outbuf,smb_flg2); 
+
+  if ((flgs2 & FLAGS2_32_BIT_ERROR_CODES) == FLAGS2_32_BIT_ERROR_CODES)
+  {
+    SIVAL(outbuf,smb_rcls,error_code);
+    
+    DEBUG(3,("%s 32 bit error packet at line %d cmd=%d (%s) eclass=%08x [%s]\n",
+           timestring(), line, cmd, smb_fn_name(cmd), error_code, smb_errstr(outbuf)));
+  }
+  else
+  {
+    CVAL(outbuf,smb_rcls) = error_class;
+    SSVAL(outbuf,smb_err,error_code);  
+    DEBUG(3,("%s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n",
           timestring(),
           line,
           (int)CVAL(inbuf,smb_com),
@@ -2339,6 +2620,8 @@ int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int
           error_class,
           error_code));
 
+  }
+  
   if (errno != 0)
     DEBUG(3,("error string = %s\n",strerror(errno)));
   
@@ -2350,7 +2633,7 @@ int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int
 /****************************************************************************
 this prevents zombie child processes
 ****************************************************************************/
-static int sig_cld()
+static int sig_cld(void)
 {
   static int depth = 0;
   if (depth != 0)
@@ -2395,7 +2678,7 @@ static int sig_cld()
 /****************************************************************************
   this is called when the client exits abruptly
   **************************************************************************/
-static int sig_pipe()
+static int sig_pipe(void)
 {
        struct cli_state *cli;
        BlockSignals(True,SIGPIPE);
@@ -2578,6 +2861,20 @@ max can be %d\n", num_interfaces, FD_SETSIZE));
           return True; 
         }
         close(Client); /* The parent doesn't need this socket */
+
+        /*
+         * Force parent to check log size after spawning child.
+         * Fix from klausr@ITAP.Physik.Uni-Stuttgart.De.
+         * The parent smbd will log to logserver.smb. 
+         * It writes only two messages for each child
+         * started/finished. But each child writes, say, 50 messages also in
+         * logserver.smb, begining with the debug_count of the parent, before the
+         * child opens its own log file logserver.client. In a worst case
+         * scenario the size of logserver.smb would be checked after about
+         * 50*50=2500 messages (ca. 100kb).
+         */
+        force_check_log_size();
+
 #endif /* NO_FORK_DEBUG */
       } /* end for num */
     } /* end while 1 */
@@ -2610,6 +2907,10 @@ max can be %d\n", num_interfaces, FD_SETSIZE));
 static void process_smb(char *inbuf, char *outbuf)
 {
   extern int Client;
+#ifdef USE_SSL
+  extern BOOL sslEnabled;     /* don't use function for performance reasons */
+  static int sslConnected = 0;
+#endif /* USE_SSL */
   static int trans_num;
   int msg_type = CVAL(inbuf,0);
   int32 len = smb_len(inbuf);
@@ -2634,6 +2935,18 @@ static void process_smb(char *inbuf, char *outbuf)
   DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
   DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
 
+#ifdef USE_SSL
+    if(sslEnabled && !sslConnected){
+        sslConnected = sslutil_negotiate_ssl(Client, msg_type);
+        if(sslConnected < 0){   /* an error occured */
+            exit_server("SSL negotiation failed");
+        }else if(sslConnected){
+            trans_num++;
+            return;
+        }
+    }
+#endif  /* USE_SSL */
+
 #ifdef WITH_VTP
   if(trans_num == 1 && VT_Check(inbuf)) 
   {
@@ -2668,7 +2981,7 @@ static void process_smb(char *inbuf, char *outbuf)
 /****************************************************************************
   open the oplock IPC socket communication
 ****************************************************************************/
-static BOOL open_oplock_ipc()
+static BOOL open_oplock_ipc(void)
 {
   struct sockaddr_in sock_name;
   int len = sizeof(sock_name);
@@ -2828,6 +3141,7 @@ pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
 ****************************************************************************/
 BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
 {
+  extern struct current_user current_user;
   extern int Client;
   char *inbuf = NULL;
   char *outbuf = NULL;
@@ -2835,6 +3149,9 @@ BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
   int fnum;
   time_t start_time;
   BOOL shutdown_server = False;
+  int saved_cnum;
+  int saved_vuid;
+  pstring saved_dir; 
 
   DEBUG(3,("%s oplock_break: called for dev = %x, inode = %x. Current \
 global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
@@ -2842,7 +3159,7 @@ global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
   /* We need to search the file open table for the
      entry containing this dev and inode, and ensure
      we have an oplock on it. */
-  for( fnum = 0; fnum < MAX_OPEN_FILES; fnum++)
+  for( fnum = 0; fnum < MAX_FNUMS; fnum++)
   {
     if(OPEN_FNUM(fnum))
     {
@@ -2940,6 +3257,15 @@ allowing break to succeed.\n", timestring(), dev, inode, fnum));
 
   start_time = time(NULL);
 
+  /*
+   * Save the information we need to re-become the
+   * user, then unbecome the user whilst we're doing this.
+   */
+  saved_cnum = fsp->cnum;
+  saved_vuid = current_user.vuid;
+  GetWd(saved_dir);
+  unbecome_user();
+
   while(OPEN_FNUM(fnum) && fsp->granted_oplock)
   {
     if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False)
@@ -2991,6 +3317,21 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
     }
   }
 
+  /*
+   * Go back to being the user who requested the oplock
+   * break.
+   */
+  if(!become_user(&Connections[saved_cnum], saved_cnum, saved_vuid))
+  {
+    DEBUG(0,("%s oplock_break: unable to re-become user ! Shutting down server\n",
+          timestring()));
+    close_sockets();
+    close(oplock_sock);
+    exit_server("unable to re-become user");
+  }
+  /* Including the directory. */
+  ChDir(saved_dir);
+
   /* Free the buffers we've been using to recurse. */
   free(inbuf);
   free(outbuf);
@@ -3240,15 +3581,15 @@ BOOL reload_services(BOOL test)
   BOOL ret;
 
   if (lp_loaded())
+  {
+    pstring fname;
+    pstrcpy(fname,lp_configfile());
+    if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
     {
-      pstring fname;
-      pstrcpy(fname,lp_configfile());
-      if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
-       {
-         pstrcpy(servicesf,fname);
-         test = False;
-       }
+      pstrcpy(servicesf,fname);
+      test = False;
     }
+  }
 
   reopen_logs();
 
@@ -3275,7 +3616,7 @@ BOOL reload_services(BOOL test)
     }
   }
 
-  reset_mangled_stack( lp_mangledstack() );
+  reset_mangled_cache();
 
   /* this forces service parameters to be flushed */
   become_service(-1,True);
@@ -3288,11 +3629,20 @@ BOOL reload_services(BOOL test)
 /****************************************************************************
 this prevents zombie child processes
 ****************************************************************************/
-static int sig_hup()
+static BOOL reload_after_sighup = False;
+
+static int sig_hup(void)
 {
   BlockSignals(True,SIGHUP);
   DEBUG(0,("Got SIGHUP\n"));
-  reload_services(False);
+
+  /*
+   * Fix from <branko.cibej@hermes.si> here.
+   * We used to reload in the signal handler - this
+   * is a *BIG* no-no.
+   */
+
+  reload_after_sighup = True;
 #ifndef DONT_REINSTALL_SIG
   signal(SIGHUP,SIGNAL_CAST sig_hup);
 #endif
@@ -3318,13 +3668,14 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   snum = find_service(service);
   if (snum < 0)
     {
+      extern int Client;
       if (strequal(service,"IPC$"))
        {         
          DEBUG(3,("%s refusing IPC connection\n",timestring()));
          return(-3);
        }
 
-      DEBUG(0,("%s couldn't find service %s\n",timestring(),service));      
+      DEBUG(0,("%s %s (%s) couldn't find service %s\n",timestring(),remote_machine,client_addr(Client),service));      
       return(-2);
     }
 
@@ -3333,11 +3684,25 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
       if (*user && Get_Pwnam(user,True))
        return(make_connection(user,user,password,pwlen,dev,vuid));
 
-      if (validated_username(vuid))
-       {
-         strcpy(user,validated_username(vuid));
-         return(make_connection(user,user,password,pwlen,dev,vuid));
-       }
+      if(lp_security() != SEC_SHARE)
+      {
+        if (validated_username(vuid))
+        {
+          pstrcpy(user,validated_username(vuid));
+          return(make_connection(user,user,password,pwlen,dev,vuid));
+        }
+      }
+      else
+      {
+        /*
+         * Security = share. Try with sesssetup_user as the username.
+         */
+        if(*sesssetup_user)
+        {
+          pstrcpy(user,sesssetup_user);
+          return(make_connection(user,user,password,pwlen,dev,vuid));
+        }
+      }
     }
 
   if (!lp_snum_ok(snum) || !check_access(snum)) {    
@@ -3346,14 +3711,14 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
 
   /* you can only connect to the IPC$ service as an ipc device */
   if (strequal(service,"IPC$"))
-    strcpy(dev,"IPC");
+    pstrcpy(dev,"IPC");
 
   if (*dev == '?' || !*dev)
     {
       if (lp_print_ok(snum))
-       strcpy(dev,"LPT1:");
+       pstrcpy(dev,"LPT1:");
       else
-       strcpy(dev,"A:");
+       pstrcpy(dev,"A:");
     }
 
   /* if the request is as a printer and you can't print then refuse */
@@ -3651,14 +4016,14 @@ int find_free_file(void )
           increases the chance that the errant client will get an error rather
           than causing corruption */
        if (first_file == 0) {
-               first_file = (getpid() ^ (int)time(NULL)) % MAX_OPEN_FILES;
+               first_file = (getpid() ^ (int)time(NULL)) % MAX_FNUMS;
                if (first_file == 0) first_file = 1;
        }
 
-       if (first_file >= MAX_OPEN_FILES)
+       if (first_file >= MAX_FNUMS)
                first_file = 1;
 
-       for (i=first_file;i<MAX_OPEN_FILES;i++)
+       for (i=first_file;i<MAX_FNUMS;i++)
                if (!Files[i].open && !Files[i].reserved) {
                        memset(&Files[i], 0, sizeof(Files[i]));
                        first_file = i+1;
@@ -3684,7 +4049,7 @@ int find_free_file(void )
          * files batch oplocked for quite a long time
          * after they have finished with them.
          */
-        for (i=first_file;i<MAX_OPEN_FILES;i++) {
+        for (i=first_file;i<MAX_FNUMS;i++) {
           if(attempt_close_oplocked_file( &Files[i])) {
             memset(&Files[i], 0, sizeof(Files[i]));
             first_file = i+1;
@@ -3693,7 +4058,7 @@ int find_free_file(void )
           }
         }
 
-        for (i=1;i<MAX_OPEN_FILES;i++) {
+        for (i=1;i<MAX_FNUMS;i++) {
           if(attempt_close_oplocked_file( &Files[i])) {
             memset(&Files[i], 0, sizeof(Files[i]));
             first_file = i+1;
@@ -3870,7 +4235,12 @@ reply for the nt protocol
 int reply_nt1(char *outbuf)
 {
   /* dual names + lock_and_read + nt SMBs + remote API calls */
-  int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_RPC_REMOTE_APIS;
+  int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_RPC_REMOTE_APIS
+#ifdef HAVE_NT_SMBS
+                     |CAP_NT_SMBS
+#endif /* HAVE_NT_SMBS */
+                      ;
+
 /*
   other valid capabilities which we may support at some time...
                      CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
@@ -3914,10 +4284,10 @@ int reply_nt1(char *outbuf)
   /* decide where (if) to put the encryption challenge, and
      follow it with the OEM'd domain name
    */
-  data_len = crypt_len + strlen(myworkgroup) + 1;
+  data_len = crypt_len + strlen(global_myworkgroup) + 1;
 
   set_message(outbuf,17,data_len,True);
-  strcpy(smb_buf(outbuf)+crypt_len, myworkgroup);
+  pstrcpy(smb_buf(outbuf)+crypt_len, global_myworkgroup);
 
   CVAL(outbuf,smb_vwv1) = secword;
   SSVALS(outbuf,smb_vwv16+1,crypt_len);
@@ -4021,7 +4391,7 @@ struct {
 /****************************************************************************
   reply to a negprot
 ****************************************************************************/
-static int reply_negprot(char *inbuf,char *outbuf)
+static int reply_negprot(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
   int outsize = set_message(outbuf,1,0,True);
   int Index=0;
@@ -4086,7 +4456,7 @@ static int reply_negprot(char *inbuf,char *outbuf)
     
   /* a special case to stop password server loops */
   if (Index == 1 && strequal(remote_machine,myhostname) && 
-      lp_security()==SEC_SERVER)
+      (lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN))
     exit_server("Password server loop!");
   
   /* Check for protocols, most desirable first */
@@ -4131,9 +4501,12 @@ close all open files for a connection
 static void close_open_files(int cnum)
 {
   int i;
-  for (i=0;i<MAX_OPEN_FILES;i++)
+  for (i=0;i<MAX_FNUMS;i++)
     if( Files[i].cnum == cnum && Files[i].open) {
-      close_file(i,False);
+      if(Files[i].is_directory)
+        close_directory(i); 
+      else                  
+        close_file(i,False); 
     }
 }
 
@@ -4174,7 +4547,7 @@ void close_cnum(int cnum, uint16 vuid)
   if (*lp_postexec(SNUM(cnum)) && become_user(&Connections[cnum], cnum,vuid))
     {
       pstring cmd;
-      strcpy(cmd,lp_postexec(SNUM(cnum)));
+      pstrcpy(cmd,lp_postexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
       smbrun(cmd,NULL,False);
       unbecome_user();
@@ -4185,7 +4558,7 @@ void close_cnum(int cnum, uint16 vuid)
   if (*lp_rootpostexec(SNUM(cnum)))
     {
       pstring cmd;
-      strcpy(cmd,lp_rootpostexec(SNUM(cnum)));
+      pstrcpy(cmd,lp_rootpostexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
       smbrun(cmd,NULL,False);
     }
@@ -4223,7 +4596,7 @@ static BOOL dump_core(void)
   pstring dname;
   pstrcpy(dname,debugf);
   if ((p=strrchr(dname,'/'))) *p=0;
-  strcat(dname,"/corefiles");
+  pstrcat(dname,"/corefiles");
   mkdir(dname,0700);
   sys_chown(dname,getuid(),getgid());
   chmod(dname,0700);
@@ -4309,8 +4682,8 @@ void standard_sub(int cnum,char *str)
         case 'u' : string_sub(p,"%u",Connections[cnum].user); break;
        /* 
          * Patch from jkf@soton.ac.uk
-        * Left the %N (NIS server name) in standard_sub_basic as it 
-        * is a feature for logon servers, hence uses the username. 
+         * Left the %N (NIS server name) in standard_sub_basic as it
+         * is a feature for logon servers, hence uses the username.
         * The %p (NIS server path) code is here as it is used
         * instead of the default "path =" string in [homes] and so
         * needs the service name, not the username. 
@@ -4347,7 +4720,7 @@ struct smb_message_struct
 {
   int code;
   char *name;
-  int (*fn)();
+  int (*fn)(char *, char *, int, int);
   int flags;
 #if PROFILING
   unsigned long time;
@@ -4434,9 +4807,17 @@ struct smb_message_struct
    /* LANMAN2.0 PROTOCOL FOLLOWS */
    {SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
    {SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
-   {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER | QUEUE_IN_OPLOCK },
+   {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER },
    {SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
 
+#ifdef HAVE_NT_SMBS
+   /* NT PROTOCOL FOLLOWS */
+   {SMBntcreateX, "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
+   {SMBnttrans, "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
+   {SMBnttranss, "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
+   {SMBntcancel, "SMBntcancel", reply_ntcancel, AS_USER },
+#endif /* HAVE_NT_SMBS */
+
    /* messaging routines */
    {SMBsends,"SMBsends",reply_sends,AS_GUEST},
    {SMBsendstrt,"SMBsendstrt",reply_sendstrt,AS_GUEST},
@@ -4499,106 +4880,126 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
 
   /* make sure this is an SMB packet */
   if (strncmp(smb_base(inbuf),"\377SMB",4) != 0)
-    {
-      DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf)));
-      return(-1);
-    }
+  {
+    DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf)));
+    return(-1);
+  }
 
   for (match=0;match<num_smb_messages;match++)
     if (smb_messages[match].code == type)
       break;
 
   if (match == num_smb_messages)
-    {
-      DEBUG(0,("Unknown message type %d!\n",type));
-      outsize = reply_unknown(inbuf,outbuf);
-    }
+  {
+    DEBUG(0,("Unknown message type %d!\n",type));
+    outsize = reply_unknown(inbuf,outbuf);
+  }
   else
+  {
+    DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
+
+    if(global_oplock_break && (smb_messages[match].flags & QUEUE_IN_OPLOCK))
     {
-      DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
+      /* 
+       * Queue this message as we are the process of an oplock break.
+       */
 
-      if(global_oplock_break && (smb_messages[match].flags & QUEUE_IN_OPLOCK))
-      {
-        /* 
-         * Queue this message as we are the process of an oplock break.
-         */
+      DEBUG(2,("%s: switch_message: queueing message due to being in oplock break state.\n",
+             timestring() ));
 
-        DEBUG(2,("%s: switch_message: queueing message due to being in oplock break state.\n",
-               timestring() ));
+      push_smb_message( inbuf, size);
+      return -1;
+    }          
 
-        push_smb_message( inbuf, size);
-        return -1;
-      }          
+    if (smb_messages[match].fn)
+    {
+      int cnum = SVAL(inbuf,smb_tid);
+      int flags = smb_messages[match].flags;
+      static uint16 last_session_tag = UID_FIELD_INVALID;
+      /* In share mode security we must ignore the vuid. */
+      uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
+      /* Ensure this value is replaced in the incoming packet. */
+      SSVAL(inbuf,smb_uid,session_tag);
 
-      if (smb_messages[match].fn)
-       {
-         int cnum = SVAL(inbuf,smb_tid);
-         int flags = smb_messages[match].flags;
-          /* In share mode security we must ignore the vuid. */
-         uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
-          /* Ensure this value is replaced in the incoming packet. */
-          SSVAL(inbuf,smb_uid,session_tag);
-
-         /* does this protocol need to be run as root? */
-         if (!(flags & AS_USER))
-           unbecome_user();
-
-         /* does this protocol need to be run as the connected user? */
-         if ((flags & AS_USER) && !become_user(&Connections[cnum], cnum,session_tag)) {
-           if (flags & AS_GUEST) 
-             flags &= ~AS_USER;
-           else
-             return(ERROR(ERRSRV,ERRinvnid));
-         }
-         /* this code is to work around a bug is MS client 3 without
-            introducing a security hole - it needs to be able to do
-            print queue checks as guest if it isn't logged in properly */
-         if (flags & AS_USER)
-           flags &= ~AS_GUEST;
+      /*
+       * Ensure the correct username is in sesssetup_user.
+       * This is a really ugly bugfix for problems with
+       * multiple session_setup_and_X's being done and
+       * allowing %U and %G substitutions to work correctly.
+       * There is a reason this code is done here, don't
+       * move it unless you know what you're doing... :-).
+       * JRA.
+       */
+      if(session_tag != last_session_tag ) {
+        user_struct *vuser = NULL;
+
+        last_session_tag = session_tag;
+        if(session_tag != UID_FIELD_INVALID)
+          vuser = get_valid_user_struct(session_tag);           
+        if(vuser != NULL)
+          pstrcpy( sesssetup_user, vuser->requested_name);
+      }
 
-         /* does it need write permission? */
-         if ((flags & NEED_WRITE) && !CAN_WRITE(cnum))
-           return(ERROR(ERRSRV,ERRaccess));
+      /* does this protocol need to be run as root? */
+      if (!(flags & AS_USER))
+        unbecome_user();
 
-         /* ipc services are limited */
-         if (IS_IPC(cnum) && (flags & AS_USER) && !(flags & CAN_IPC))
-           return(ERROR(ERRSRV,ERRaccess));        
+      /* does this protocol need to be run as the connected user? */
+      if ((flags & AS_USER) && !become_user(&Connections[cnum], cnum,session_tag)) {
+        if (flags & AS_GUEST) 
+          flags &= ~AS_USER;
+        else
+          return(ERROR(ERRSRV,ERRinvnid));
+      }
+      /* this code is to work around a bug is MS client 3 without
+         introducing a security hole - it needs to be able to do
+         print queue checks as guest if it isn't logged in properly */
+      if (flags & AS_USER)
+        flags &= ~AS_GUEST;
 
-         /* load service specific parameters */
-         if (OPEN_CNUM(cnum) && !become_service(cnum,(flags & AS_USER)?True:False))
-           return(ERROR(ERRSRV,ERRaccess));
+      /* does it need write permission? */
+      if ((flags & NEED_WRITE) && !CAN_WRITE(cnum))
+        return(ERROR(ERRSRV,ERRaccess));
 
-         /* does this protocol need to be run as guest? */
-         if ((flags & AS_GUEST) && (!become_guest() || !check_access(-1)))
-           return(ERROR(ERRSRV,ERRaccess));
+      /* ipc services are limited */
+      if (IS_IPC(cnum) && (flags & AS_USER) && !(flags & CAN_IPC))
+        return(ERROR(ERRSRV,ERRaccess));           
 
-         last_inbuf = inbuf;
+      /* load service specific parameters */
+      if (OPEN_CNUM(cnum) && !become_service(cnum,(flags & AS_USER)?True:False))
+        return(ERROR(ERRSRV,ERRaccess));
 
-         outsize = smb_messages[match].fn(inbuf,outbuf,size,bufsize);
-       }
-      else
-       {
-         outsize = reply_unknown(inbuf,outbuf);
-       }
+      /* does this protocol need to be run as guest? */
+      if ((flags & AS_GUEST) && (!become_guest() || !check_access(-1)))
+        return(ERROR(ERRSRV,ERRaccess));
+
+      last_inbuf = inbuf;
+
+      outsize = smb_messages[match].fn(inbuf,outbuf,size,bufsize);
     }
+    else
+    {
+      outsize = reply_unknown(inbuf,outbuf);
+    }
+  }
 
 #if PROFILING
   GetTimeOfDay(&msg_end_time);
   if (!(smb_messages[match].flags & TIME_INIT))
-    {
-      smb_messages[match].time = 0;
-      smb_messages[match].flags |= TIME_INIT;
-    }
+  {
+    smb_messages[match].time = 0;
+    smb_messages[match].flags |= TIME_INIT;
+  }
   {
     unsigned long this_time =     
       (msg_end_time.tv_sec - msg_start_time.tv_sec)*1e6 +
-       (msg_end_time.tv_usec - msg_start_time.tv_usec);
+      (msg_end_time.tv_usec - msg_start_time.tv_usec);
     smb_messages[match].time += this_time;
     total_time += this_time;
   }
   DEBUG(2,("TIME %s  %d usecs   %g pct\n",
-          smb_fn_name(type),smb_messages[match].time,
-       (100.0*smb_messages[match].time) / total_time));
+        smb_fn_name(type),smb_messages[match].time,
+        (100.0*smb_messages[match].time) / total_time));
 #endif
 
   return(outsize);
@@ -4666,12 +5067,12 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
   CVAL(outbuf2,smb_com) = CVAL(inbuf2,smb_com);
   
   memcpy(outbuf2+4,inbuf2+4,4);
-  CVAL(outbuf2,smb_rcls) = SUCCESS;
+  CVAL(outbuf2,smb_rcls) = SMB_SUCCESS;
   CVAL(outbuf2,smb_reh) = 0;
   CVAL(outbuf2,smb_flg) = 0x80 | (CVAL(inbuf2,smb_flg) & 0x8); /* bit 7 set 
                                                                  means a reply */
   SSVAL(outbuf2,smb_flg2,1); /* say we support long filenames */
-  SSVAL(outbuf2,smb_err,SUCCESS);
+  SSVAL(outbuf2,smb_err,SMB_SUCCESS);
   SSVAL(outbuf2,smb_tid,SVAL(inbuf2,smb_tid));
   SSVAL(outbuf2,smb_pid,SVAL(inbuf2,smb_pid));
   SSVAL(outbuf2,smb_uid,SVAL(inbuf2,smb_uid));
@@ -4728,12 +5129,12 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
   set_message(outbuf,0,0,True);
   
   memcpy(outbuf+4,inbuf+4,4);
-  CVAL(outbuf,smb_rcls) = SUCCESS;
+  CVAL(outbuf,smb_rcls) = SMB_SUCCESS;
   CVAL(outbuf,smb_reh) = 0;
   CVAL(outbuf,smb_flg) = 0x80 | (CVAL(inbuf,smb_flg) & 0x8); /* bit 7 set 
                                                             means a reply */
   SSVAL(outbuf,smb_flg2,1); /* say we support long filenames */
-  SSVAL(outbuf,smb_err,SUCCESS);
+  SSVAL(outbuf,smb_err,SMB_SUCCESS);
   SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
   SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
   SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
@@ -4838,6 +5239,18 @@ static void process(void)
         reload_services(True);
       }
 
+      /*
+       * If reload_after_sighup == True then we got a SIGHUP
+       * and are being asked to reload. Fix from <branko.cibej@hermes.si>
+       */
+
+      if (reload_after_sighup)
+      {
+        DEBUG(0,("Reloading services after SIGHUP\n"));
+        reload_services(False);
+        reload_after_sighup = False;
+      }
+
       /* automatic timeout if all connections are closed */      
       if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) 
       {
@@ -4877,6 +5290,52 @@ static void process(void)
         DEBUG(2,("%s Closing idle connection 2\n",timestring()));
         return;
       }
+
+      if(global_machine_pasword_needs_changing)
+      {
+        unsigned char trust_passwd_hash[16];
+        time_t lct;
+        pstring remote_machine_list;
+
+        /*
+         * We're in domain level security, and the code that
+         * read the machine password flagged that the machine
+         * password needs changing.
+         */
+
+        /*
+         * First, open the machine password file with an exclusive lock.
+         */
+
+        if(!trust_password_lock( global_myworkgroup, global_myname, True)) {
+          DEBUG(0,("process: unable to open the machine account password file for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+          continue;
+        }
+
+        if(!get_trust_account_password( trust_passwd_hash, &lct)) {
+          DEBUG(0,("process: unable to read the machine account password for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+          trust_password_unlock();
+          continue;
+        }
+
+        /*
+         * Make sure someone else hasn't already done this.
+         */
+
+        if(t < lct + lp_machine_password_timeout()) {
+          trust_password_unlock();
+          global_machine_pasword_needs_changing = False;
+          continue;
+        }
+
+        pstrcpy(remote_machine_list, lp_passwordserver());
+
+        change_trust_account_password( global_myworkgroup, remote_machine_list);
+        trust_password_unlock();
+        global_machine_pasword_needs_changing = False;
+      }
     }
 
     if(got_smb)
@@ -4895,6 +5354,21 @@ static void init_structs(void )
   int i;
   get_myname(myhostname,NULL);
 
+  /*
+   * Set the machine NETBIOS name if not already
+   * set from the config file.
+   */
+
+  if (!*global_myname)
+  {
+    char *p;
+    fstrcpy( global_myname, myhostname );
+    p = strchr( global_myname, '.' );
+    if (p) 
+      *p = 0;
+  }
+  strupper( global_myname );
+
   for (i=0;i<MAX_CONNECTIONS;i++)
     {
       Connections[i].open = False;
@@ -4907,11 +5381,10 @@ static void init_structs(void )
       string_init(&Connections[i].origpath,"");
     }
 
-  for (i=0;i<MAX_OPEN_FILES;i++)
+  for (i=0;i<MAX_FNUMS;i++)
     {
       Files[i].open = False;
       string_init(&Files[i].name,"");
-
     }
 
   for (i=0;i<MAX_OPEN_FILES;i++)
@@ -4979,9 +5452,9 @@ static void usage(char *pname)
 
   TimeInit();
 
-  strcpy(debugf,SMBLOGFILE);  
+  pstrcpy(debugf,SMBLOGFILE);  
 
-  strcpy(remote_machine, "smb");
+  pstrcpy(remote_machine, "smb");
 
   setup_logging(argv[0],False);
 
@@ -4998,7 +5471,7 @@ static void usage(char *pname)
   seteuid(0);
 #endif
 
-  fault_setup(exit_server);
+  fault_setup((void (*)(void *))exit_server);
   signal(SIGTERM , SIGNAL_CAST dflt_sig);
 
   /* we want total control over the permissions on created files,
@@ -5020,10 +5493,10 @@ static void usage(char *pname)
     switch (opt)
       {
       case 'O':
-       strcpy(user_socket_options,optarg);
+       pstrcpy(user_socket_options,optarg);
        break;
       case 'i':
-       strcpy(scope,optarg);
+       pstrcpy(scope,optarg);
        break;
       case 'P':
        {
@@ -5032,10 +5505,10 @@ static void usage(char *pname)
        }
        break;  
       case 's':
-       strcpy(servicesf,optarg);
+       pstrcpy(servicesf,optarg);
        break;
       case 'l':
-       strcpy(debugf,optarg);
+       pstrcpy(debugf,optarg);
        break;
       case 'a':
        {
@@ -5102,9 +5575,24 @@ static void usage(char *pname)
   if (!reload_services(False))
     return(-1);        
 
+#ifdef USE_SSL
+  {
+    extern BOOL sslEnabled;
+    sslEnabled = lp_ssl_enabled();
+    if(sslEnabled)
+      sslutil_init(True);
+  }
+#endif        /* USE_SSL */
+
   codepage_initialise(lp_client_code_page());
 
-  strcpy(myworkgroup, lp_workgroup());
+  pstrcpy(global_myworkgroup, lp_workgroup());
+
+  if(!pdb_generate_machine_sid())
+  {
+    DEBUG(0,("ERROR: Samba cannot get a machine SID.\n"));
+    exit(1);
+  }
 
 #ifndef NO_SIGNAL_TEST
   signal(SIGHUP,SIGNAL_CAST sig_hup);
@@ -5154,6 +5642,9 @@ static void usage(char *pname)
   if (!locking_init(0))
     exit(1);
 
+  if(!initialize_password_db())
+    exit(1);
+
   /* possibly reload the services file. */
   reload_services(True);
 
@@ -5175,5 +5666,3 @@ static void usage(char *pname)
   exit_server("normal exit");
   return(0);
 }
-
-