Merge of new 2.2 code into HEAD (Gerald I hate you :-) :-). Allows new SAMR
[ira/wip.git] / source3 / smbd / open.c
index 5a0493e625fdc350d0f6a8328a01cf1622b51d4b..afcaeff1ae3ac8578af2e7a408e6d44846d0c322 100644 (file)
@@ -1,5 +1,3 @@
-#define OLD_NTDOMAIN 1
-
 /* 
    Unix SMB/Netbios implementation.
    Version 1.9.
@@ -25,7 +23,7 @@
 
 extern int DEBUGLEVEL;
 
-extern pstring sesssetup_user;
+extern userdom_struct current_user_info;
 extern uint16 global_oplock_port;
 extern BOOL global_client_failed_oplock_break;
 
@@ -36,13 +34,18 @@ extern BOOL global_client_failed_oplock_break;
 static int fd_open(struct connection_struct *conn, char *fname, 
                   int flags, mode_t mode)
 {
-       int fd = conn->vfs_ops.open(dos_to_unix(fname,False),flags,mode);
+       int fd;
+#ifdef O_NONBLOCK
+       flags |= O_NONBLOCK;
+#endif
+
+       fd = conn->vfs_ops.open(conn,dos_to_unix(fname,False),flags,mode);
 
        /* Fix for files ending in '.' */
        if((fd == -1) && (errno == ENOENT) &&
           (strchr(fname,'.')==NULL)) {
                pstrcat(fname,".");
-               fd = conn->vfs_ops.open(dos_to_unix(fname,False),flags,mode);
+               fd = conn->vfs_ops.open(conn,dos_to_unix(fname,False),flags,mode);
        }
 
        DEBUG(10,("fd_open: name %s, mode = %d, fd = %d. %s\n", fname, (int)mode, fd,
@@ -83,12 +86,11 @@ static void check_for_pipe(char *fname)
 ****************************************************************************/
 
 static BOOL open_file(files_struct *fsp,connection_struct *conn,
-                     char *fname1,int flags,mode_t mode)
+                     char *fname1,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode)
 {
        extern struct current_user current_user;
        pstring fname;
        int accmode = (flags & O_ACCMODE);
-       SMB_STRUCT_STAT sbuf;
 
        fsp->fd = -1;
        fsp->oplock_type = NO_OPLOCK;
@@ -133,10 +135,12 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
                return False;
        }
 
-       if (conn->vfs_ops.fstat(fsp->fd, &sbuf) == -1) {
-               DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) ));
-               fd_close(conn, fsp);
-               return False;
+       if (!VALID_STAT(*psbuf)) {
+               if (vfs_fstat(fsp,fsp->fd,psbuf) == -1) {
+                       DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) ));
+                       fd_close(conn, fsp);
+                       return False;
+               }
        }
 
        /*
@@ -145,18 +149,18 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
         * so catch a directory open and return an EISDIR. JRA.
         */
 
-       if(S_ISDIR(sbuf.st_mode)) {
+       if(S_ISDIR(psbuf->st_mode)) {
                fd_close(conn, fsp);
                errno = EISDIR;
                return False;
        }
 
-       fsp->mode = sbuf.st_mode;
-       fsp->inode = sbuf.st_ino;
-       fsp->dev = sbuf.st_dev;
+       fsp->mode = psbuf->st_mode;
+       fsp->inode = psbuf->st_ino;
+       fsp->dev = psbuf->st_dev;
        GetTimeOfDay(&fsp->open_time);
        fsp->vuid = current_user.vuid;
-       fsp->size = 0;
+       fsp->size = psbuf->st_size;
        fsp->pos = -1;
        fsp->can_lock = True;
        fsp->can_read = ((flags & O_WRONLY)==0);
@@ -182,10 +186,17 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
        fsp->wcp = NULL; /* Write cache pointer. */
 
        DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
-                *sesssetup_user ? sesssetup_user : conn->user,fsp->fsp_name,
+                *current_user_info.smb_name ? current_user_info.smb_name : conn->user,fsp->fsp_name,
                 BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
                 conn->num_files_open + 1));
 
