Merge branch 'master' of ssh://git.samba.org/data/git/abartlet/samba into extended...
[abartlet/samba.git/.git] / source3 / smbd / trans2.c
index c385c6ccb1705469daef9d5a2aada9440f4ecd68..606e65679549ea5b6a13f40a0e35cd69e0f32db7 100644 (file)
@@ -1006,22 +1006,24 @@ static void call_trans2open(connection_struct *conn,
                return;
        }
 
-       status = create_file(conn,                      /* conn */
-                            req,                       /* req */
-                            0,                         /* root_dir_fid */
-                            fname,                     /* fname */
-                            access_mask,               /* access_mask */
-                            share_mode,                /* share_access */
-                            create_disposition,        /* create_disposition*/
-                            create_options,            /* create_options */
-                            open_attr,                 /* file_attributes */
-                            oplock_request,            /* oplock_request */
-                            open_size,                 /* allocation_size */
-                            NULL,                      /* sd */
-                            ea_list,                   /* ea_list */
-                            &fsp,                      /* result */
-                            &smb_action,               /* pinfo */
-                            &sbuf);                    /* psbuf */
+       status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               fname,                                  /* fname */
+               CFF_DOS_PATH,                           /* create_file_flags */
+               access_mask,                            /* access_mask */
+               share_mode,                             /* share_access */
+               create_disposition,                     /* create_disposition*/
+               create_options,                         /* create_options */
+               open_attr,                              /* file_attributes */
+               oplock_request,                         /* oplock_request */
+               open_size,                              /* allocation_size */
+               NULL,                                   /* sd */
+               ea_list,                                /* ea_list */
+               &fsp,                                   /* result */
+               &smb_action,                            /* pinfo */
+               &sbuf);                                 /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
                if (open_was_deferred(req->mid)) {
@@ -1093,15 +1095,13 @@ static bool exact_match(connection_struct *conn,
 {
        if (mask[0] == '.' && mask[1] == 0)
                return False;
-       if (conn->case_sensitive)
-               return strcmp(str,mask)==0;
-       if (StrCaseCmp(str,mask) != 0) {
-               return False;
-       }
        if (dptr_has_wild(conn->dirptr)) {
                return False;
        }
-       return True;
+       if (conn->case_sensitive)
+               return strcmp(str,mask)==0;
+       else
+               return StrCaseCmp(str,mask) == 0;
 }
 
 /****************************************************************************
@@ -1135,7 +1135,7 @@ static uint32 unix_filetype(mode_t mode)
                return UNIX_TYPE_SOCKET;
 #endif
 
-       DEBUG(0,("unix_filetype: unknown filetype %u", (unsigned)mode));
+       DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
        return UNIX_TYPE_UNKNOWN;
 }
 
@@ -3999,6 +3999,46 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                        return;
                }
 
+               if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+                   && is_ntfs_stream_name(fname)) {
+                       char *base;
+                       SMB_STRUCT_STAT bsbuf;
+
+                       status = split_ntfs_stream_name(talloc_tos(), fname,
+                                                       &base, NULL);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(10, ("create_file_unixpath: "
+                                       "split_ntfs_stream_name failed: %s\n",
+                                       nt_errstr(status)));
+                               reply_nterror(req, status);
+                               return;
+                       }
+
+                       SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */
+
+                       if (INFO_LEVEL_IS_UNIX(info_level)) {
+                               /* Always do lstat for UNIX calls. */
+                               if (SMB_VFS_LSTAT(conn,base,&bsbuf)) {
+                                       DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",base,strerror(errno)));
+                                       reply_unixerror(req,ERRDOS,ERRbadpath);
+                                       return;
+                               }
+                       } else {
+                               if (SMB_VFS_STAT(conn,base,&bsbuf) != 0) {
+                                       DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",base,strerror(errno)));
+                                       reply_unixerror(req,ERRDOS,ERRbadpath);
+                                       return;
+                               }
+                       }
+
+                       fileid = vfs_file_id_from_sbuf(conn, &bsbuf);
+                       get_file_infos(fileid, &delete_pending, NULL);
+                       if (delete_pending) {
+                               reply_nterror(req, NT_STATUS_DELETE_PENDING);
+                               return;
+                       }
+               }
+
                if (INFO_LEVEL_IS_UNIX(info_level)) {
                        /* Always do lstat for UNIX calls. */
                        if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
@@ -4917,7 +4957,11 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
                          time_to_asc(convert_timespec_to_time_t(ts[1])) ));
 
                if (fsp != NULL) {
-                       set_sticky_write_time_fsp(fsp, ts[1]);
+                       if (fsp->base_fsp) {
+                               set_sticky_write_time_fsp(fsp->base_fsp, ts[1]);
+                       } else {
+                               set_sticky_write_time_fsp(fsp, ts[1]);
+                       }
                } else {
                        set_sticky_write_time_path(conn, fname,
                                            vfs_file_id_from_sbuf(conn, psbuf),
@@ -4927,6 +4971,10 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
 
        DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
 
+       if (fsp && fsp->base_fsp) {
+               fname = fsp->base_fsp->fsp_name;
+       }
+
        if(file_ntimes(conn, fname, ts)!=0) {
                return map_nt_error_from_unix(errno);
        }
@@ -5009,15 +5057,26 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                return NT_STATUS_OK;
        }
 
-       status = open_file_ntcreate(conn, req, fname, psbuf,
-                               FILE_WRITE_ATTRIBUTES,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
-                               FILE_OPEN,
-                               0,
-                               FILE_ATTRIBUTE_NORMAL,
-                               FORCE_OPLOCK_BREAK_TO_NONE,
-                               NULL, &new_fsp);
-       
+        status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               fname,                                  /* fname */
+               0,                                      /* create_file_flags */
+               FILE_WRITE_ATTRIBUTES,                  /* access_mask */
+               (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
+                   FILE_SHARE_DELETE),
+               FILE_OPEN,                              /* create_disposition*/
+               0,                                      /* create_options */
+               FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
+               FORCE_OPLOCK_BREAK_TO_NONE,             /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &new_fsp,                               /* result */
+               NULL,                                   /* pinfo */
+               psbuf);                                 /* psbuf */
+
        if (!NT_STATUS_IS_OK(status)) {
                /* NB. We check for open_was_deferred in the caller. */
                return status;
@@ -5353,26 +5412,42 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                return NT_STATUS_NOT_SUPPORTED;
        }
 
