X-Git-Url: http://git.samba.org/?p=amitay%2Fsamba.git;a=blobdiff_plain;f=source3%2Fsmbd%2Ftrans2.c;h=65c50336f6f179ab915574a8a0c5ac00b7a9e2c5;hp=9a2ae9b2f47f99d8150d53b6ab3844b1b46a08f7;hb=49ec754fca7beaacb852facc6cfecdfedbc89e45;hpb=df5752ec90d2b648b221887840262acf8fe43ef6 diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 9a2ae9b2f47..65c50336f6f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -26,6 +26,7 @@ #include "includes.h" #include "ntioctl.h" #include "system/filesys.h" +#include "lib/util/time_basic.h" #include "version.h" #include "smbd/smbd.h" #include "smbd/globals.h" @@ -41,6 +42,8 @@ #include "lib/util_ea.h" #include "lib/readdir_attr.h" #include "messages.h" +#include "smb1_utils.h" +#include "libcli/smb/smb2_posix.h" #define DIR_ENTRY_SAFETY_MARGIN 4096 @@ -116,11 +119,13 @@ static NTSTATUS get_posix_fsp(connection_struct *conn, uint32_t share_access = FILE_SHARE_READ| FILE_SHARE_WRITE| FILE_SHARE_DELETE; + struct smb2_create_blobs *posx = NULL; + /* * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files, * but set reasonable defaults. */ - uint32_t file_attributes = 0664|FILE_FLAG_POSIX_SEMANTICS; + uint32_t file_attributes = 0664; uint32_t oplock = NO_OPLOCK; uint32_t create_options = FILE_NON_DIRECTORY_FILE; @@ -138,7 +143,7 @@ static NTSTATUS get_posix_fsp(connection_struct *conn, * Only FILE_FLAG_POSIX_SEMANTICS matters on existing * directories, but set reasonable defaults. */ - file_attributes = 0775|FILE_FLAG_POSIX_SEMANTICS; + file_attributes = 0775; create_options = FILE_DIRECTORY_FILE; } @@ -146,7 +151,16 @@ static NTSTATUS get_posix_fsp(connection_struct *conn, smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname); if (smb_fname_tmp == NULL) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto done; + } + + status = make_smb2_posix_create_ctx( + talloc_tos(), &posx, file_attributes); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n", + nt_errstr(status)); + goto done; } status = SMB_VFS_CREATE_FILE( @@ -167,33 +181,31 @@ static NTSTATUS get_posix_fsp(connection_struct *conn, NULL, /* ea_list */ ret_fsp, /* result */ NULL, /* pinfo */ - NULL, /* in_context */ + posx, /* in_context */ NULL); /* out_context */ +done: + TALLOC_FREE(posx); TALLOC_FREE(smb_fname_tmp); return status; } #endif /******************************************************************** - The canonical "check access" based on object handle or path function. + The canonical "check access" based on path. ********************************************************************/ static NTSTATUS check_access(connection_struct *conn, - files_struct *fsp, - const struct smb_filename *smb_fname, - uint32_t access_mask) + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + uint32_t access_mask) { - NTSTATUS status; - - if (fsp) { - status = check_access_fsp(fsp, access_mask); - } else { - status = smbd_check_access_rights(conn, smb_fname, - false, access_mask); - } - - return status; + SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp); + return smbd_check_access_rights(conn, + dirfsp, + smb_fname, + false, + access_mask); } /******************************************************************** @@ -213,16 +225,6 @@ uint64_t smb_roundup(connection_struct *conn, uint64_t val) return val; } -/******************************************************************** - Globally (for this connection / multi-channel) disable file-ID - calculation. This is required to be global because it serves - Macs in AAPL mode, which is globally set. -********************************************************************/ -void aapl_force_zero_file_id(struct smbd_server_connection *sconn) -{ - sconn->aapl_zero_file_id = true; -} - /**************************************************************************** Utility functions for dealing with extended attributes. ****************************************************************************/ @@ -814,7 +816,14 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, return status; } - status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA); + if (fsp != NULL) { + status = check_access_fsp(fsp, FILE_WRITE_EA); + } else { + status = check_access(conn, + conn->cwd_fsp, + smb_fname, + FILE_WRITE_EA); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1450,8 +1459,28 @@ static void call_trans2open(connection_struct *conn, /* We have re-scheduled this call. */ goto out; } - reply_openerror(req, status); - goto out; + + if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) { + reply_openerror(req, status); + goto out; + } + + fsp = fcb_or_dos_open( + req, + smb_fname, + access_mask, + create_options, + private_flags); + if (fsp == NULL) { + bool ok = defer_smb1_sharing_violation(req); + if (ok) { + goto out; + } + reply_openerror(req, status); + goto out; + } + + smb_action = FILE_WAS_OPENED; } size = get_file_size_stat(&smb_fname->st); @@ -1571,13 +1600,11 @@ static uint32_t unix_filetype(mode_t mode) Map wire perms onto standard UNIX permissions. Obey share restrictions. ****************************************************************************/ -enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR}; - -static NTSTATUS unix_perms_from_wire( connection_struct *conn, - const SMB_STRUCT_STAT *psbuf, - uint32_t perms, - enum perm_type ptype, - mode_t *ret_perms) +NTSTATUS unix_perms_from_wire(connection_struct *conn, + const SMB_STRUCT_STAT *psbuf, + uint32_t perms, + enum perm_type ptype, + mode_t *ret_perms) { mode_t ret = 0; @@ -2047,10 +2074,10 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx, was_8_3 = mangle_is_8_3(fname, True, conn->params); p += 4; SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8; SOFF_T(p,0,file_size); p += 8; SOFF_T(p,0,allocation_size); p += 8; SIVAL(p,0,mode); p += 4; @@ -2121,10 +2148,10 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx, DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n")); p += 4; SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8; SOFF_T(p,0,file_size); p += 8; SOFF_T(p,0,allocation_size); p += 8; SIVAL(p,0,mode); p += 4; @@ -2160,10 +2187,10 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx, DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n")); p += 4; SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8; SOFF_T(p,0,file_size); p += 8; SOFF_T(p,0,allocation_size); p += 8; SIVAL(p,0,mode); p += 4; @@ -2243,10 +2270,10 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx, DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n")); p += 4; SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8; SOFF_T(p,0,file_size); p += 8; SOFF_T(p,0,allocation_size); p += 8; SIVAL(p,0,mode); p += 4; @@ -2294,10 +2321,10 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx, was_8_3 = mangle_is_8_3(fname, True, conn->params); p += 4; SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8; + put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8; SOFF_T(p,0,file_size); p += 8; SOFF_T(p,0,allocation_size); p += 8; SIVAL(p,0,mode); p += 4; @@ -2703,13 +2730,16 @@ static void call_trans2findfirst(connection_struct *conn, bool mask_contains_wcard = False; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); - struct dptr_struct *dirptr = NULL; + bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn)); struct smbd_server_connection *sconn = req->sconn; - uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP | + uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP | ucf_flags_from_smb_request(req); bool backup_priv = false; bool as_root = false; + files_struct *fsp = NULL; + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + int ret; if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2820,7 +2850,14 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da goto out; } - mask = smb_dname->original_lcomp; + mask = get_original_lcomp(talloc_tos(), + conn, + directory, + ucf_flags); + if (mask == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + goto out; + } directory = smb_dname->base_name; @@ -2907,22 +2944,78 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } params = *pparams; + /* + * As we've cut off the last component from + * smb_fname we need to re-stat smb_dname + * so FILE_OPEN disposition knows the directory + * exists. + */ + if (req->posix_pathnames) { + ret = SMB_VFS_LSTAT(conn, smb_dname); + } else { + ret = SMB_VFS_STAT(conn, smb_dname); + } + + if (ret == -1) { + ntstatus = map_nt_error_from_unix(errno); + reply_nterror(req, ntstatus); + goto out; + } + + /* + * Open an fsp on this directory for the dptr. + */ + ntstatus = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + smb_dname, /* dname */ + FILE_LIST_DIRECTORY, /* access_mask */ + FILE_SHARE_READ| + FILE_SHARE_WRITE, /* share_access */ + FILE_OPEN, /* create_disposition*/ + FILE_DIRECTORY_FILE, /* create_options */ + FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */ + NO_OPLOCK, /* oplock_request */ + NULL, /* lease */ + 0, /* allocation_size */ + 0, /* private_flags */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp, /* result */ + NULL, /* pinfo */ + NULL, /* in_context */ + NULL);/* out_context */ + + if (!NT_STATUS_IS_OK(ntstatus)) { + DBG_ERR("failed to open directory %s\n", + smb_fname_str_dbg(smb_dname)); + reply_nterror(req, ntstatus); + goto out; + } + /* 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, req, - NULL, /* fsp */ - smb_dname, + fsp, /* fsp */ False, True, req->smbpid, mask, mask_contains_wcard, dirtype, - &dirptr); + &fsp->dptr); if (!NT_STATUS_IS_OK(ntstatus)) { + /* + * Use NULL here for the first parameter (req) + * as this is not a client visible handle so + * can'tbe part of an SMB1 chain. + */ + close_file(NULL, fsp, NORMAL_CLOSE); + fsp = NULL; reply_nterror(req, ntstatus); goto out; } @@ -2930,19 +3023,19 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (backup_priv) { /* Remember this in case we have to do a findnext. */ - dptr_set_priv(dirptr); + dptr_set_priv(fsp->dptr); } - dptr_num = dptr_dnum(dirptr); + dptr_num = dptr_dnum(fsp->dptr); DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype)); /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - directory,lp_dont_descend(talloc_tos(), SNUM(conn)))); + directory,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)))); if (in_list(directory, - lp_dont_descend(talloc_tos(), SNUM(conn)), + lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)), conn->case_sensitive)) { dont_descend = True; } @@ -2962,7 +3055,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } else { ntstatus = get_lanman2_dir_entry(talloc_tos(), conn, - dirptr, + fsp->dptr, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, @@ -3011,7 +3104,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Check if we can close the dirptr */ if(close_after_first || (finished && close_if_end)) { DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); - dptr_close(sconn, &dptr_num); + dptr_num = -1; + close_file(NULL, fsp, NORMAL_CLOSE); + fsp = NULL; } /* @@ -3022,7 +3117,15 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd */ if(numentries == 0) { - dptr_close(sconn, &dptr_num); + dptr_num = -1; + /* + * We may have already closed the file in the + * close_after_first or finished case above. + */ + if (fsp != NULL) { + close_file(NULL, fsp, NORMAL_CLOSE); + fsp = NULL; + } if (get_Protocol() < PROTOCOL_NT1) { reply_force_doserror(req, ERRDOS, ERRnofiles); goto out; @@ -3119,12 +3222,14 @@ static void call_trans2findnext(connection_struct *conn, int space_remaining; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); + bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn)); TALLOC_CTX *ctx = talloc_tos(); - struct dptr_struct *dirptr; struct smbd_server_connection *sconn = req->sconn; bool backup_priv = false; bool as_root = false; + files_struct *fsp = NULL; + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -3277,7 +3382,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd params = *pparams; /* Check that the dptr is valid */ - if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) { + fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num); + if (fsp == NULL) { reply_nterror(req, STATUS_NO_MORE_FILES); return; } @@ -3294,21 +3400,21 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Get the attr mask from the dptr */ dirtype = dptr_attr(sconn, dptr_num); - backup_priv = dptr_get_priv(dirptr); + backup_priv = dptr_get_priv(fsp->dptr); DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld) " "backup_priv = %d\n", dptr_num, mask, dirtype, - (long)dirptr, - dptr_TellDir(dirptr), + (long)fsp->dptr, + dptr_TellDir(fsp->dptr), (int)backup_priv)); /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - directory,lp_dont_descend(ctx, SNUM(conn)))); - if (in_list(directory,lp_dont_descend(ctx, SNUM(conn)),conn->case_sensitive)) + directory,lp_dont_descend(ctx, lp_sub, SNUM(conn)))); + if (in_list(directory,lp_dont_descend(ctx, lp_sub, SNUM(conn)),conn->case_sensitive)) dont_descend = True; p = pdata; @@ -3355,13 +3461,13 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd * should already be at the correct place. */ - finished = !dptr_SearchDir(dirptr, resume_name, ¤t_pos, &st); + finished = !dptr_SearchDir(fsp->dptr, resume_name, ¤t_pos, &st); } /* end if resume_name && !continue_bit */ for (i=0;(i<(int)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 fsp->dptr except when absolutely necessary. It allows for a filename of about 40 chars */ if (space_remaining < DIRLEN_GUESS && numentries > 0) { out_of_space = True; @@ -3369,7 +3475,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } else { ntstatus = get_lanman2_dir_entry(ctx, conn, - dirptr, + fsp->dptr, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, @@ -3413,10 +3519,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd smb_fn_name(req->cmd), mask, directory, dirtype, numentries ) ); - /* Check if we can close the dirptr */ + /* Check if we can close the fsp->dptr */ if(close_after_request || (finished && close_if_end)) { DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); - dptr_close(sconn, &dptr_num); /* This frees up the saved mask */ + dptr_num = -1; + close_file(NULL, fsp, NORMAL_CLOSE); + fsp = NULL; } if (as_root) { @@ -3437,7 +3545,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16]) { - E_md4hash(lp_servicename(talloc_tos(), SNUM(conn)),objid); + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + + E_md4hash(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),objid); return objid; } @@ -3487,6 +3598,8 @@ NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn, char **ppdata, int *ret_data_len) { + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); char *pdata, *end_data; int data_len = 0; size_t len = 0; @@ -3595,7 +3708,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u * Add volume serial number - hash of a combination of * the called hostname and the service name. */ - SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), snum)) ^ (str_checksum(get_local_machine_name())<<16) ); + SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^ (str_checksum(get_local_machine_name())<<16) ); /* * Win2k3 and previous mess this up by sending a name length * one byte short. I believe only older clients (OS/2 Win9x) use @@ -3677,7 +3790,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u * Add volume serial number - hash of a combination of * the called hostname and the service name. */ - SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), snum)) ^ + SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^ (str_checksum(get_local_machine_name())<<16)); /* Max label len is 32 characters. */ @@ -3692,7 +3805,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", (int)strlen(vname),vname, - lp_servicename(talloc_tos(), snum))); + lp_servicename(talloc_tos(), lp_sub, snum))); if (max_data_bytes >= 24 && data_len > max_data_bytes) { /* the client only requested a portion of the volume label */ @@ -3825,7 +3938,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned if (get_current_uid(conn) != 0) { DEBUG(0,("get_user_quota: access_denied " "service [%s] user [%s]\n", - lp_servicename(talloc_tos(), SNUM(conn)), + lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), conn->session_info->unix_info->unix_name)); return NT_STATUS_ACCESS_DENIED; } @@ -3833,14 +3946,14 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned status = vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn)))); + DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))); return status; } data_len = 48; DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n", - lp_servicename(talloc_tos(), SNUM(conn)))); + lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))); /* Unknown1 24 NULL bytes*/ SBIG_UINT(pdata,0,(uint64_t)0); @@ -3986,7 +4099,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned return NT_STATUS_INVALID_LEVEL; #endif /* EOPNOTSUPP */ } else { - DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn)))); + DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))); return NT_STATUS_DOS(ERRSRV, ERRerror); } break; @@ -4117,6 +4230,8 @@ static NTSTATUS smb_set_fsquota(connection_struct *conn, files_struct *fsp, const DATA_BLOB *qdata) { + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); NTSTATUS status; SMB_NTQUOTA_STRUCT quotas; @@ -4125,7 +4240,7 @@ static NTSTATUS smb_set_fsquota(connection_struct *conn, /* access check */ if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) { DEBUG(3, ("set_fsquota: access_denied service [%s] user [%s]\n", - lp_servicename(talloc_tos(), SNUM(conn)), + lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), conn->session_info->unix_info->unix_name)); return NT_STATUS_ACCESS_DENIED; } @@ -4162,7 +4277,7 @@ static NTSTATUS smb_set_fsquota(connection_struct *conn, /* now set the quotas */ if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { DEBUG(1, ("vfs_set_ntquota() failed for service [%s]\n", - lp_servicename(talloc_tos(), SNUM(conn)))); + lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))); status = map_nt_error_from_unix(errno); } else { status = NT_STATUS_OK; @@ -4258,13 +4373,15 @@ static void call_trans2setfsinfo(connection_struct *conn, char **ppdata, int total_data, unsigned int max_data_bytes) { + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); struct smbXsrv_connection *xconn = req->xconn; char *pdata = *ppdata; char *params = *pparams; uint16_t info_level; DEBUG(10,("call_trans2setfsinfo: for service [%s]\n", - lp_servicename(talloc_tos(), SNUM(conn)))); + lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))); /* */ if (total_params < 4) { @@ -4591,9 +4708,9 @@ static char *store_file_unix_basic(connection_struct *conn, SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */ pdata += 8; - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */ - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */ - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */ + put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, &psbuf->st_ex_ctime); /* Change Time 64 Bit */ + put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, &psbuf->st_ex_atime); /* Last access time 64 Bit */ + put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, &psbuf->st_ex_mtime); /* Last modification time 64 Bit */ pdata += 24; SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */ @@ -4733,7 +4850,7 @@ static char *store_file_unix_basic_info2(connection_struct *conn, pdata = store_file_unix_basic(conn, pdata, fsp, psbuf); /* Create (birth) time 64 bit */ - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime); + put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, &psbuf->st_ex_btime); pdata += 8; map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask); @@ -4841,7 +4958,7 @@ static NTSTATUS smb_query_posix_acl(connection_struct *conn, unsigned int size_needed = 0; NTSTATUS status; bool ok; - bool close_fsp; + bool close_fsp = false; /* * Ensure we always operate on a file descriptor, not just @@ -4889,7 +5006,7 @@ static NTSTATUS smb_query_posix_acl(connection_struct *conn, * We can only have default POSIX ACLs on * directories. */ - if (!fsp->is_directory) { + if (!fsp->fsp_flags.is_directory) { DBG_INFO("Non-directory open %s\n", fsp_str_dbg(fsp)); status = NT_STATUS_INVALID_HANDLE; @@ -5126,7 +5243,9 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, dstart = pdata; dend = dstart + data_size - 1; - if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) { + if (!is_omit_timespec(&write_time_ts) && + !INFO_LEVEL_IS_UNIX(info_level)) + { update_stat_ex_mtime(psbuf, write_time_ts); } @@ -5348,10 +5467,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, data_size = 40; SIVAL(pdata,36,0); } - put_long_date_timespec(conn->ts_res,pdata,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ + put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts); + put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts); + put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */ + put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */ SIVAL(pdata,32,mode); DEBUG(5,("SMB_QFBI - ")); @@ -5434,7 +5553,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, { char *nfname = NULL; - if (!fsp->conn->sconn->using_smb2) { + if (fsp == NULL || !fsp->conn->sconn->using_smb2) { return NT_STATUS_INVALID_LEVEL; } @@ -5507,10 +5626,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, unsigned int ea_size = estimate_ea_size(conn, fsp, smb_fname); DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n")); - put_long_date_timespec(conn->ts_res,pdata,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ + put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts); + put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts); + put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */ + put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */ SIVAL(pdata,32,mode); SIVAL(pdata,36,0); /* padding. */ pdata += 40; @@ -5542,10 +5661,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, unsigned int ea_size = estimate_ea_size(conn, fsp, smb_fname); DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n")); - put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */ + put_long_date_full_timespec(conn->ts_res,pdata+0x00,&create_time_ts); + put_long_date_full_timespec(conn->ts_res,pdata+0x08,&atime_ts); + put_long_date_full_timespec(conn->ts_res,pdata+0x10,&mtime_ts); /* write time */ + put_long_date_full_timespec(conn->ts_res,pdata+0x18,&ctime_ts); /* change time */ SIVAL(pdata, 0x20, mode); SIVAL(pdata, 0x24, 0); /* padding. */ SBVAL(pdata, 0x28, allocation_size); @@ -5692,10 +5811,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_FILE_NETWORK_OPEN_INFORMATION: DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n")); - put_long_date_timespec(conn->ts_res,pdata,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ + put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts); + put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts); + put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */ + put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */ SOFF_T(pdata,32,allocation_size); SOFF_T(pdata,40,file_size); SIVAL(pdata,48,mode); @@ -5760,9 +5879,12 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, #else return NT_STATUS_DOS(ERRDOS, ERRbadlink); #endif - link_len = SMB_VFS_READLINK(conn, - smb_fname, - buffer, PATH_MAX); + link_len = SMB_VFS_READLINKAT(conn, + conn->cwd_fsp, + smb_fname, + buffer, + PATH_MAX); + if (link_len == -1) { return map_nt_error_from_unix(errno); } @@ -6294,6 +6416,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* We have re-scheduled this call. */ return; } + if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) { + bool ok = defer_smb1_sharing_violation(req); + if (ok) { + return; + } + } reply_nterror(req, status); return; } @@ -6321,6 +6449,7 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, struct smb_filename *smb_fname_new) { NTSTATUS status = NT_STATUS_OK; + int ret; bool ok; /* source must already exist. */ @@ -6367,7 +6496,14 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", smb_fname_old->base_name, smb_fname_new->base_name)); - if (SMB_VFS_LINK(conn, smb_fname_old, smb_fname_new) != 0) { + ret = SMB_VFS_LINKAT(conn, + conn->cwd_fsp, + smb_fname_old, + conn->cwd_fsp, + smb_fname_new, + 0); + + if (ret != 0) { status = map_nt_error_from_unix(errno); DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n", nt_errstr(status), smb_fname_old->base_name, @@ -6389,6 +6525,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn, bool setting_write_time) { struct smb_filename smb_fname_base; + struct timeval_buf tbuf[4]; uint32_t action = FILE_NOTIFY_CHANGE_LAST_ACCESS |FILE_NOTIFY_CHANGE_LAST_WRITE @@ -6399,15 +6536,15 @@ NTSTATUS smb_set_file_time(connection_struct *conn, } /* get some defaults (no modifications) if any info is zero or -1. */ - if (null_timespec(ft->create_time)) { + if (is_omit_timespec(&ft->create_time)) { action &= ~FILE_NOTIFY_CHANGE_CREATION; } - if (null_timespec(ft->atime)) { + if (is_omit_timespec(&ft->atime)) { action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; } - if (null_timespec(ft->mtime)) { + if (is_omit_timespec(&ft->mtime)) { action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } @@ -6424,14 +6561,14 @@ NTSTATUS smb_set_file_time(connection_struct *conn, round_timespec(conn->ts_res, &ft->atime); round_timespec(conn->ts_res, &ft->mtime); - DEBUG(5,("smb_set_filetime: actime: %s\n ", - time_to_asc(convert_timespec_to_time_t(ft->atime)))); - DEBUG(5,("smb_set_filetime: modtime: %s\n ", - time_to_asc(convert_timespec_to_time_t(ft->mtime)))); - DEBUG(5,("smb_set_filetime: ctime: %s\n ", - time_to_asc(convert_timespec_to_time_t(ft->ctime)))); - DEBUG(5,("smb_set_file_time: createtime: %s\n ", - time_to_asc(convert_timespec_to_time_t(ft->create_time)))); + DBG_DEBUG("smb_set_filetime: actime: %s\n ", + timespec_string_buf(&ft->atime, true, &tbuf[0])); + DBG_DEBUG("smb_set_filetime: modtime: %s\n ", + timespec_string_buf(&ft->mtime, true, &tbuf[1])); + DBG_DEBUG("smb_set_filetime: ctime: %s\n ", + timespec_string_buf(&ft->ctime, true, &tbuf[2])); + DBG_DEBUG("smb_set_file_time: createtime: %s\n ", + timespec_string_buf(&ft->create_time, true, &tbuf[3])); if (setting_write_time) { /* @@ -6444,8 +6581,8 @@ NTSTATUS smb_set_file_time(connection_struct *conn, * away and will set it on file close and after a write. JRA. */ - DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", - time_to_asc(convert_timespec_to_time_t(ft->mtime)))); + DBG_DEBUG("setting pending modtime to %s\n", + timespec_string_buf(&ft->mtime, true, &tbuf[0])); if (fsp != NULL) { if (fsp->base_fsp) { @@ -6560,6 +6697,13 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, get_file_size_stat(psbuf)); if (size == get_file_size_stat(psbuf)) { + if (fsp == NULL) { + return NT_STATUS_OK; + } + if (!fsp->fsp_flags.modified) { + return NT_STATUS_OK; + } + trigger_write_time_update_immediate(fsp); return NT_STATUS_OK; } @@ -6832,6 +6976,7 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, { char *link_target = NULL; TALLOC_CTX *ctx = talloc_tos(); + int ret; /* Set a symbolic link. */ /* Don't allow this if follow links is false. */ @@ -6854,7 +6999,11 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", new_smb_fname->base_name, link_target )); - if (SMB_VFS_SYMLINK(conn,link_target,new_smb_fname) != 0) { + ret = SMB_VFS_SYMLINKAT(conn, + link_target, + conn->cwd_fsp, + new_smb_fname); + if (ret != 0) { return map_nt_error_from_unix(errno); } @@ -6937,8 +7086,8 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, uint32_t len; char *newname = NULL; struct smb_filename *smb_fname_dst = NULL; - uint32_t ucf_flags = UCF_SAVE_LCOMP | - ucf_flags_from_smb_request(req); + const char *dst_original_lcomp = NULL; + uint32_t ucf_flags = ucf_flags_from_smb_request(req); NTSTATUS status = NT_STATUS_OK; TALLOC_CTX *ctx = talloc_tos(); @@ -7010,25 +7159,29 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, status = NT_STATUS_NO_MEMORY; goto out; } + } - /* - * Set the original last component, since - * rename_internals_fsp() requires it. - */ - smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst, - newname); - if (smb_fname_dst->original_lcomp == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - + /* + * Set the original last component, since + * rename_internals_fsp() requires it. + */ + dst_original_lcomp = get_original_lcomp(smb_fname_dst, + conn, + newname, + ucf_flags); + if (dst_original_lcomp == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; } DEBUG(10,("smb2_file_rename_information: " "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n", fsp_fnum_dbg(fsp), fsp_str_dbg(fsp), smb_fname_str_dbg(smb_fname_dst))); - status = rename_internals_fsp(conn, fsp, smb_fname_dst, + status = rename_internals_fsp(conn, + fsp, + smb_fname_dst, + dst_original_lcomp, (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM), overwrite); @@ -7049,8 +7202,7 @@ static NTSTATUS smb_file_link_information(connection_struct *conn, char *newname = NULL; struct smb_filename *smb_fname_dst = NULL; NTSTATUS status = NT_STATUS_OK; - uint32_t ucf_flags = UCF_SAVE_LCOMP | - ucf_flags_from_smb_request(req); + uint32_t ucf_flags = ucf_flags_from_smb_request(req); TALLOC_CTX *ctx = talloc_tos(); if (!fsp) { @@ -7142,6 +7294,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, uint32_t len; char *newname = NULL; struct smb_filename *smb_fname_dst = NULL; + const char *dst_original_lcomp = NULL; bool dest_has_wcard = False; NTSTATUS status = NT_STATUS_OK; char *p; @@ -7187,18 +7340,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, DEBUG(10,("smb_file_rename_information: got name |%s|\n", newname)); - if (req->flags2 & FLAGS2_DFS_PATHNAMES) { - status = resolve_dfspath_wcard(ctx, conn, - newname, - UCF_COND_ALLOW_WCARD_LCOMP, - !conn->sconn->using_smb2, - &newname, - &dest_has_wcard); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - } - /* Check the new name has no '/' characters. */ if (strchr_m(newname, '/')) { return NT_STATUS_NOT_SUPPORTED; @@ -7222,12 +7363,14 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, } /* - * Set the original last component, since + * Get the original last component, since * rename_internals_fsp() requires it. */ - smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst, - newname); - if (smb_fname_dst->original_lcomp == NULL) { + dst_original_lcomp = get_original_lcomp(smb_fname_dst, + conn, + newname, + 0); + if (dst_original_lcomp == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } @@ -7239,8 +7382,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, * the newname instead. */ char *base_name = NULL; - uint32_t ucf_flags = UCF_SAVE_LCOMP | - ucf_flags_from_smb_request(req); + uint32_t ucf_flags = ucf_flags_from_smb_request(req); if (dest_has_wcard) { ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP; @@ -7276,8 +7418,13 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_NO_MEMORY; } - status = unix_convert(ctx, conn, base_name, &smb_fname_dst, - ucf_flags); + status = filename_convert(ctx, + conn, + base_name, + ucf_flags, + NULL, + NULL, + &smb_fname_dst); /* If an error we expect this to be * NT_STATUS_OBJECT_PATH_NOT_FOUND */ @@ -7298,6 +7445,14 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, goto out; } } + dst_original_lcomp = get_original_lcomp(smb_fname_dst, + conn, + newname, + ucf_flags); + if (dst_original_lcomp == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } } if (fsp) { @@ -7305,17 +7460,28 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n", fsp_fnum_dbg(fsp), fsp_str_dbg(fsp), smb_fname_str_dbg(smb_fname_dst))); - status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0, - overwrite); + status = rename_internals_fsp(conn, + fsp, + smb_fname_dst, + dst_original_lcomp, + 0, + overwrite); } else { DEBUG(10,("smb_file_rename_information: " "SMB_FILE_RENAME_INFORMATION %s -> %s\n", smb_fname_str_dbg(smb_fname_src), smb_fname_str_dbg(smb_fname_dst))); - status = rename_internals(ctx, conn, req, smb_fname_src, - smb_fname_dst, 0, overwrite, false, - dest_has_wcard, - FILE_WRITE_ATTRIBUTES); + status = rename_internals(ctx, + conn, + req, + smb_fname_src, + smb_fname_dst, + dst_original_lcomp, + 0, + overwrite, + false, + dest_has_wcard, + FILE_WRITE_ATTRIBUTES); } out: TALLOC_FREE(smb_fname_dst); @@ -7435,7 +7601,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, } /* If we have a default acl, this *must* be a directory. */ - if (valid_def_acls && !fsp->is_directory) { + if (valid_def_acls && !fsp->fsp_flags.is_directory) { DBG_INFO("Can't set default acls on " "non-directory %s\n", fsp_str_dbg(fsp)); @@ -7522,7 +7688,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, break; case POSIX_LOCK_TYPE_WRITE: /* Return the right POSIX-mappable error code for files opened read-only. */ - if (!fsp->can_write) { + if (!fsp->fsp_flags.can_write) { return NT_STATUS_INVALID_HANDLE; } lock_type = WRITE_LOCK; @@ -7565,6 +7731,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, if (lock_type == UNLOCK_LOCK) { struct smbd_lock_element l = { + .req_guid = smbd_request_guid(req, 0), .smblctx = smblctx, .brltype = UNLOCK_LOCK, .offset = offset, @@ -7580,6 +7747,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, } *lck = (struct smbd_lock_element) { + .req_guid = smbd_request_guid(req, 0), .smblctx = smblctx, .brltype = lock_type, .count = count, @@ -7589,7 +7757,6 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, subreq = smbd_smb1_do_locks_send( fsp, req->sconn->ev_ctx, - req->sconn->msg_ctx, &req, fsp, blocking_lock ? UINT32_MAX : 0, @@ -7663,13 +7830,20 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, uint32_t dosmode = 0; NTSTATUS status = NT_STATUS_OK; - ZERO_STRUCT(ft); + init_smb_file_time(&ft); if (total_data < 36) { return NT_STATUS_INVALID_PARAMETER; } - status = check_access(conn, fsp, smb_fname, FILE_WRITE_ATTRIBUTES); + if (fsp != NULL) { + status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES); + } else { + status = check_access(conn, + conn->cwd_fsp, + smb_fname, + FILE_WRITE_ATTRIBUTES); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -7682,22 +7856,29 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, } /* create time */ - ft.create_time = interpret_long_date(pdata); + ft.create_time = pull_long_date_full_timespec(pdata); /* access time */ - ft.atime = interpret_long_date(pdata+8); + ft.atime = pull_long_date_full_timespec(pdata+8); /* write time. */ - ft.mtime = interpret_long_date(pdata+16); + ft.mtime = pull_long_date_full_timespec(pdata+16); /* change time. */ - ft.ctime = interpret_long_date(pdata+24); + ft.ctime = pull_long_date_full_timespec(pdata+24); DEBUG(10, ("smb_set_file_basic_info: file %s\n", smb_fname_str_dbg(smb_fname))); - return smb_set_file_time(conn, fsp, smb_fname, &ft, - true); + status = smb_set_file_time(conn, fsp, smb_fname, &ft, true); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (fsp != NULL && fsp->fsp_flags.modified) { + trigger_write_time_update_immediate(fsp); + } + return NT_STATUS_OK; } /**************************************************************************** @@ -7713,32 +7894,43 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn, NTSTATUS status; struct smb_file_time ft; - ZERO_STRUCT(ft); + init_smb_file_time(&ft); if (total_data < 12) { return NT_STATUS_INVALID_PARAMETER; } /* create time */ - ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata)); + ft.create_time = time_t_to_full_timespec(srv_make_unix_date2(pdata)); /* access time */ - ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4)); + ft.atime = time_t_to_full_timespec(srv_make_unix_date2(pdata+4)); /* write time */ - ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8)); + ft.mtime = time_t_to_full_timespec(srv_make_unix_date2(pdata+8)); DEBUG(10,("smb_set_info_standard: file %s\n", smb_fname_str_dbg(smb_fname))); - status = check_access(conn, fsp, smb_fname, FILE_WRITE_ATTRIBUTES); + if (fsp != NULL) { + status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES); + } else { + status = check_access(conn, + conn->cwd_fsp, + smb_fname, + FILE_WRITE_ATTRIBUTES); + } if (!NT_STATUS_IS_OK(status)) { return status; } - return smb_set_file_time(conn, - fsp, - smb_fname, - &ft, - true); + status = smb_set_file_time(conn, fsp, smb_fname, &ft, true); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (fsp != NULL && fsp->fsp_flags.modified) { + trigger_write_time_update_immediate(fsp); + } + return NT_STATUS_OK; } /**************************************************************************** @@ -7895,6 +8087,7 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, uint32_t raw_unixmode = IVAL(pdata,84); NTSTATUS status; mode_t unixmode; + int ret; if (total_data < 100) { return NT_STATUS_INVALID_PARAMETER; @@ -7911,6 +8104,11 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, #endif switch (file_type) { + /* We can't create other objects here. */ + case UNIX_TYPE_FILE: + case UNIX_TYPE_DIR: + case UNIX_TYPE_SYMLINK: + return NT_STATUS_ACCESS_DENIED; #if defined(S_IFIFO) case UNIX_TYPE_FIFO: unixmode |= S_IFIFO; @@ -7923,11 +8121,18 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, #endif #if defined(S_IFCHR) case UNIX_TYPE_CHARDEV: + /* This is only allowed for root. */ + if (get_current_uid(conn) != sec_initial_uid()) { + return NT_STATUS_ACCESS_DENIED; + } unixmode |= S_IFCHR; break; #endif #if defined(S_IFBLK) case UNIX_TYPE_BLKDEV: + if (get_current_uid(conn) != sec_initial_uid()) { + return NT_STATUS_ACCESS_DENIED; + } unixmode |= S_IFBLK; break; #endif @@ -7940,7 +8145,13 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, (unsigned int)unixmode, smb_fname_str_dbg(smb_fname))); /* Ok - do the mknod. */ - if (SMB_VFS_MKNOD(conn, smb_fname, unixmode, dev) != 0) { + ret = SMB_VFS_MKNODAT(conn, + conn->cwd_fsp, + smb_fname, + unixmode, + dev); + + if (ret != 0) { return map_nt_error_from_unix(errno); } @@ -7949,14 +8160,21 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, */ if (lp_inherit_permissions(SNUM(conn))) { - char *parent; - if (!parent_dirname(talloc_tos(), smb_fname->base_name, - &parent, NULL)) { + struct smb_filename *parent_fname = NULL; + bool ok; + + ok = parent_smb_fname(talloc_tos(), + smb_fname, + &parent_fname, + NULL); + if (!ok) { return NT_STATUS_NO_MEMORY; } - inherit_access_posix_acl(conn, parent, smb_fname, + inherit_access_posix_acl(conn, + parent_fname, + smb_fname, unixmode); - TALLOC_FREE(parent); + TALLOC_FREE(parent_fname); } return NT_STATUS_OK; @@ -7980,15 +8198,13 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE; gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE; NTSTATUS status = NT_STATUS_OK; - bool delete_on_fail = False; enum perm_type ptype; files_struct *all_fsps = NULL; bool modify_mtime = true; struct file_id id; - struct smb_filename *smb_fname_tmp = NULL; SMB_STRUCT_STAT sbuf; - ZERO_STRUCT(ft); + init_smb_file_time(&ft); if (total_data < 100) { return NT_STATUS_INVALID_PARAMETER; @@ -8000,8 +8216,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, size |= (((off_t)IVAL(pdata,4)) << 32); } - ft.atime = interpret_long_date(pdata+24); /* access_time */ - ft.mtime = interpret_long_date(pdata+32); /* modification_time */ + ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */ + ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */ set_owner = (uid_t)IVAL(pdata,40); set_grp = (gid_t)IVAL(pdata,48); raw_unixmode = IVAL(pdata,84); @@ -8037,39 +8253,10 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * a new info level should be used for mknod. JRA. */ - status = smb_unix_mknod(conn, + return smb_unix_mknod(conn, pdata, total_data, smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname); - if (smb_fname_tmp == NULL) { - return NT_STATUS_NO_MEMORY; - } - - if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) { - status = map_nt_error_from_unix(errno); - TALLOC_FREE(smb_fname_tmp); - SMB_VFS_UNLINK(conn, smb_fname); - return status; - } - - sbuf = smb_fname_tmp->st; - smb_fname = smb_fname_tmp; - - /* Ensure we don't try and change anything else. */ - raw_unixmode = SMB_MODE_NO_CHANGE; - size = get_file_size_stat(&sbuf); - ft.atime = sbuf.st_ex_atime; - ft.mtime = sbuf.st_ex_mtime; - /* - * We continue here as we might want to change the - * owner uid/gid. - */ - delete_on_fail = True; } #if 1 @@ -8129,9 +8316,6 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, if (ret != 0) { status = map_nt_error_from_unix(errno); - if (delete_on_fail) { - SMB_VFS_UNLINK(conn, smb_fname); - } return status; } } @@ -8160,27 +8344,26 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, } if (ret != 0) { status = map_nt_error_from_unix(errno); - if (delete_on_fail) { - SMB_VFS_UNLINK(conn, smb_fname); - } return status; } } /* Deal with any size changes. */ - status = smb_set_file_size(conn, req, - fsp, - smb_fname, - &sbuf, - size, - false); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (S_ISREG(sbuf.st_ex_mode)) { + status = smb_set_file_size(conn, req, + fsp, + smb_fname, + &sbuf, + size, + false); + if (!NT_STATUS_IS_OK(status)) { + return status; + } } /* Deal with any time changes. */ - if (null_timespec(ft.mtime) && null_timespec(ft.atime)) { + if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) { /* No change, don't cancel anything. */ return status; } @@ -8192,7 +8375,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * We're setting the time explicitly for UNIX. * Cancel any pending changes over all handles. */ - all_fsps->update_write_time_on_close = false; + all_fsps->fsp_flags.update_write_time_on_close = false; TALLOC_FREE(all_fsps->update_write_time_event); } @@ -8202,7 +8385,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * we need. Just remember if we modified * mtime and send the notify ourselves. */ - if (null_timespec(ft.mtime)) { + if (is_omit_timespec(&ft.mtime)) { modify_mtime = false; } @@ -8293,12 +8476,12 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, { NTSTATUS status = NT_STATUS_OK; uint32_t raw_unixmode = 0; - uint32_t mod_unixmode = 0; mode_t unixmode = (mode_t)0; files_struct *fsp = NULL; uint16_t info_level_return = 0; int info; char *pdata = *ppdata; + struct smb2_create_blobs *posx = NULL; if (total_data < 18) { return NT_STATUS_INVALID_PARAMETER; @@ -8313,7 +8496,12 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, return status; } - mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS; + status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n", + nt_errstr(status)); + return status; + } DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n", smb_fname_str_dbg(smb_fname), (unsigned int)unixmode)); @@ -8327,7 +8515,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, FILE_SHARE_NONE, /* share_access */ FILE_CREATE, /* create_disposition*/ FILE_DIRECTORY_FILE, /* create_options */ - mod_unixmode, /* file_attributes */ + 0, /* file_attributes */ 0, /* oplock_request */ NULL, /* lease */ 0, /* allocation_size */ @@ -8336,7 +8524,10 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, NULL, /* ea_list */ &fsp, /* result */ &info, /* pinfo */ - NULL, NULL); /* create context */ + posx, /* in_context_blobs */ + NULL); /* out_context_blobs */ + + TALLOC_FREE(posx); if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); @@ -8405,7 +8596,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, uint32_t flags = 0; uint32_t wire_open_mode = 0; uint32_t raw_unixmode = 0; - uint32_t mod_unixmode = 0; + uint32_t attributes = 0; uint32_t create_disp = 0; uint32_t access_mask = 0; uint32_t create_options = FILE_NON_DIRECTORY_FILE; @@ -8415,6 +8606,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, int oplock_request = 0; int info = 0; uint16_t info_level_return = 0; + struct smb2_create_blobs *posx = NULL; if (total_data < 18) { return NT_STATUS_INVALID_PARAMETER; @@ -8525,7 +8717,12 @@ static NTSTATUS smb_posix_open(connection_struct *conn, return status; } - mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS; + status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n", + nt_errstr(status)); + return status; + } if (wire_open_mode & SMB_O_SYNC) { create_options |= FILE_WRITE_THROUGH; @@ -8534,7 +8731,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, access_mask |= FILE_APPEND_DATA; } if (wire_open_mode & SMB_O_DIRECT) { - mod_unixmode |= FILE_FLAG_NO_BUFFERING; + attributes |= FILE_FLAG_NO_BUFFERING; } if ((wire_open_mode & SMB_O_DIRECTORY) || @@ -8561,7 +8758,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, FILE_SHARE_DELETE), create_disp, /* create_disposition*/ create_options, /* create_options */ - mod_unixmode, /* file_attributes */ + attributes, /* file_attributes */ oplock_request, /* oplock_request */ NULL, /* lease */ 0, /* allocation_size */ @@ -8570,7 +8767,10 @@ static NTSTATUS smb_posix_open(connection_struct *conn, NULL, /* ea_list */ &fsp, /* result */ &info, /* pinfo */ - NULL, NULL); /* create context */ + posx, /* in_context_blobs */ + NULL); /* out_context_blobs */ + + TALLOC_FREE(posx); if (!NT_STATUS_IS_OK(status)) { return status; @@ -8651,7 +8851,6 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, int total_data, struct smb_filename *smb_fname) { - struct server_id self = messaging_server_id(conn->sconn->msg_ctx); NTSTATUS status = NT_STATUS_OK; files_struct *fsp = NULL; uint16_t flags = 0; @@ -8660,6 +8859,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, int create_options = 0; struct share_mode_lock *lck = NULL; bool other_nonposix_opens; + struct smb2_create_blobs *posx = NULL; if (total_data < 2) { return NT_STATUS_INVALID_PARAMETER; @@ -8684,6 +8884,13 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, create_options |= FILE_DIRECTORY_FILE; } + status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n", + nt_errstr(status)); + return status; + } + status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ @@ -8694,7 +8901,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, FILE_SHARE_DELETE), FILE_OPEN, /* create_disposition*/ create_options, /* create_options */ - FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */ + 0, /* file_attributes */ 0, /* oplock_request */ NULL, /* lease */ 0, /* allocation_size */ @@ -8703,7 +8910,10 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, NULL, /* ea_list */ &fsp, /* result */ &info, /* pinfo */ - NULL, NULL); /* create context */ + posx, /* in_context_blobs */ + NULL); /* out_context_blobs */ + + TALLOC_FREE(posx); if (!NT_STATUS_IS_OK(status)) { return status; @@ -8722,7 +8932,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - other_nonposix_opens = has_other_nonposix_opens(lck, fsp, self); + other_nonposix_opens = has_other_nonposix_opens(lck, fsp); if (other_nonposix_opens) { /* Fail with sharing violation. */ TALLOC_FREE(lck); @@ -9247,6 +9457,12 @@ static void call_trans2setfilepathinfo(connection_struct *conn, /* We have re-scheduled this call. */ return; } + if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) { + bool ok = defer_smb1_sharing_violation(req); + if (ok) { + return; + } + } if (NT_STATUS_EQUAL(status, NT_STATUS_EVENT_PENDING)) { /* We have re-scheduled this call. */ return; @@ -9570,6 +9786,8 @@ static void call_trans2ioctl(connection_struct *conn, char **ppdata, int total_data, unsigned int max_data_bytes) { + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); char *pdata = *ppdata; files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0)); NTSTATUS status; @@ -9605,7 +9823,7 @@ static void call_trans2ioctl(connection_struct *conn, return; } status = srvstr_push(pdata, req->flags2, pdata+18, - lp_servicename(talloc_tos(), SNUM(conn)), 13, + lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13, STR_ASCII|STR_TERMINATE, &len); /* Service name */ if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -9628,6 +9846,7 @@ void reply_findclose(struct smb_request *req) { int dptr_num; struct smbd_server_connection *sconn = req->sconn; + files_struct *fsp = NULL; START_PROFILE(SMBfindclose); @@ -9641,7 +9860,20 @@ void reply_findclose(struct smb_request *req) DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num)); - dptr_close(sconn, &dptr_num); + /* + * OS/2 seems to use -1 to indicate "close all directories" + * This has to mean on this specific connection struct. + */ + if (dptr_num == -1) { + dptr_closecnum(req->conn); + } else { + fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num); + dptr_num = -1; + if (fsp != NULL) { + close_file(NULL, fsp, NORMAL_CLOSE); + fsp = NULL; + } + } reply_outbuf(req, 0, 0);