TALLOC_FREE happily lives with a NULL ptr. Tim, please check!
[ira/wip.git] / source3 / smbd / trans2.c
index 6c082a8273e64a59dbce0b75881a394cc07b84fb..1748cfa0b858ed29b01090c2a29561db100fcd67 100644 (file)
@@ -26,6 +26,7 @@
 #include "includes.h"
 #include "version.h"
 #include "smbd/globals.h"
+#include "../libcli/auth/libcli_auth.h"
 
 extern enum protocol_types Protocol;
 
@@ -832,7 +833,9 @@ void send_trans2_replies(connection_struct *conn,
                show_msg((char *)req->outbuf);
                if (!srv_send_smb(smbd_server_fd(),
                                (char *)req->outbuf,
-                               IS_CONN_ENCRYPTED(conn)))
+                               true, req->seqnum+1,
+                               IS_CONN_ENCRYPTED(conn),
+                               &req->pcd))
                        exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
 
                TALLOC_FREE(req->outbuf);
@@ -893,6 +896,8 @@ static void call_trans2open(connection_struct *conn,
        uint32 create_options = 0;
        TALLOC_CTX *ctx = talloc_tos();
 
+       SET_STAT_INVALID(sbuf);
+
        /*
         * Ensure we have enough parameters to perform the operation.
         */
@@ -1233,12 +1238,12 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                                int *last_entry_off,
                                struct ea_list *name_list)
 {
-       const char *dname;
+       char *dname;
        bool found = False;
        SMB_STRUCT_STAT sbuf;
        const char *mask = NULL;
        char *pathreal = NULL;
-       const char *fname = NULL;
+       char *fname = NULL;
        char *p, *q, *pdata = *ppdata;
        uint32 reskey=0;
        long prev_dirpos=0;
@@ -1314,9 +1319,13 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                /* Mangle fname if it's an illegal name. */
                if (mangle_must_mangle(dname,conn->params)) {
                        if (!name_to_8_3(dname,mangled_name,True,conn->params)) {
+                               TALLOC_FREE(fname);
                                continue; /* Error - couldn't mangle. */
                        }
-                       fname = mangled_name;
+                       fname = talloc_strdup(ctx, mangled_name);
+                       if (!fname) {
+                               return False;
+                       }
                }
 
                if(!(got_match = *got_exact_match = exact_match(conn, fname, mask))) {
@@ -1333,6 +1342,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                         */
                        /* Force the mangling into 8.3. */
                        if (!name_to_8_3( fname, mangled_name, False, conn->params)) {
+                               TALLOC_FREE(fname);
                                continue; /* Error - couldn't mangle. */
                        }
 
@@ -1345,6 +1355,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                        bool isdots = (ISDOT(dname) || ISDOTDOT(dname));
 
                        if (dont_descend && !isdots) {
+                               TALLOC_FREE(fname);
                                continue;
                        }
 
@@ -1362,6 +1373,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                        }
 
                        if (!pathreal) {
+                               TALLOC_FREE(fname);
                                return False;
                        }
 
@@ -1370,6 +1382,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                                        DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
                                                pathreal,strerror(errno)));
                                        TALLOC_FREE(pathreal);
+                                       TALLOC_FREE(fname);
                                        continue;
                                }
                        } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
@@ -1381,6 +1394,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                                        DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
                                                pathreal,strerror(errno)));
                                        TALLOC_FREE(pathreal);
+                                       TALLOC_FREE(fname);
                                        continue;
                                }
                        }
@@ -1394,6 +1408,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                        if (!dir_check_ftype(conn,mode,dirtype)) {
                                DEBUG(5,("get_lanman2_dir_entry: [%s] attribs didn't match %x\n",fname,dirtype));
                                TALLOC_FREE(pathreal);
+                               TALLOC_FREE(fname);
                                continue;
                        }
 
@@ -1435,6 +1450,9 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
 
                        dptr_DirCacheAdd(conn->dirptr, dname, curr_dirpos);
                }
+
+               if (!found)
+                       TALLOC_FREE(fname);
        }
 
        p = pdata;