-       /* Create the base directory. */
-       base_name = talloc_strdup(ctx, fname);
-       if (!base_name) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       p = strrchr_m(base_name, '/');
-       if (p) {
-               p[1] = '\0';
+       if (fsp && fsp->base_fsp) {
+               if (newname[0] != ':') {
+                       return NT_STATUS_NOT_SUPPORTED;
+               }
+               base_name = talloc_asprintf(ctx, "%s%s",
+                                          fsp->base_fsp->fsp_name,
+                                          newname);
+               if (!base_name) {
+                       return NT_STATUS_NO_MEMORY;
+               }
        } else {
-               base_name = talloc_strdup(ctx, "./");
+               if (is_ntfs_stream_name(newname)) {
+                       return NT_STATUS_NOT_SUPPORTED;
+               }
+
+               /* Create the base directory. */
+               base_name = talloc_strdup(ctx, fname);
+               if (!base_name) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               p = strrchr_m(base_name, '/');
+               if (p) {
+                       p[1] = '\0';
+               } else {
+                       base_name = talloc_strdup(ctx, "./");
+                       if (!base_name) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+               }
+               /* Append the new name. */
+               base_name = talloc_asprintf_append(base_name,
+                               "%s",
+                               newname);
                if (!base_name) {
                        return NT_STATUS_NO_MEMORY;
                }
-       }
-       /* Append the new name. */
-       base_name = talloc_asprintf_append(base_name,
-                       "%s",
-                       newname);
-       if (!base_name) {
-               return NT_STATUS_NO_MEMORY;
        }
 
        if (fsp) {
@@ -5762,14 +5837,25 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
 
        /* Pathname or stat or directory file. */
 
-       status = open_file_ntcreate(conn, req, fname, psbuf,
-                               FILE_WRITE_DATA,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
-                               FILE_OPEN,
-                               0,
-                               FILE_ATTRIBUTE_NORMAL,
-                               FORCE_OPLOCK_BREAK_TO_NONE,
-                               NULL, &new_fsp);
+       status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               fname,                                  /* fname */
+               0,                                      /* create_file_flags */
+               FILE_WRITE_DATA,                        /* access_mask */
+               (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
+                   FILE_SHARE_DELETE),
+               FILE_OPEN,                              /* create_disposition*/
+               0,                                      /* create_options */
+               FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
+               FORCE_OPLOCK_BREAK_TO_NONE,             /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &new_fsp,                               /* result */
+               NULL,                                   /* pinfo */
+               psbuf);                                 /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
                /* NB. We check for open_was_deferred in the caller. */
@@ -6193,16 +6279,24 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
        DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
                fname, (unsigned int)unixmode ));
 