+       /*
+        * Take care of inherited ACLs on created files. JRA.
+        */
+
+       if ((flags & O_CREAT) && (conn->vfs_ops.fchmod_acl != NULL))
+               conn->vfs_ops.fchmod_acl(fsp, fsp->fd, mode);
+
        return True;
 }
 
@@ -208,7 +219,7 @@ static int truncate_unless_locked(struct connection_struct *conn, files_struct *
                unix_ERR_code = ERRlock;
                return -1;
        } else {
-               return conn->vfs_ops.ftruncate(fsp->fd,0); 
+               return conn->vfs_ops.ftruncate(fsp,fsp->fd,0); 
        }
 }
 
@@ -508,17 +519,17 @@ static void kernel_flock(files_struct *fsp, int deny_mode)
 
 
 /****************************************************************************
- Open a file with a share mode.
+ Open a file with a share mode. On output from this open we are guarenteeing
+ that 
 ****************************************************************************/
-files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mode,int ofun,
-                     mode_t mode,int oplock_request, int *Access,int *action)
+files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf, 
+                               int share_mode,int ofun, mode_t mode,int oplock_request, int *Access,int *action)
 {
        int flags=0;
        int flags2=0;
        int deny_mode = GET_DENY_MODE(share_mode);
        BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode);
-       SMB_STRUCT_STAT sbuf;
-       BOOL file_existed = vfs_file_exist(conn, fname, &sbuf);
+       BOOL file_existed = VALID_STAT(*psbuf);
        BOOL fcbopen = False;
        SMB_DEV_T dev = 0;
        SMB_INO_T inode = 0;
@@ -542,6 +553,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
                return NULL;
 
        fsp->fd = -1;
+       fsp->conn = conn; /* The vfs_fXXX() macros need this. */
 
        DEBUG(10,("open_file_shared: fname = %s, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
                fname, share_mode, ofun, (int)mode,  oplock_request ));
@@ -614,7 +626,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
 #endif /* O_SYNC */
   
        if (flags != O_RDONLY && file_existed && 
-                       (!CAN_WRITE(conn) || IS_DOS_READONLY(dos_mode(conn,fname,&sbuf)))) {
+                       (!CAN_WRITE(conn) || IS_DOS_READONLY(dos_mode(conn,fname,psbuf)))) {
                if (!fcbopen) {
                        DEBUG(5,("open_file_shared: read/write access requested for file %s on read only %s\n",
                                fname, !CAN_WRITE(conn) ? "share" : "file" ));
@@ -633,14 +645,29 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
        }
 
        if (file_existed) {
-               dev = sbuf.st_dev;
-               inode = sbuf.st_ino;
+
+               dev = psbuf->st_dev;
+               inode = psbuf->st_ino;
 
                lock_share_entry(conn, dev, inode);
 
                num_share_modes = open_mode_check(conn, fname, dev, inode, share_mode,
                                                                &flags, &oplock_request, &all_current_opens_are_level_II);
                if(num_share_modes == -1) {
+
+                       /*
+                        * This next line is a subtlety we need for MS-Access. If a file open will
+                        * fail due to share permissions and also for security (access)
+                        * reasons, we need to return the access failed error, not the
+                        * share error. This means we must attempt to open the file anyway
+                        * in order to get the UNIX access error - even if we're going to
+                        * fail the open for share reasons. This is bad, as we're burning
+                        * another fd if there are existing locks but there's nothing else
+                        * we can do. We also ensure we're not going to create or tuncate
+                        * the file as we only want an access decision at this stage. JRA.
+                        */
+                       open_file(fsp,conn,fname,psbuf,flags|(flags2&~(O_TRUNC|O_CREAT)),mode);
+
                        unlock_share_entry(conn, dev, inode);
                        file_free(fsp);
                        return NULL;
@@ -654,10 +681,10 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
        DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
                        flags,flags2,(int)mode));
 
-       fsp_open = open_file(fsp,conn,fname,flags|(flags2&~(O_TRUNC)),mode);
+       fsp_open = open_file(fsp,conn,fname,psbuf,flags|(flags2&~(O_TRUNC)),mode);
 
        if (!fsp_open && (flags == O_RDWR) && (errno != ENOENT) && fcbopen) {
-               if((fsp_open = open_file(fsp,conn,fname,O_RDONLY,mode)) == True)
+               if((fsp_open = open_file(fsp,conn,fname,psbuf,O_RDONLY,mode)) == True)
                        flags = O_RDONLY;
        }
 
@@ -668,14 +695,6 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
                return NULL;
        }
 