@@ -1828,10 +1846,11 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                        break;
 
                default:
+                       TALLOC_FREE(fname);
                        return(False);
        }
 
-
+       TALLOC_FREE(fname);
        if (PTR_DIFF(p,pdata) > space_remaining) {
                /* Move the dirptr back to prev_dirpos */
                dptr_SeekDir(conn->dirptr, prev_dirpos);
@@ -1863,6 +1882,7 @@ static void call_trans2findfirst(connection_struct *conn,
                maxentries then so be it. We assume that the redirector has
                enough room for the fixed number of parameter bytes it has
                requested. */
+       struct smb_filename *smb_dname = NULL;
        char *params = *pparams;
        char *pdata = *ppdata;
        char *data_end;
@@ -1885,7 +1905,6 @@ static void call_trans2findfirst(connection_struct *conn,
        bool out_of_space = False;
        int space_remaining;
        bool mask_contains_wcard = False;
-       SMB_STRUCT_STAT sbuf;
        struct ea_list *ea_list = NULL;
        NTSTATUS ntstatus = NT_STATUS_OK;
        bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
@@ -1913,7 +1932,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                /* W2K3 seems to treat zero as 1. */
                maxentries = 1;
        }
+
        switch (info_level) {
                case SMB_FIND_INFO_STANDARD:
                case SMB_FIND_EA_SIZE:
@@ -1962,7 +1981,17 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                return;
        }
 
-       ntstatus = unix_convert(ctx, conn, directory, True, &directory, &mask, &sbuf);
+       ntstatus = unix_convert(ctx, conn, directory, &smb_dname,
+                               (UCF_SAVE_LCOMP | UCF_ALLOW_WCARD_LCOMP));
+       if (!NT_STATUS_IS_OK(ntstatus)) {
+               reply_nterror(req, ntstatus);
+               return;
+       }
+
+       mask = smb_dname->original_lcomp;
+
+       ntstatus = get_full_smb_filename(ctx, smb_dname, &directory);
+       TALLOC_FREE(smb_dname);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                reply_nterror(req, ntstatus);
                return;
@@ -2042,7 +2071,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        }
        params = *pparams;
 
-       /* Save the wildcard match and attribs we are using on this directory - 
+       /* Save the wildcard match and attribs we are using on this directory -
                needed as lanman2 assumes these are being saved between calls */
 
        ntstatus = dptr_create(conn,
@@ -2063,6 +2092,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        dptr_num = dptr_dnum(conn->dirptr);
        DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
 
+       /* Initialize per TRANS2_FIND_FIRST operation data */
+       dptr_init_search_op(conn->dirptr);
+
        /* We don't need to check for VOL here as this is returned by
                a different TRANS2 call. */
 
@@ -2077,7 +2109,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
                bool got_exact_match = False;
 
-               /* this is a heuristic to avoid seeking the dirptr except when 
+               /* this is a heuristic to avoid seeking the dirptr except when
                        absolutely necessary. It allows for a filename of about 40 chars */
                if (space_remaining < DIRLEN_GUESS && numentries > 0) {
                        out_of_space = True;
@@ -2373,6 +2405,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                (long)conn->dirptr,
                dptr_TellDir(conn->dirptr)));
 
+       /* Initialize per TRANS2_FIND_NEXT operation data */
+       dptr_init_search_op(conn->dirptr);
+
        /* We don't need to check for VOL here as this is returned by
                a different TRANS2 call. */
 
@@ -2885,8 +2920,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                case SMB_QUERY_CIFS_UNIX_INFO:
                {
                        bool large_write = lp_min_receive_file_size() &&
-                                               !srv_is_signing_active();
-                       bool large_read = !srv_is_signing_active();
+                                       !srv_is_signing_active(smbd_server_conn);
+                       bool large_read = !srv_is_signing_active(smbd_server_conn);
                        int encrypt_caps = 0;
 
                        if (!lp_unix_extensions()) {
@@ -3809,6 +3844,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
        SMB_STRUCT_STAT sbuf;
        char *dos_fname = NULL;
        char *fname = NULL;
+       struct smb_filename *smb_fname = NULL;
        char *fullpathname;
        char *base_name;
        char *p;
@@ -3956,11 +3992,20 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                        return;
                }
 
-               status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
+               status = unix_convert(ctx, conn, fname, &smb_fname, 0);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+               sbuf = smb_fname->st;
+
+               status = get_full_smb_filename(ctx, smb_fname, &fname);
+               TALLOC_FREE(smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
                }
+
                status = check_name(conn, fname);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status)));