-       status = open_directory(conn, req,
-                               fname,
-                               psbuf,
-                               FILE_READ_ATTRIBUTES, /* Just a stat open */
-                               FILE_SHARE_NONE, /* Ignored for stat opens */
-                               FILE_CREATE,
-                               0,
-                               mod_unixmode,
-                               &info,
-                               &fsp);
+       status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               fname,                                  /* fname */
+               0,                                      /* create_file_flags */
+               FILE_READ_ATTRIBUTES,                   /* access_mask */
+               FILE_SHARE_NONE,                        /* share_access */
+               FILE_CREATE,                            /* create_disposition*/
+               FILE_DIRECTORY_FILE,                    /* create_options */
+               mod_unixmode,                           /* file_attributes */
+               0,                                      /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &fsp,                                   /* result */
+               &info,                                  /* pinfo */
+               psbuf);                                 /* psbuf */
 
         if (NT_STATUS_IS_OK(status)) {
                 close_file(req, fsp, NORMAL_CLOSE);
@@ -6359,17 +6453,25 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                (unsigned int)wire_open_mode,
                (unsigned int)unixmode ));
 
-       status = open_file_ntcreate(conn, req,
-                               fname,
-                               psbuf,
-                               access_mask,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
-                               create_disp,
-                               0,              /* no create options yet. */
-                               mod_unixmode,
-                               oplock_request,
-                               &info,
-                               &fsp);
+        status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               fname,                                  /* fname */
+               0,                                      /* create_file_flags */
+               access_mask,                            /* access_mask */
+               (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
+                   FILE_SHARE_DELETE),
+               create_disp,                            /* create_disposition*/
+               0,                                      /* create_options */
+               mod_unixmode,                           /* file_attributes */
+               oplock_request,                         /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &fsp,                                   /* result */
+               &info,                                  /* pinfo */
+               psbuf);                                 /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -6454,6 +6556,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
        uint16 flags = 0;
        char del = 1;
        int info = 0;
+       int create_options = 0;
        int i;
        struct share_mode_lock *lck = NULL;
 
@@ -6477,30 +6580,28 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
                fname));
 
        if (VALID_STAT_OF_DIR(*psbuf)) {
-               status = open_directory(conn, req,
-                                       fname,
-                                       psbuf,
-                                       DELETE_ACCESS,
-                                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
-                                       FILE_OPEN,
-                                       0,
-                                       FILE_FLAG_POSIX_SEMANTICS|0777,
-                                       &info,
-                                       &fsp);
-       } else {
-
-               status = open_file_ntcreate(conn, req,
-                               fname,
-                               psbuf,
-                               DELETE_ACCESS,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
-                               FILE_OPEN,
-                               0,
-                               FILE_FLAG_POSIX_SEMANTICS|0777,
-                               0, /* No oplock, but break existing ones. */
-                               &info,
-                               &fsp);
-       }
+               create_options |= FILE_DIRECTORY_FILE;
+       }
+
+        status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               fname,                                  /* fname */
+               0,                                      /* create_file_flags */
+               DELETE_ACCESS,                          /* access_mask */
+               (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
+                   FILE_SHARE_DELETE),
+               FILE_OPEN,                              /* create_disposition*/
+               create_options,                         /* create_options */
+               FILE_FLAG_POSIX_SEMANTICS|0777,         /* file_attributes */
+               0,                                      /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &fsp,                                   /* result */
+               &info,                                  /* pinfo */
+               psbuf);                                 /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -7269,8 +7370,8 @@ static void call_trans2ioctl(connection_struct *conn,
                return;
        }
 