-       /* not that we ignore failure for the following. It is
-           basically a hack for NFS, and NFS will never set one of
-           these only read them. Nobody but Samba can ever set a deny
-           mode and we have already checked our more authoritative
-           locking database for permission to set this deny mode. If
-           the kernel refuses the operations then the kernel is wrong */
-       kernel_flock(fsp, deny_mode);
-
        /*
         * Deal with the race condition where two smbd's detect the file doesn't
         * exist and do the create at the same time. One of them will win and
@@ -702,6 +721,14 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
                 */
        }
 
+       /* note that we ignore failure for the following. It is
+           basically a hack for NFS, and NFS will never set one of
+           these only read them. Nobody but Samba can ever set a deny
+           mode and we have already checked our more authoritative
+           locking database for permission to set this deny mode. If
+           the kernel refuses the operations then the kernel is wrong */
+       kernel_flock(fsp, deny_mode);
+
        /*
         * At this point onwards, we can guarentee that the share entry
         * is locked, whether we created the file or not, and that the
@@ -712,11 +739,16 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
         * If requested, truncate the file.
         */
 
-       if ((flags2&O_TRUNC) && (truncate_unless_locked(conn,fsp) == -1)) {
-               unlock_share_entry_fsp(fsp);
-               fd_close(conn,fsp);
-               file_free(fsp);
-               return NULL;
+       if (flags2&O_TRUNC) {
+               /*
+                * We are modifing the file after open - update the stat struct..
+                */
+               if ((truncate_unless_locked(conn,fsp) == -1) || (vfs_fstat(fsp,fsp->fd,psbuf)==-1)) {
+                       unlock_share_entry_fsp(fsp);
+                       fd_close(conn,fsp);
+                       file_free(fsp);
+                       return NULL;
+               }
        }
 
        switch (flags) {
@@ -778,28 +810,26 @@ files_struct *open_file_shared(connection_struct *conn,char *fname,int share_mod
  with the 'stat_open' flag set 
 ****************************************************************************/
 
-files_struct *open_file_stat(connection_struct *conn,
-                  char *fname, int smb_ofun, SMB_STRUCT_STAT *pst, int *action)
+files_struct *open_file_stat(connection_struct *conn, char *fname,
+                                                       SMB_STRUCT_STAT *psbuf, int smb_ofun, int *action)
 {
        extern struct current_user current_user;
-       files_struct *fsp = file_new();
+       files_struct *fsp = NULL;
 
-       if(!fsp)
-               return NULL;
-
-       if(conn->vfs_ops.stat(dos_to_unix(fname, False), pst) < 0) {
-               DEBUG(0,("open_file_stat: unable to stat name = %s. Error was %s\n",
-                        fname, strerror(errno) ));
-               file_free(fsp);
+       if (!VALID_STAT(*psbuf)) {
+               DEBUG(0,("open_file_stat: unable to stat name = %s. Error was %s\n", fname, strerror(errno) ));
                return NULL;
        }
 
-       if(S_ISDIR(pst->st_mode)) {
+       if(S_ISDIR(psbuf->st_mode)) {
                DEBUG(0,("open_file_stat: %s is a directory !\n", fname ));
-               file_free(fsp);
                return NULL;
        }
 
+       fsp = file_new();
+       if(!fsp)
+               return NULL;
+
        *action = FILE_WAS_OPENED;
        
        DEBUG(5,("open_file_stat: opening file %s as a stat entry\n", fname));
@@ -809,10 +839,12 @@ files_struct *open_file_stat(connection_struct *conn,
         */
        
        fsp->fd = -1;
-       fsp->mode = 0;
+       fsp->mode = psbuf->st_mode;
+       fsp->inode = psbuf->st_ino;
+       fsp->dev = psbuf->st_dev;
        GetTimeOfDay(&fsp->open_time);
+       fsp->size = psbuf->st_size;
        fsp->vuid = current_user.vuid;
-       fsp->size = 0;
        fsp->pos = -1;
        fsp->can_lock = False;
        fsp->can_read = False;
@@ -846,20 +878,20 @@ files_struct *open_file_stat(connection_struct *conn,
  Open a directory from an NT SMB call.
 ****************************************************************************/
 
-files_struct *open_directory(connection_struct *conn,
-                  char *fname, int smb_ofun, mode_t unixmode, int *action)
+files_struct *open_directory(connection_struct *conn, char *fname,
+                                                       SMB_STRUCT_STAT *psbuf, int smb_ofun, mode_t unixmode, int *action)
 {
        extern struct current_user current_user;
-       SMB_STRUCT_STAT st;
        BOOL got_stat = False;
        files_struct *fsp = file_new();
 
        if(!fsp)
                return NULL;
 
-       if(conn->vfs_ops.stat(dos_to_unix(fname, False), &st) == 0) {
+       fsp->conn = conn; /* THe vfs_fXXX() macros need this. */
+
+       if (VALID_STAT(*psbuf))
                got_stat = True;
-       }
 
        if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) {
                file_free(fsp);
@@ -871,7 +903,7 @@ files_struct *open_directory(connection_struct *conn,
 
                if (got_stat) {
 
-                       if(!S_ISDIR(st.st_mode)) {
+                       if(!S_ISDIR(psbuf->st_mode)) {
                                DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
                                file_free(fsp);
                                errno = EACCES;
@@ -892,13 +924,18 @@ files_struct *open_directory(connection_struct *conn,
                                return NULL;
                        }
 
-                       if(conn->vfs_ops.mkdir(dos_to_unix(fname, False), 
-                                               unix_mode(conn,aDIR, fname)) < 0) {
+                       if(vfs_mkdir(conn,fname, unix_mode(conn,aDIR, fname)) < 0) {
                                DEBUG(0,("open_directory: unable to create %s. Error was %s\n",
                                         fname, strerror(errno) ));
                                file_free(fsp);
                                return NULL;
                        }
+
+                       if(vfs_stat(conn,fname, psbuf) != 0) {
+                               file_free(fsp);
+                               return NULL;
+                       }
+
                        *action = FILE_WAS_CREATED;
 
                }
@@ -915,7 +952,7 @@ files_struct *open_directory(connection_struct *conn,
                        return NULL;
                }
 
-               if(!S_ISDIR(st.st_mode)) {
+               if(!S_ISDIR(psbuf->st_mode)) {
                        DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
                        file_free(fsp);
                        return NULL;
@@ -924,18 +961,19 @@ files_struct *open_directory(connection_struct *conn,
                *action = FILE_WAS_OPENED;
        }
        
-       DEBUG(5,("open_directory: opening directory %s\n",
-                fname));
+       DEBUG(5,("open_directory: opening directory %s\n", fname));
 
        /*
         * Setup the files_struct for it.
         */
        
        fsp->fd = -1;
-       fsp->mode = 0;
+       fsp->mode = psbuf->st_mode;
+       fsp->inode = psbuf->st_ino;
+       fsp->dev = psbuf->st_dev;
        GetTimeOfDay(&fsp->open_time);
+       fsp->size = psbuf->st_size;
        fsp->vuid = current_user.vuid;
-       fsp->size = 0;
        fsp->pos = -1;
        fsp->can_lock = True;
        fsp->can_read = False;
@@ -979,7 +1017,7 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
   SMB_DEV_T dev;
   SMB_INO_T inode;
 
-  if (conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf) == -1)
+  if (vfs_stat(conn,fname,&sbuf) == -1)
     return(True);
 
   dev = sbuf.st_dev;
@@ -1118,5 +1156,3 @@ free_and_exit:
     free((char *)old_shares);
   return(ret);
 }
-
-#undef OLD_NTDOMAIN