@@ -4796,57 +4841,64 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
                const char *oldname_in,
                const char *newname_in)
 {
-       SMB_STRUCT_STAT sbuf1, sbuf2;
-       char *last_component_oldname = NULL;
-       char *last_component_newname = NULL;
+       struct smb_filename *smb_fname = NULL;
+       struct smb_filename *smb_fname_new = NULL;
        char *oldname = NULL;
        char *newname = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       ZERO_STRUCT(sbuf1);
-       ZERO_STRUCT(sbuf2);
+       status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
 
-       status = unix_convert(ctx, conn, oldname_in, False, &oldname,
-                       &last_component_oldname, &sbuf1);
+       status = get_full_smb_filename(ctx, smb_fname, &oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        status = check_name(conn, oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        /* source must already exist. */
-       if (!VALID_STAT(sbuf1)) {
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       if (!VALID_STAT(smb_fname->st)) {
+               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, newname_in, False, &newname,
-                       &last_component_newname, &sbuf2);
+       status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname_new, &newname);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
 
        status = check_name(conn, newname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        /* Disallow if newname already exists. */
-       if (VALID_STAT(sbuf2)) {
-               return NT_STATUS_OBJECT_NAME_COLLISION;
+       if (VALID_STAT(smb_fname_new->st)) {
+               status = NT_STATUS_OBJECT_NAME_COLLISION;
+               goto out;
        }
 
        /* No links from a directory. */
-       if (S_ISDIR(sbuf1.st_mode)) {
-               return NT_STATUS_FILE_IS_A_DIRECTORY;
+       if (S_ISDIR(smb_fname->st.st_mode)) {
+               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+               goto out;
        }
 
        /* Ensure this is within the share. */
        status = check_reduced_name(conn, oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname ));
@@ -4854,9 +4906,11 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
        if (SMB_VFS_LINK(conn,oldname,newname) != 0) {
                status = map_nt_error_from_unix(errno);
                DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
-                                nt_errstr(status), newname, oldname));
+                                nt_errstr(status), newname, oldname));
        }
-
+ out:
+       TALLOC_FREE(smb_fname);
+       TALLOC_FREE(smb_fname_new);
        return status;
 }
 
@@ -4965,6 +5019,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
 ****************************************************************************/
 
 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
+                               files_struct *fsp,
                                const char *fname,
                                SMB_STRUCT_STAT *psbuf,
                                uint32 dosmode)