-       if ((SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL)
-           && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+       if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
+           && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
                *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
                if (*ppdata == NULL) {
                        reply_nterror(req, NT_STATUS_NO_MEMORY);
@@ -7533,8 +7634,6 @@ void reply_trans2(struct smb_request *req)
        unsigned int psoff;
        unsigned int pscnt;
        unsigned int tran_call;
-       unsigned int size;
-       unsigned int av_size;
        struct trans_state *state;
        NTSTATUS result;
 
@@ -7551,8 +7650,6 @@ void reply_trans2(struct smb_request *req)
        psoff = SVAL(req->vwv+10, 0);
        pscnt = SVAL(req->vwv+9, 0);
        tran_call = SVAL(req->vwv+14, 0);
-       size = smb_len(req->inbuf) + 4;
-       av_size = smb_len(req->inbuf);
 
        result = allow_new_trans(conn->pending_trans, req->mid);
        if (!NT_STATUS_IS_OK(result)) {
@@ -7617,8 +7714,8 @@ void reply_trans2(struct smb_request *req)
                 */
                if ( (state->setup_count == 4)
                     && (tran_call == TRANSACT2_IOCTL)
-                    && (SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL)
-                    && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+                    && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
+                    && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
                        DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
                } else {
                        DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
@@ -7634,6 +7731,12 @@ void reply_trans2(struct smb_request *req)
                goto bad_param;
 
        if (state->total_data) {
+
+               if (trans_oob(state->total_data, 0, dscnt)
+                   || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) {
+                       goto bad_param;
+               }
+
                /* Can't use talloc here, the core routines do realloc on the
                 * params and data. */
                state->data = (char *)SMB_MALLOC(state->total_data);
@@ -7646,21 +7749,16 @@ void reply_trans2(struct smb_request *req)
                        return;
                }
 
-               if (dscnt > state->total_data ||
-                               dsoff+dscnt < dsoff) {
-                       goto bad_param;
-               }
-
-               if (dsoff > av_size ||
-                               dscnt > av_size ||
-                               dsoff+dscnt > av_size) {
-                       goto bad_param;
-               }
-
                memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
        }
 
        if (state->total_param) {
+
+               if (trans_oob(state->total_param, 0, pscnt)
+                   || trans_oob(smb_len(req->inbuf), psoff, pscnt)) {
+                       goto bad_param;
+               }
+
                /* Can't use talloc here, the core routines do realloc on the
                 * params and data. */
                state->param = (char *)SMB_MALLOC(state->total_param);
@@ -7674,17 +7772,6 @@ void reply_trans2(struct smb_request *req)
                        return;
                } 
 
-               if (pscnt > state->total_param ||
-                               psoff+pscnt < psoff) {
-                       goto bad_param;
-               }
-
-               if (psoff > av_size ||
-                               pscnt > av_size ||
-                               psoff+pscnt > av_size) {
-                       goto bad_param;
-               }
-
                memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
        }
 
@@ -7732,8 +7819,6 @@ void reply_transs2(struct smb_request *req)
        connection_struct *conn = req->conn;
        unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
        struct trans_state *state;
-       unsigned int size;
-       unsigned int av_size;
 
        START_PROFILE(SMBtranss2);
 
@@ -7745,9 +7830,6 @@ void reply_transs2(struct smb_request *req)
                return;
        }
 
-       size = smb_len(req->inbuf)+4;
-       av_size = smb_len(req->inbuf);
-
        for (state = conn->pending_trans; state != NULL;
             state = state->next) {
                if (state->mid == req->mid) {
@@ -7785,41 +7867,19 @@ void reply_transs2(struct smb_request *req)
                goto bad_param;
 
        if (pcnt) {
-               if (pdisp > state->total_param ||
-                               pcnt > state->total_param ||
-                               pdisp+pcnt > state->total_param ||
-                               pdisp+pcnt < pdisp) {
-                       goto bad_param;
-               }
-
-               if (poff > av_size ||
-                               pcnt > av_size ||
-                               poff+pcnt > av_size ||
-                               poff+pcnt < poff) {
+               if (trans_oob(state->total_param, pdisp, pcnt)
+                   || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
                        goto bad_param;
                }
-
-               memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,
-                      pcnt);
+               memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
        }
 
        if (dcnt) {
-               if (ddisp > state->total_data ||
-                               dcnt > state->total_data ||
-                               ddisp+dcnt > state->total_data ||
-                               ddisp+dcnt < ddisp) {
-                       goto bad_param;
-               }
-
-               if (ddisp > av_size ||
-                               dcnt > av_size ||
-                               ddisp+dcnt > av_size ||
-                               ddisp+dcnt < ddisp) {
+               if (trans_oob(state->total_data, ddisp, dcnt)
+                   || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
                        goto bad_param;
                }
-
-               memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,
-                      dcnt);      
+               memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
        }
 
        if ((state->received_param < state->total_param) ||