@@ -4973,6 +5028,14 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
+       if (fsp) {
+               if (fsp->base_fsp) {
+                       fname = fsp->base_fsp->fsp_name;
+               } else {
+                       fname = fsp->fsp_name;
+               }
+       }
+               
        if (dosmode) {
                if (S_ISDIR(psbuf->st_mode)) {
                        dosmode |= aDIR;
@@ -5348,9 +5411,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
        uint32 len;
        char *newname = NULL;
        char *base_name = NULL;
+       struct smb_filename *smb_fname = NULL;
        bool dest_has_wcard = False;
-       SMB_STRUCT_STAT sbuf;
-       char *newname_last_component = NULL;
        NTSTATUS status = NT_STATUS_OK;
        char *p;
        TALLOC_CTX *ctx = talloc_tos();
@@ -5359,8 +5421,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       ZERO_STRUCT(sbuf);
-
        overwrite = (CVAL(pdata,0) ? True : False);
        root_fid = IVAL(pdata,4);
        len = IVAL(pdata,8);
@@ -5432,10 +5492,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                        return NT_STATUS_NO_MEMORY;
                }
 
-               status = unix_convert(ctx, conn, newname, False,
-                               &newname,
-                               &newname_last_component,
-                               &sbuf);
+               status = unix_convert(ctx, conn, newname, &smb_fname,
+                                     UCF_SAVE_LCOMP);
 
                /* If an error we expect this to be
                 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
@@ -5443,7 +5501,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                if (!NT_STATUS_IS_OK(status)
                    && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
                                        status)) {
-                       return status;
+                       goto out;
                }
        }
 
@@ -5451,8 +5509,9 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
                        fsp->fnum, fsp->fsp_name, base_name ));
                status = rename_internals_fsp(conn, fsp, base_name,
-                                             newname_last_component, 0,
-                                             overwrite);
+                                             smb_fname ?
+                                             smb_fname->original_lcomp : NULL,
+                                             0, overwrite);
        } else {
                DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
                        fname, base_name ));
@@ -5460,7 +5519,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                                        overwrite, False, dest_has_wcard,
                                        FILE_WRITE_ATTRIBUTES);
        }
-
+ out:
+       TALLOC_FREE(smb_fname);
        return status;
 }
 
@@ -5621,7 +5681,8 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
                                                        POSIX_LOCK,
                                                        blocking_lock,
                                                        &status,
-                                                       &block_smbpid);
+                                                       &block_smbpid,
+                                                       NULL);
 
                if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
                        /*
@@ -5715,12 +5776,11 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
 
        /* Set the attributes */
        dosmode = IVAL(pdata,32);
-       status = smb_set_file_dosmode(conn, fname, psbuf, dosmode);
+       status = smb_set_file_dosmode(conn, fsp, fname, psbuf, dosmode);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-
        /* access time */
        ft.atime = interpret_long_date(pdata+8);
 
@@ -6407,6 +6467,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                create_disp = FILE_OVERWRITE_IF;
        } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
                create_disp = FILE_OPEN_IF;
+       } else if ((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL | SMB_O_TRUNC)) == 0) {
+               create_disp = FILE_OPEN;
        } else {
                DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
                        (unsigned int)wire_open_mode ));
@@ -6453,7 +6515,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
                    FILE_SHARE_DELETE),
                create_disp,                            /* create_disposition*/
-               0,                                      /* create_options */
+               FILE_NON_DIRECTORY_FILE,                /* create_options */
                mod_unixmode,                           /* file_attributes */
                oplock_request,                         /* oplock_request */
                0,                                      /* allocation_size */
@@ -6664,6 +6726,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
        uint16 info_level;
        SMB_STRUCT_STAT sbuf;
        char *fname = NULL;
+       struct smb_filename *smb_fname = NULL;
        files_struct *fsp = NULL;
        NTSTATUS status = NT_STATUS_OK;
        int data_return_size = 0;
@@ -6778,8 +6841,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                        return;
                }
 
-               status = unix_convert(ctx, conn, fname, False,
-                               &fname, NULL, &sbuf);
+               status = unix_convert(ctx, conn, fname, &smb_fname, 0);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+               sbuf = smb_fname->st;
+
+               status = get_full_smb_filename(ctx, smb_fname, &fname);
+               TALLOC_FREE(smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
@@ -7093,10 +7163,10 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
                             char **ppdata, int total_data,
                             unsigned int max_data_bytes)
 {
+       struct smb_filename *smb_dname = NULL;
        char *params = *pparams;
        char *pdata = *ppdata;
        char *directory = NULL;
-       SMB_STRUCT_STAT sbuf;
        NTSTATUS status = NT_STATUS_OK;
        struct ea_list *ea_list = NULL;
        TALLOC_CTX *ctx = talloc_tos();
@@ -7121,7 +7191,13 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
 
        DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
 
-       status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
+       status = unix_convert(ctx, conn, directory, &smb_dname, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               return;
+       }
+
+       status = get_full_smb_filename(ctx, smb_dname, &directory);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
@@ -7468,6 +7544,8 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req,
                }
        }
 
+       SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
+
        /* Now we must call the relevant TRANS2 function */
        switch(state->call)  {
        case TRANSACT2_OPEN: