X-Git-Url: http://git.samba.org/samba.git/?p=sfrench%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source3%2Fsmbd%2Ftrans2.c;h=de6073a973fdbc35197caf5831199727b83f49f2;hp=4afb27e9ecd2614a2216588aa159eb5bc01b3676;hb=8e43af0f81e644411f5a719860383373b210cc8b;hpb=0c8e9cc7570f7498b4ea533325a1d324c3e75be9 diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 4afb27e9ecd..de6073a973f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -40,6 +40,7 @@ #include "rpc_server/srv_pipe_hnd.h" #include "printing.h" #include "lib/util_ea.h" +#include "lib/readdir_attr.h" #define DIR_ENTRY_SAFETY_MARGIN 4096 @@ -53,6 +54,51 @@ static char *store_file_unix_basic_info2(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *psbuf); +/**************************************************************************** + Check if an open file handle or smb_fname is a symlink. +****************************************************************************/ + +static NTSTATUS refuse_symlink(connection_struct *conn, + const files_struct *fsp, + const struct smb_filename *smb_fname) +{ + SMB_STRUCT_STAT sbuf; + const SMB_STRUCT_STAT *pst = NULL; + + if (fsp) { + pst = &fsp->fsp_name->st; + } else { + pst = &smb_fname->st; + } + + if (!VALID_STAT(*pst)) { + int ret = vfs_stat_smb_basename(conn, + smb_fname, + &sbuf); + if (ret == -1 && errno != ENOENT) { + return map_nt_error_from_unix(errno); + } else if (ret == -1) { + /* it's not a symlink.. */ + return NT_STATUS_OK; + } + pst = &sbuf; + } + + if (S_ISLNK(pst->st_ex_mode)) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + +NTSTATUS check_access_fsp(const struct files_struct *fsp, + uint32_t access_mask) +{ + if (!(fsp->access_mask & access_mask)) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + /******************************************************************** The canonical "check access" based on object handle or path function. ********************************************************************/ @@ -62,20 +108,16 @@ NTSTATUS check_access(connection_struct *conn, const struct smb_filename *smb_fname, uint32_t access_mask) { + NTSTATUS status; + if (fsp) { - if (!(fsp->access_mask & access_mask)) { - return NT_STATUS_ACCESS_DENIED; - } + status = check_access_fsp(fsp, access_mask); } else { - NTSTATUS status = smbd_check_access_rights(conn, - smb_fname, - false, - access_mask); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + status = smbd_check_access_rights(conn, smb_fname, + false, access_mask); } - return NT_STATUS_OK; + + return status; } /******************************************************************** @@ -104,6 +146,9 @@ uint64_t smb_roundup(connection_struct *conn, uint64_t val) uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf) { uint64_t file_index; + if (conn->sconn->aapl_zero_file_id) { + return 0; + } if (conn->base_share_dev == psbuf->st_ex_dev) { return (uint64_t)psbuf->st_ex_ino; } @@ -112,6 +157,17 @@ uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf) return file_index; } + +/******************************************************************** + 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. ****************************************************************************/ @@ -120,7 +176,7 @@ uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf) Refuse to allow clients to overwrite our private xattrs. ****************************************************************************/ -static bool samba_private_attr_name(const char *unix_ea_name) +bool samba_private_attr_name(const char *unix_ea_name) { static const char * const prohibited_ea_names[] = { SAMBA_POSIX_INHERITANCE_EA_NAME, @@ -147,9 +203,12 @@ static bool samba_private_attr_name(const char *unix_ea_name) Get one EA value. Fill in a struct ea_struct. ****************************************************************************/ -NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, - files_struct *fsp, const char *fname, - const char *ea_name, struct ea_struct *pea) +NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, + connection_struct *conn, + files_struct *fsp, + const struct smb_filename *smb_fname, + const char *ea_name, + struct ea_struct *pea) { /* Get the value of this xattr. Max size is 64k. */ size_t attr_size = 256; @@ -166,7 +225,8 @@ NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, if (fsp && fsp->fh->fd != -1) { sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size); } else { - sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size); + sizeret = SMB_VFS_GETXATTR(conn, smb_fname, + ea_name, val, attr_size); } if (sizeret == -1 && errno == ERANGE && attr_size != 65536) { @@ -179,7 +239,7 @@ NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, } DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret)); - dump_data(10, (uint8 *)val, sizeret); + dump_data(10, (uint8_t *)val, sizeret); pea->flags = 0; if (strnequal(ea_name, "user.", 5)) { @@ -196,77 +256,77 @@ NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, return NT_STATUS_OK; } -NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, - files_struct *fsp, const char *fname, - char ***pnames, size_t *pnum_names) +NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, + connection_struct *conn, + files_struct *fsp, + const struct smb_filename *smb_fname, + char ***pnames, + size_t *pnum_names) { + char smallbuf[1024]; /* Get a list of all xattrs. Max namesize is 64k. */ size_t ea_namelist_size = 1024; - char *ea_namelist = NULL; + char *ea_namelist = smallbuf; + char *to_free = NULL; char *p; - char **names, **tmp; + char **names; size_t num_names; ssize_t sizeret = -1; + NTSTATUS status; - if (!lp_ea_support(SNUM(conn))) { - if (pnames) { - *pnames = NULL; - } - *pnum_names = 0; - return NT_STATUS_OK; + if (pnames) { + *pnames = NULL; } + *pnum_names = 0; - /* - * TALLOC the result early to get the talloc hierarchy right. - */ - - names = talloc_array(mem_ctx, char *, 1); - if (names == NULL) { - DEBUG(0, ("talloc failed\n")); - return NT_STATUS_NO_MEMORY; + status = refuse_symlink(conn, fsp, smb_fname); + if (!NT_STATUS_IS_OK(status)) { + /* + * Just return no EA's on a symlink. + */ + return NT_STATUS_OK; } - while (ea_namelist_size <= 65536) { + if (fsp && fsp->fh->fd != -1) { + sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist, + ea_namelist_size); + } else { + sizeret = SMB_VFS_LISTXATTR(conn, + smb_fname, + ea_namelist, + ea_namelist_size); + } - ea_namelist = talloc_realloc( - names, ea_namelist, char, ea_namelist_size); + if ((sizeret == -1) && (errno == ERANGE)) { + ea_namelist_size = 65536; + ea_namelist = talloc_array(mem_ctx, char, ea_namelist_size); if (ea_namelist == NULL) { - DEBUG(0, ("talloc failed\n")); - TALLOC_FREE(names); return NT_STATUS_NO_MEMORY; } + to_free = ea_namelist; if (fsp && fsp->fh->fd != -1) { sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist, ea_namelist_size); } else { - sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, + sizeret = SMB_VFS_LISTXATTR(conn, + smb_fname, + ea_namelist, ea_namelist_size); } - - if ((sizeret == -1) && (errno == ERANGE)) { - ea_namelist_size *= 2; - } - else { - break; - } } if (sizeret == -1) { - TALLOC_FREE(names); - return map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); + TALLOC_FREE(to_free); + return status; } - DEBUG(10, ("%s: ea_namelist size = %u\n", - __func__, (unsigned int)sizeret)); + DBG_DEBUG("ea_namelist size = %zd\n", sizeret); if (sizeret == 0) { - TALLOC_FREE(names); - if (pnames) { - *pnames = NULL; - } - *pnum_names = 0; + TALLOC_FREE(to_free); return NT_STATUS_OK; } @@ -275,7 +335,7 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, */ if (ea_namelist[sizeret-1] != '\0') { - TALLOC_FREE(names); + TALLOC_FREE(to_free); return NT_STATUS_INTERNAL_ERROR; } @@ -288,26 +348,45 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, num_names += 1; } - tmp = talloc_realloc(mem_ctx, names, char *, num_names); - if (tmp == NULL) { + *pnum_names = num_names; + + if (pnames == NULL) { + TALLOC_FREE(to_free); + return NT_STATUS_OK; + } + + names = talloc_array(mem_ctx, char *, num_names); + if (names == NULL) { DEBUG(0, ("talloc failed\n")); - TALLOC_FREE(names); + TALLOC_FREE(to_free); return NT_STATUS_NO_MEMORY; } - names = tmp; + if (ea_namelist == smallbuf) { + ea_namelist = talloc_memdup(names, smallbuf, sizeret); + if (ea_namelist == NULL) { + TALLOC_FREE(names); + return NT_STATUS_NO_MEMORY; + } + } else { + talloc_steal(names, ea_namelist); + + ea_namelist = talloc_realloc(names, ea_namelist, char, + sizeret); + if (ea_namelist == NULL) { + TALLOC_FREE(names); + return NT_STATUS_NO_MEMORY; + } + } + num_names = 0; for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) { names[num_names++] = p; } - if (pnames) { - *pnames = names; - } else { - TALLOC_FREE(names); - } - *pnum_names = num_names; + *pnames = names; + return NT_STATUS_OK; } @@ -315,27 +394,46 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, Return a linked list of the total EA's. Plus the total size ****************************************************************************/ -static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, - const char *fname, size_t *pea_total_len, struct ea_list **ea_list) +static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, + connection_struct *conn, + files_struct *fsp, + const struct smb_filename *smb_fname, + size_t *pea_total_len, + struct ea_list **ea_list) { /* Get a list of all xattrs. Max namesize is 64k. */ size_t i, num_names; char **names; struct ea_list *ea_list_head = NULL; + bool posix_pathnames = false; NTSTATUS status; *pea_total_len = 0; *ea_list = NULL; - status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname, - &names, &num_names); + if (!lp_ea_support(SNUM(conn))) { + return NT_STATUS_OK; + } + + if (fsp) { + posix_pathnames = + (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH); + } else { + posix_pathnames = (smb_fname->flags & SMB_FILENAME_POSIX_PATH); + } + + status = get_ea_names_from_file(talloc_tos(), + conn, + fsp, + smb_fname, + &names, + &num_names); if (!NT_STATUS_IS_OK(status)) { return status; } if (num_names == 0) { - *ea_list = NULL; return NT_STATUS_OK; } @@ -351,7 +449,7 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc * Filter out any underlying POSIX EA names * that a Windows client can't handle. */ - if (!lp_posix_pathnames() && + if (!posix_pathnames && is_invalid_windows_ea_name(names[i])) { continue; } @@ -361,9 +459,12 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc return NT_STATUS_NO_MEMORY; } - status = get_ea_value(listp, conn, fsp, - fname, names[i], - &listp->ea); + status = get_ea_value(listp, + conn, + fsp, + smb_fname, + names[i], + &listp->ea); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(listp); @@ -388,7 +489,7 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc "= %u\n", (unsigned int)*pea_total_len, dos_ea_name, (unsigned int)listp->ea.value.length)); - DLIST_ADD_END(ea_list_head, listp, struct ea_list *); + DLIST_ADD_END(ea_list_head, listp); } @@ -418,7 +519,12 @@ static NTSTATUS get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *co return NT_STATUS_INVALID_PARAMETER; } - return get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, pea_total_len, ea_list); + return get_ea_list_from_file_path(mem_ctx, + conn, + fsp, + smb_fname, + pea_total_len, + ea_list); } /**************************************************************************** @@ -561,7 +667,12 @@ static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, if (is_ntfs_stream_smb_fname(smb_fname)) { fsp = NULL; } - (void)get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, &total_ea_len, &ea_list); + (void)get_ea_list_from_file_path(mem_ctx, + conn, + fsp, + smb_fname, + &total_ea_len, + &ea_list); if(conn->sconn->using_smb2) { NTSTATUS status; unsigned int ret_data_size; @@ -590,12 +701,20 @@ static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, Ensure the EA name is case insensitive by matching any existing EA name. ****************************************************************************/ -static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name) +static void canonicalize_ea_name(connection_struct *conn, + files_struct *fsp, + const struct smb_filename *smb_fname, + fstring unix_ea_name) { size_t total_ea_len; TALLOC_CTX *mem_ctx = talloc_tos(); struct ea_list *ea_list; - NTSTATUS status = get_ea_list_from_file_path(mem_ctx, conn, fsp, fname, &total_ea_len, &ea_list); + NTSTATUS status = get_ea_list_from_file_path(mem_ctx, + conn, + fsp, + smb_fname, + &total_ea_len, + &ea_list); if (!NT_STATUS_IS_OK(status)) { return; } @@ -618,12 +737,24 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname, struct ea_list *ea_list) { NTSTATUS status; - char *fname = NULL; + bool posix_pathnames = false; if (!lp_ea_support(SNUM(conn))) { return NT_STATUS_EAS_NOT_SUPPORTED; } + if (fsp) { + posix_pathnames = + (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH); + } else { + posix_pathnames = (smb_fname->flags & SMB_FILENAME_POSIX_PATH); + } + + status = refuse_symlink(conn, fsp, smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA); if (!NT_STATUS_IS_OK(status)) { return status; @@ -639,12 +770,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, * we set *any* of them. */ - if (ea_list_has_invalid_name(ea_list)) { + if (!posix_pathnames && ea_list_has_invalid_name(ea_list)) { return STATUS_INVALID_EA_NAME; } - fname = smb_fname->base_name; - for (;ea_list; ea_list = ea_list->next) { int ret; fstring unix_ea_name; @@ -652,7 +781,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */ fstrcat(unix_ea_name, ea_list->ea.name); - canonicalize_ea_name(conn, fsp, fname, unix_ea_name); + canonicalize_ea_name(conn, + fsp, + smb_fname, + unix_ea_name); DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length)); @@ -670,8 +802,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name); } else { DEBUG(10,("set_ea: deleting ea name %s on file %s.\n", - unix_ea_name, fname)); - ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name); + unix_ea_name, smb_fname->base_name)); + ret = SMB_VFS_REMOVEXATTR(conn, + smb_fname, + unix_ea_name); } #ifdef ENOATTR /* Removing a non existent attribute always succeeds. */ @@ -690,9 +824,13 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, ea_list->ea.value.data, ea_list->ea.value.length, 0); } else { DEBUG(10,("set_ea: setting ea name %s on file %s.\n", - unix_ea_name, fname)); - ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name, - ea_list->ea.value.data, ea_list->ea.value.length, 0); + unix_ea_name, smb_fname->base_name)); + ret = SMB_VFS_SETXATTR(conn, + smb_fname, + unix_ea_name, + ea_list->ea.value.data, + ea_list->ea.value.length, + 0); } } @@ -743,7 +881,7 @@ static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, siz } offset += (namelen + 1); /* Go past the name + terminating zero. */ - DLIST_ADD_END(ea_list_head, eal, struct ea_list *); + DLIST_ADD_END(ea_list_head, eal); DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name)); } @@ -767,7 +905,7 @@ static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t d return NULL; } - DLIST_ADD_END(ea_list_head, eal, struct ea_list *); + DLIST_ADD_END(ea_list_head, eal); offset += bytes_used; } @@ -859,8 +997,8 @@ void send_trans2_replies(connection_struct *conn, int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ int data_alignment_offset = 0; bool overflow = False; - struct smbd_server_connection *sconn = req->sconn; - int max_send = sconn->smb1.sessions.max_send; + struct smbXsrv_connection *xconn = req->xconn; + int max_send = xconn->smb1.sessions.max_send; /* Modify the data_to_send and datasize and set the error if we're trying to send more than max_data_bytes. We still send @@ -887,7 +1025,7 @@ void send_trans2_replies(connection_struct *conn, __LINE__,__FILE__); } show_msg((char *)req->outbuf); - if (!srv_send_smb(sconn, + if (!srv_send_smb(xconn, (char *)req->outbuf, true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), @@ -1027,7 +1165,7 @@ void send_trans2_replies(connection_struct *conn, /* Send the packet */ show_msg((char *)req->outbuf); - if (!srv_send_smb(sconn, + if (!srv_send_smb(xconn, (char *)req->outbuf, true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), @@ -1067,7 +1205,7 @@ static void call_trans2open(connection_struct *conn, char *params = *pparams; char *pdata = *ppdata; int deny_mode; - int32 open_attr; + int32_t open_attr; bool oplock_request; #if 0 bool return_additional_info; @@ -1075,7 +1213,7 @@ static void call_trans2open(connection_struct *conn, time_t open_time; #endif int open_ofun; - uint32 open_size; + uint32_t open_size; char *pname; char *fname = NULL; off_t size=0; @@ -1084,13 +1222,14 @@ static void call_trans2open(connection_struct *conn, int smb_action = 0; files_struct *fsp; struct ea_list *ea_list = NULL; - uint16 flags = 0; + uint16_t flags = 0; NTSTATUS status; - uint32 access_mask; - uint32 share_mode; - uint32 create_disposition; - uint32 create_options = 0; + uint32_t access_mask; + uint32_t share_mode; + uint32_t create_disposition; + uint32_t create_options = 0; uint32_t private_flags = 0; + uint32_t ucf_flags = ucf_flags_from_smb_request(req); TALLOC_CTX *ctx = talloc_tos(); /* @@ -1124,9 +1263,25 @@ static void call_trans2open(connection_struct *conn, goto out; } - srvstr_get_path(ctx, params, req->flags2, &fname, pname, - total_params - 28, STR_TERMINATE, + if (req->posix_pathnames) { + srvstr_get_path_posix(ctx, + params, + req->flags2, + &fname, + pname, + total_params - 28, + STR_TERMINATE, + &status); + } else { + srvstr_get_path(ctx, + params, + req->flags2, + &fname, + pname, + total_params - 28, + STR_TERMINATE, &status); + } if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; @@ -1138,9 +1293,8 @@ static void call_trans2open(connection_struct *conn, status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - 0, + ucf_flags, NULL, &smb_fname); if (!NT_STATUS_IS_OK(status)) { @@ -1195,7 +1349,8 @@ static void call_trans2open(connection_struct *conn, goto out; } - if (ea_list_has_invalid_name(ea_list)) { + if (!req->posix_pathnames && + ea_list_has_invalid_name(ea_list)) { int param_len = 30; *pparams = (char *)SMB_REALLOC(*pparams, param_len); if(*pparams == NULL ) { @@ -1221,15 +1376,17 @@ static void call_trans2open(connection_struct *conn, create_options, /* create_options */ open_attr, /* file_attributes */ oplock_request, /* oplock_request */ + NULL, /* lease */ open_size, /* allocation_size */ private_flags, NULL, /* sd */ ea_list, /* ea_list */ &fsp, /* result */ - &smb_action); /* psbuf */ + &smb_action, /* psbuf */ + NULL, NULL); /* create context */ if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->sconn, req->mid)) { + if (open_was_deferred(req->xconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -1258,7 +1415,7 @@ static void call_trans2open(connection_struct *conn, SSVAL(params,0,fsp->fnum); SSVAL(params,2,fattr); srv_put_dos_date2(params,4, mtime); - SIVAL(params,8, (uint32)size); + SIVAL(params,8, (uint32_t)size); SSVAL(params,12,deny_mode); SSVAL(params,14,0); /* open_type - file or directory. */ SSVAL(params,16,0); /* open_state - only valid for IPC device. */ @@ -1275,7 +1432,7 @@ static void call_trans2open(connection_struct *conn, SIVAL(params,20,inode); SSVAL(params,24,0); /* Padding. */ if (flags & 8) { - uint32 ea_size = estimate_ea_size(conn, fsp, + uint32_t ea_size = estimate_ea_size(conn, fsp, smb_fname); SIVAL(params, 26, ea_size); } else { @@ -1319,7 +1476,7 @@ static bool exact_match(bool has_wild, Return the filetype for UNIX extensions. ****************************************************************************/ -static uint32 unix_filetype(mode_t mode) +static uint32_t unix_filetype(mode_t mode) { if(S_ISREG(mode)) return UNIX_TYPE_FILE; @@ -1358,7 +1515,7 @@ enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_ static NTSTATUS unix_perms_from_wire( connection_struct *conn, const SMB_STRUCT_STAT *psbuf, - uint32 perms, + uint32_t perms, enum perm_type ptype, mode_t *ret_perms) { @@ -1420,18 +1577,18 @@ static NTSTATUS unix_perms_from_wire( connection_struct *conn, ****************************************************************************/ static bool check_msdfs_link(connection_struct *conn, - const char *pathname, - SMB_STRUCT_STAT *psbuf) + struct smb_filename *smb_fname) { int saved_errno = errno; if(lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && - is_msdfs_link(conn, pathname, psbuf)) { + is_msdfs_link(conn, smb_fname)) { DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s " "as a directory\n", - pathname)); - psbuf->st_ex_mode = (psbuf->st_ex_mode & 0xFFF) | S_IFDIR; + smb_fname->base_name)); + smb_fname->st.st_ex_mode = + (smb_fname->st.st_ex_mode & 0xFFF) | S_IFDIR; errno = saved_errno; return true; } @@ -1467,6 +1624,31 @@ static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx, /* Mangle fname if it's an illegal name. */ if (mangle_must_mangle(dname, state->conn->params)) { + /* + * Slow path - ensure we can push the original name as UCS2. If + * not, then just don't return this name. + */ + NTSTATUS status; + size_t ret_len = 0; + size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */ + uint8_t *tmp = talloc_array(talloc_tos(), + uint8_t, + len); + + status = srvstr_push(NULL, + FLAGS2_UNICODE_STRINGS, + tmp, + dname, + len, + STR_TERMINATE, + &ret_len); + + TALLOC_FREE(tmp); + + if (!NT_STATUS_IS_OK(status)) { + return false; + } + ok = name_to_8_3(dname, mangled_name, true, state->conn->params); if (!ok) { @@ -1547,8 +1729,7 @@ static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx, * directories */ ms_dfs_link = check_msdfs_link(state->conn, - smb_fname->base_name, - &smb_fname->st); + smb_fname); if (!ms_dfs_link) { DEBUG(5,("smbd_dirptr_lanman2_mode_fn: " "Couldn't stat [%s] (%s)\n", @@ -1568,7 +1749,7 @@ static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx, return true; } -static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, +static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx, connection_struct *conn, uint16_t flags2, uint32_t info_level, @@ -1584,7 +1765,6 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, char *base_data, char **ppdata, char *end_data, - bool *out_of_space, uint64_t *last_entry_off) { char *p, *q, *pdata = *ppdata; @@ -1592,27 +1772,32 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, uint64_t file_size = 0; uint64_t allocation_size = 0; uint64_t file_index = 0; - uint32_t len; - struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts; + size_t len = 0; + struct timespec mdate_ts = {0}; + struct timespec adate_ts = {0}; + struct timespec cdate_ts = {0}; + struct timespec create_date_ts = {0}; time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0; char *nameptr; char *last_entry_ptr; bool was_8_3; int off; int pad = 0; - - *out_of_space = false; - - ZERO_STRUCT(mdate_ts); - ZERO_STRUCT(adate_ts); - ZERO_STRUCT(create_date_ts); - ZERO_STRUCT(cdate_ts); + NTSTATUS status; + struct readdir_attr_data *readdir_attr_data = NULL; if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) { file_size = get_file_size_stat(&smb_fname->st); } allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st); + status = SMB_VFS_READDIR_ATTR(conn, smb_fname, ctx, &readdir_attr_data); + if (!NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED, status)) { + return status; + } + } + file_index = get_FileIndex(conn, &smb_fname->st); mdate_ts = smb_fname->st.st_ex_mtime; @@ -1639,12 +1824,11 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, pad -= off; if (pad && pad > space_remaining) { - *out_of_space = true; DEBUG(9,("smbd_marshall_dir_entry: out of space " "for padding (wanted %u, had %d)\n", (unsigned int)pad, space_remaining )); - return false; /* Not finished - just out of space */ + return STATUS_MORE_ENTRIES; /* Not finished - just out of space */ } off += pad; @@ -1674,17 +1858,20 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, srv_put_dos_date2(p,0,create_date); srv_put_dos_date2(p,4,adate); srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); + SIVAL(p,12,(uint32_t)file_size); + SIVAL(p,16,(uint32_t)allocation_size); SSVAL(p,20,mode); p += 23; nameptr = p; if (flags2 & FLAGS2_UNICODE_STRINGS) { p += ucs2_align(base_data, p, 0); } - len = srvstr_push(base_data, flags2, p, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE); + STR_TERMINATE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (flags2 & FLAGS2_UNICODE_STRINGS) { if (len > 2) { SCVAL(nameptr, -1, len - 2); @@ -1710,8 +1897,8 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, srv_put_dos_date2(p,0,create_date); srv_put_dos_date2(p,4,adate); srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); + SIVAL(p,12,(uint32_t)file_size); + SIVAL(p,16,(uint32_t)allocation_size); SSVAL(p,20,mode); { unsigned int ea_size = estimate_ea_size(conn, NULL, @@ -1720,9 +1907,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, } p += 27; nameptr = p - 1; - len = srvstr_push(base_data, flags2, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE | STR_NOALIGN); + STR_TERMINATE | STR_NOALIGN, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (flags2 & FLAGS2_UNICODE_STRINGS) { if (len > 2) { len -= 2; @@ -1745,11 +1935,10 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, { struct ea_list *file_list = NULL; size_t ea_len = 0; - NTSTATUS status; DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n")); if (!name_list) { - return false; + return NT_STATUS_INVALID_PARAMETER; } if (requires_resume_key) { SIVAL(p,0,reskey); @@ -1758,8 +1947,8 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, srv_put_dos_date2(p,0,create_date); srv_put_dos_date2(p,4,adate); srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); + SIVAL(p,12,(uint32_t)file_size); + SIVAL(p,16,(uint32_t)allocation_size); SSVAL(p,20,mode); p += 22; /* p now points to the EA area. */ @@ -1774,20 +1963,22 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, /* We need to determine if this entry will fit in the space available. */ /* Max string size is 255 bytes. */ if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) { - *out_of_space = true; DEBUG(9,("smbd_marshall_dir_entry: out of space " "(wanted %u, had %d)\n", (unsigned int)PTR_DIFF(p + 255 + ea_len,pdata), space_remaining )); - return False; /* Not finished - just out of space */ + return STATUS_MORE_ENTRIES; /* Not finished - just out of space */ } /* Push the ea_data followed by the name. */ p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list); nameptr = p; - len = srvstr_push(base_data, flags2, + status = srvstr_push(base_data, flags2, p + 1, fname, PTR_DIFF(end_data, p+1), - STR_TERMINATE | STR_NOALIGN); + STR_TERMINATE | STR_NOALIGN, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (flags2 & FLAGS2_UNICODE_STRINGS) { if (len > 2) { len -= 2; @@ -1840,9 +2031,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, memset(mangled_name,'\0',12); } mangled_name[12] = 0; - len = srvstr_push(base_data, flags2, + status = srvstr_push(base_data, flags2, p+2, mangled_name, 24, - STR_UPPER|STR_UNICODE); + STR_UPPER|STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (len < 24) { memset(p + 2 + len,'\0',24 - len); } @@ -1851,9 +2045,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, memset(p,'\0',26); } p += 2 + 24; - len = srvstr_push(base_data, flags2, p, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); + STR_TERMINATE_ASCII, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(q,0,len); p += len; @@ -1887,9 +2084,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, SOFF_T(p,0,file_size); p += 8; SOFF_T(p,0,allocation_size); p += 8; SIVAL(p,0,mode); p += 4; - len = srvstr_push(base_data, flags2, + status = srvstr_push(base_data, flags2, p + 4, fname, PTR_DIFF(end_data, p+4), - STR_TERMINATE_ASCII); + STR_TERMINATE_ASCII, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(p,0,len); p += 4 + len; @@ -1930,9 +2130,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, SIVAL(p,0,ea_size); /* Extended attributes */ p +=4; } - len = srvstr_push(base_data, flags2, p, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); + STR_TERMINATE_ASCII, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(q, 0, len); p += len; @@ -1962,9 +2165,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, p += 4; /* this must *not* be null terminated or w2k gets in a loop trying to set an acl on a dir (tridge) */ - len = srvstr_push(base_data, flags2, p, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); + STR_TERMINATE_ASCII, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(p, -4, len); p += len; @@ -2009,9 +2215,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, p += 4; SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */ SBVAL(p,0,file_index); p += 8; - len = srvstr_push(base_data, flags2, p, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); + STR_TERMINATE_ASCII, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(q, 0, len); p += len; @@ -2049,17 +2258,41 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, q = p; p += 4; /* q is placeholder for name length */ if (mode & FILE_ATTRIBUTE_REPARSE_POINT) { SIVAL(p, 0, IO_REPARSE_TAG_DFS); + } else if (readdir_attr_data && + readdir_attr_data->type == RDATTR_AAPL) { + /* + * OS X specific SMB2 extension negotiated via + * AAPL create context: return max_access in + * ea_size field. + */ + SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access); } else { unsigned int ea_size = estimate_ea_size(conn, NULL, smb_fname); SIVAL(p,0,ea_size); /* Extended attributes */ } p += 4; - /* Clear the short name buffer. This is - * IMPORTANT as not doing so will trigger - * a Win2k client bug. JRA. - */ - if (!was_8_3 && check_mangled_names) { + + if (readdir_attr_data && + readdir_attr_data->type == RDATTR_AAPL) { + /* + * OS X specific SMB2 extension negotiated via + * AAPL create context: return resource fork + * length and compressed FinderInfo in + * shortname field. + * + * According to documentation short_name_len + * should be 0, but on the wire behaviour + * shows its set to 24 by clients. + */ + SSVAL(p, 0, 24); + + /* Resourefork length */ + SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size); + + /* Compressed FinderInfo */ + memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16); + } else if (!was_8_3 && check_mangled_names) { char mangled_name[13]; /* mangled 8.3 name. */ if (!name_to_8_3(fname,mangled_name,True, conn->params)) { @@ -2067,23 +2300,48 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, memset(mangled_name,'\0',12); } mangled_name[12] = 0; - len = srvstr_push(base_data, flags2, + status = srvstr_push(base_data, flags2, p+2, mangled_name, 24, - STR_UPPER|STR_UNICODE); + STR_UPPER|STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SSVAL(p, 0, len); if (len < 24) { memset(p + 2 + len,'\0',24 - len); } SSVAL(p, 0, len); } else { + /* Clear the short name buffer. This is + * IMPORTANT as not doing so will trigger + * a Win2k client bug. JRA. + */ memset(p,'\0',26); } p += 26; - SSVAL(p,0,0); p += 2; /* Reserved ? */ + + /* Reserved ? */ + if (readdir_attr_data && + readdir_attr_data->type == RDATTR_AAPL) { + /* + * OS X specific SMB2 extension negotiated via + * AAPL create context: return UNIX mode in + * reserved field. + */ + uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode; + SSVAL(p, 0, aapl_mode); + } else { + SSVAL(p, 0, 0); + } + p += 2; + SBVAL(p,0,file_index); p += 8; - len = srvstr_push(base_data, flags2, p, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); + STR_TERMINATE_ASCII, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(q,0,len); p += len; @@ -2119,17 +2377,23 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n")); p = store_file_unix_basic(conn, p, NULL, &smb_fname->st); - len = srvstr_push(base_data, flags2, p, + status = srvstr_push(base_data, flags2, p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE); + STR_TERMINATE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } } else { DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n")); p = store_file_unix_basic_info2(conn, p, NULL, &smb_fname->st); nameptr = p; p += 4; - len = srvstr_push(base_data, flags2, p, fname, - PTR_DIFF(end_data, p), 0); + status = srvstr_push(base_data, flags2, p, fname, + PTR_DIFF(end_data, p), 0, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(nameptr, 0, len); } @@ -2157,16 +2421,15 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, break; default: - return false; + return NT_STATUS_INVALID_LEVEL; } if (PTR_DIFF(p,pdata) > space_remaining) { - *out_of_space = true; DEBUG(9,("smbd_marshall_dir_entry: out of space " "(wanted %u, had %d)\n", (unsigned int)PTR_DIFF(p,pdata), space_remaining )); - return false; /* Not finished - just out of space */ + return STATUS_MORE_ENTRIES; /* Not finished - just out of space */ } /* Setup the last entry pointer, as an offset from base_data */ @@ -2174,15 +2437,15 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, /* Advance the data pointer to the next slot */ *ppdata = p; - return true; + return NT_STATUS_OK; } -bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, +NTSTATUS smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, connection_struct *conn, struct dptr_struct *dirptr, - uint16 flags2, + uint16_t flags2, const char *path_mask, - uint32 dirtype, + uint32_t dirtype, int info_level, int requires_resume_key, bool dont_descend, @@ -2193,10 +2456,10 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, char *base_data, char *end_data, int space_remaining, - bool *out_of_space, bool *got_exact_match, int *_last_entry_off, - struct ea_list *name_list) + struct ea_list *name_list, + struct file_id *file_id) { const char *p; const char *mask = NULL; @@ -2207,15 +2470,21 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, struct smbd_dirptr_lanman2_state state; bool ok; uint64_t last_entry_off = 0; + NTSTATUS status; + enum mangled_names_options mangled_names; + bool marshall_with_83_names; + + mangled_names = lp_mangled_names(conn->params); ZERO_STRUCT(state); state.conn = conn; state.info_level = info_level; - state.check_mangled_names = lp_mangled_names(conn->params); + if (mangled_names != MANGLED_NAMES_NO) { + state.check_mangled_names = true; + } state.has_wild = dptr_has_wild(dirptr); state.got_exact_match = false; - *out_of_space = false; *got_exact_match = false; p = strrchr_m(path_mask,'/'); @@ -2243,17 +2512,19 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, &mode, &prev_dirpos); if (!ok) { - return false; + return NT_STATUS_END_OF_FILE; } *got_exact_match = state.got_exact_match; - ok = smbd_marshall_dir_entry(ctx, + marshall_with_83_names = (mangled_names == MANGLED_NAMES_YES); + + status = smbd_marshall_dir_entry(ctx, conn, flags2, info_level, name_list, - state.check_mangled_names, + marshall_with_83_names, requires_resume_key, mode, fname, @@ -2264,28 +2535,36 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, base_data, ppdata, end_data, - out_of_space, &last_entry_off); + if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) { + DEBUG(1,("Conversion error: illegal character: %s\n", + smb_fname_str_dbg(smb_fname))); + } + + if (file_id != NULL) { + *file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); + } + TALLOC_FREE(fname); TALLOC_FREE(smb_fname); - if (*out_of_space) { + if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { dptr_SeekDir(dirptr, prev_dirpos); - return false; + return status; } - if (!ok) { - return false; + if (!NT_STATUS_IS_OK(status)) { + return status; } *_last_entry_off = last_entry_off; - return true; + return NT_STATUS_OK; } -static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, +static NTSTATUS get_lanman2_dir_entry(TALLOC_CTX *ctx, connection_struct *conn, struct dptr_struct *dirptr, - uint16 flags2, + uint16_t flags2, const char *path_mask, - uint32 dirtype, + uint32_t dirtype, int info_level, bool requires_resume_key, bool dont_descend, @@ -2294,7 +2573,6 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, char *base_data, char *end_data, int space_remaining, - bool *out_of_space, bool *got_exact_match, int *last_entry_off, struct ea_list *name_list) @@ -2313,8 +2591,8 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, align, do_pad, ppdata, base_data, end_data, space_remaining, - out_of_space, got_exact_match, - last_entry_off, name_list); + got_exact_match, + last_entry_off, name_list, NULL); } /**************************************************************************** @@ -2336,9 +2614,9 @@ static void call_trans2findfirst(connection_struct *conn, char *params = *pparams; char *pdata = *ppdata; char *data_end; - uint32 dirtype; + uint32_t dirtype; int maxentries; - uint16 findfirst_flags; + uint16_t findfirst_flags; bool close_after_first; bool close_if_end; bool requires_resume_key; @@ -2358,11 +2636,12 @@ static void call_trans2findfirst(connection_struct *conn, struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); - TALLOC_CTX *ctx = talloc_tos(); struct dptr_struct *dirptr = NULL; struct smbd_server_connection *sconn = req->sconn; - uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP); + uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP | + ucf_flags_from_smb_request(req); bool backup_priv = false; + bool as_root = false; if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2418,9 +2697,27 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da goto out; } - srvstr_get_path_wcard(ctx, params, req->flags2, &directory, - params+12, total_params - 12, - STR_TERMINATE, &ntstatus, &mask_contains_wcard); + if (req->posix_pathnames) { + srvstr_get_path_wcard_posix(talloc_tos(), + params, + req->flags2, + &directory, + params+12, + total_params - 12, + STR_TERMINATE, + &ntstatus, + &mask_contains_wcard); + } else { + srvstr_get_path_wcard(talloc_tos(), + params, + req->flags2, + &directory, + params+12, + total_params - 12, + STR_TERMINATE, + &ntstatus, + &mask_contains_wcard); + } if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); goto out; @@ -2428,7 +2725,8 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da if (backup_priv) { become_root(); - ntstatus = filename_convert_with_privilege(ctx, + as_root = true; + ntstatus = filename_convert_with_privilege(talloc_tos(), conn, req, directory, @@ -2436,8 +2734,7 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da &mask_contains_wcard, &smb_dname); } else { - ntstatus = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, + ntstatus = filename_convert(talloc_tos(), conn, directory, ucf_flags, &mask_contains_wcard, @@ -2462,7 +2759,7 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da if(p == NULL) { /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */ if((directory[0] == '.') && (directory[1] == '\0')) { - mask = talloc_strdup(ctx,"*"); + mask = talloc_strdup(talloc_tos(),"*"); if (!mask) { reply_nterror(req, NT_STATUS_NO_MEMORY); goto out; @@ -2480,12 +2777,14 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da reply_nterror(req, NT_STATUS_NO_MEMORY); goto out; } + /* Ensure smb_dname->base_name matches. */ + smb_dname->base_name = directory; } DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); if (info_level == SMB_FIND_EA_LIST) { - uint32 ea_size; + uint32_t ea_size; if (total_data < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2506,7 +2805,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } /* Pull out the list of names. */ - ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); + ea_list = read_ea_name_list(talloc_tos(), pdata + 4, ea_size - 4); if (!ea_list) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); goto out; @@ -2526,7 +2825,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } pdata = *ppdata; data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1; - + /* + * squash valgrind "writev(vector[...]) points to uninitialised byte(s)" + * error. + */ + memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data)); /* Realloc the params space */ *pparams = (char *)SMB_REALLOC(*pparams, 10); if (*pparams == NULL) { @@ -2541,7 +2844,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd ntstatus = dptr_create(conn, req, NULL, /* fsp */ - directory, + smb_dname, False, True, req->smbpid, @@ -2571,9 +2874,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd 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(talloc_tos(), SNUM(conn)))); + if (in_list(directory, + lp_dont_descend(talloc_tos(), SNUM(conn)), + conn->case_sensitive)) { dont_descend = True; + } p = pdata; space_remaining = max_data_bytes; @@ -2588,7 +2894,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd out_of_space = True; finished = False; } else { - finished = !get_lanman2_dir_entry(ctx, + ntstatus = get_lanman2_dir_entry(talloc_tos(), conn, dirptr, req->flags2, @@ -2596,14 +2902,24 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd requires_resume_key,dont_descend, ask_sharemode, &p,pdata,data_end, - space_remaining, &out_of_space, + space_remaining, &got_exact_match, &last_entry_off, ea_list); + if (NT_STATUS_EQUAL(ntstatus, + NT_STATUS_ILLEGAL_CHARACTER)) { + /* + * Bad character conversion on name. Ignore this + * entry. + */ + continue; + } + if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) { + out_of_space = true; + } else { + finished = !NT_STATUS_IS_OK(ntstatus); + } } - if (finished && out_of_space) - finished = False; - if (!finished && !out_of_space) numentries++; @@ -2688,7 +3004,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } out: - if (backup_priv) { + if (as_root) { unbecome_root(); } @@ -2716,9 +3032,9 @@ static void call_trans2findnext(connection_struct *conn, char *data_end; int dptr_num; int maxentries; - uint16 info_level; - uint32 resume_key; - uint16 findnext_flags; + uint16_t info_level; + uint32_t resume_key; + uint16_t findnext_flags; bool close_after_request; bool close_if_end; bool requires_resume_key; @@ -2728,7 +3044,7 @@ static void call_trans2findnext(connection_struct *conn, const char *mask = NULL; const char *directory = NULL; char *p = NULL; - uint16 dirtype; + uint16_t dirtype; int numentries = 0; int i, last_entry_off=0; bool finished = False; @@ -2742,6 +3058,7 @@ static void call_trans2findnext(connection_struct *conn, struct dptr_struct *dirptr; struct smbd_server_connection *sconn = req->sconn; bool backup_priv = false; + bool as_root = false; if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2760,10 +3077,27 @@ static void call_trans2findnext(connection_struct *conn, if (!continue_bit) { /* We only need resume_name if continue_bit is zero. */ - srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name, - params+12, - total_params - 12, STR_TERMINATE, &ntstatus, - &mask_contains_wcard); + if (req->posix_pathnames) { + srvstr_get_path_wcard_posix(ctx, + params, + req->flags2, + &resume_name, + params+12, + total_params - 12, + STR_TERMINATE, + &ntstatus, + &mask_contains_wcard); + } else { + srvstr_get_path_wcard(ctx, + params, + req->flags2, + &resume_name, + params+12, + total_params - 12, + STR_TERMINATE, + &ntstatus, + &mask_contains_wcard); + } if (!NT_STATUS_IS_OK(ntstatus)) { /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to complain (it thinks we're asking for the directory above the shared @@ -2819,7 +3153,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n", } if (info_level == SMB_FIND_EA_LIST) { - uint32 ea_size; + uint32_t ea_size; if (total_data < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2862,6 +3196,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd pdata = *ppdata; data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1; + /* + * squash valgrind "writev(vector[...]) points to uninitialised byte(s)" + * error. + */ + memset(pdata + total_data, 0, (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data); /* Realloc the params space */ *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD); if(*pparams == NULL ) { @@ -2915,6 +3254,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (backup_priv) { become_root(); + as_root = true; } /* @@ -2964,7 +3304,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd out_of_space = True; finished = False; } else { - finished = !get_lanman2_dir_entry(ctx, + ntstatus = get_lanman2_dir_entry(ctx, conn, dirptr, req->flags2, @@ -2972,14 +3312,24 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd requires_resume_key,dont_descend, ask_sharemode, &p,pdata,data_end, - space_remaining, &out_of_space, + space_remaining, &got_exact_match, &last_entry_off, ea_list); + if (NT_STATUS_EQUAL(ntstatus, + NT_STATUS_ILLEGAL_CHARACTER)) { + /* + * Bad character conversion on name. Ignore this + * entry. + */ + continue; + } + if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) { + out_of_space = true; + } else { + finished = !NT_STATUS_IS_OK(ntstatus); + } } - if (finished && out_of_space) - finished = False; - if (!finished && !out_of_space) numentries++; @@ -3006,7 +3356,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd dptr_close(sconn, &dptr_num); /* This frees up the saved mask */ } - if (backup_priv) { + if (as_root) { unbecome_root(); } @@ -3063,7 +3413,8 @@ static void samba_extended_info_version(struct smb_extended_info *extended_info) "%s", samba_version_string()); } -NTSTATUS smbd_do_qfsinfo(connection_struct *conn, +NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn, + connection_struct *conn, TALLOC_CTX *mem_ctx, uint16_t info_level, uint16_t flags2, @@ -3074,15 +3425,18 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn, int *ret_data_len) { char *pdata, *end_data; - int data_len = 0, len; + int data_len = 0; + size_t len = 0; const char *vname = volume_label(talloc_tos(), SNUM(conn)); int snum = SNUM(conn); const char *fstype = lp_fstype(SNUM(conn)); const char *filename = NULL; - uint32 additional_flags = 0; + const uint64_t bytes_per_sector = 512; + uint32_t additional_flags = 0; struct smb_filename smb_fname; SMB_STRUCT_STAT st; NTSTATUS status = NT_STATUS_OK; + uint64_t df_ret; if (fname == NULL || fname->base_name == NULL) { filename = "."; @@ -3130,9 +3484,11 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn, switch (info_level) { case SMB_INFO_ALLOCATION: { - uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; + uint64_t dfree,dsize,bsize,block_size,sectors_per_unit; data_len = 18; - if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) { + df_ret = get_dfree_info(conn, &smb_fname, &bsize, + &dfree, &dsize); + if (df_ret == (uint64_t)-1) { return map_nt_error_from_unix(errno); } @@ -3149,13 +3505,18 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn, dsize *= factor; dfree *= factor; } - bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); + /* + * For large drives, return max values and not modulo. + */ + dsize = MIN(dsize, UINT32_MAX); + dfree = MIN(dfree, UINT32_MAX); + SIVAL(pdata,l1_idFileSystem,st.st_ex_dev); SIVAL(pdata,l1_cSectorUnit,sectors_per_unit); SIVAL(pdata,l1_cUnit,dsize); @@ -3177,16 +3538,19 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u * this call so try fixing this by adding a terminating null to * the pushed string. The change here was adding the STR_TERMINATE. JRA. */ - len = srvstr_push( + status = srvstr_push( pdata, flags2, pdata+l2_vol_szVolLabel, vname, PTR_DIFF(end_data, pdata+l2_vol_szVolLabel), - STR_NOALIGN|STR_TERMINATE); + STR_NOALIGN|STR_TERMINATE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SCVAL(pdata,l2_vol_cch,len); data_len = l2_vol_szVolLabel + len; - DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n", + DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %u, name = %s\n", (unsigned)convert_timespec_to_time_t(st.st_ex_ctime), - len, vname)); + (unsigned)len, vname)); break; case SMB_QUERY_FS_ATTRIBUTE_INFO: @@ -3214,9 +3578,12 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u SIVAL(pdata,4,255); /* Max filename component length */ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it and will think we can't do long filenames */ - len = srvstr_push(pdata, flags2, pdata+12, fstype, + status = srvstr_push(pdata, flags2, pdata+12, fstype, PTR_DIFF(end_data, pdata+12), - STR_UNICODE); + STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(pdata,8,len); data_len = 12 + len; if (max_data_bytes >= 16 && data_len > max_data_bytes) { @@ -3230,8 +3597,11 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u case SMB_QUERY_FS_LABEL_INFO: case SMB_FS_LABEL_INFORMATION: - len = srvstr_push(pdata, flags2, pdata+4, vname, - PTR_DIFF(end_data, pdata+4), 0); + status = srvstr_push(pdata, flags2, pdata+4, vname, + PTR_DIFF(end_data, pdata+4), 0, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } data_len = 4 + len; SIVAL(pdata,0,len); break; @@ -3247,9 +3617,12 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u (str_checksum(get_local_machine_name())<<16)); /* Max label len is 32 characters. */ - len = srvstr_push(pdata, flags2, pdata+18, vname, + status = srvstr_push(pdata, flags2, pdata+18, vname, PTR_DIFF(end_data, pdata+18), - STR_UNICODE); + STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(pdata,12,len); data_len = 18+len; @@ -3268,9 +3641,11 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u case SMB_QUERY_FS_SIZE_INFO: case SMB_FS_SIZE_INFORMATION: { - uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; + uint64_t dfree,dsize,bsize,block_size,sectors_per_unit; data_len = 24; - if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) { + df_ret = get_dfree_info(conn, &smb_fname, &bsize, + &dfree, &dsize); + if (df_ret == (uint64_t)-1) { return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); @@ -3286,7 +3661,6 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u dsize *= factor; dfree *= factor; } - bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, @@ -3301,9 +3675,11 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned case SMB_FS_FULL_SIZE_INFORMATION: { - uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; + uint64_t dfree,dsize,bsize,block_size,sectors_per_unit; data_len = 32; - if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) { + df_ret = get_dfree_info(conn, &smb_fname, &bsize, + &dfree, &dsize); + if (df_ret == (uint64_t)-1) { return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); @@ -3319,7 +3695,6 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned dsize *= factor; dfree *= factor; } - bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, @@ -3391,9 +3766,11 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned return NT_STATUS_ACCESS_DENIED; } - if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { + 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)))); - return map_nt_error_from_unix(errno); + return status; } data_len = 48; @@ -3437,6 +3814,34 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned break; } + case SMB_FS_SECTOR_SIZE_INFORMATION: + { + data_len = 28; + /* + * These values match a physical Windows Server 2012 + * share backed by NTFS atop spinning rust. + */ + DEBUG(5, ("SMB_FS_SECTOR_SIZE_INFORMATION:")); + /* logical_bytes_per_sector */ + SIVAL(pdata, 0, bytes_per_sector); + /* phys_bytes_per_sector_atomic */ + SIVAL(pdata, 4, bytes_per_sector); + /* phys_bytes_per_sector_perf */ + SIVAL(pdata, 8, bytes_per_sector); + /* fs_effective_phys_bytes_per_sector_atomic */ + SIVAL(pdata, 12, bytes_per_sector); + /* flags */ + SIVAL(pdata, 16, SSINFO_FLAGS_ALIGNED_DEVICE + | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE); + /* byte_off_sector_align */ + SIVAL(pdata, 20, 0); + /* byte_off_partition_align */ + SIVAL(pdata, 24, 0); + *fixed_portion = 28; + break; + } + + /* * Query the version and capabilities of the CIFS UNIX extensions * in use. @@ -3445,8 +3850,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(conn->sconn); - bool large_read = !srv_is_signing_active(conn->sconn); + !srv_is_signing_active(xconn); + bool large_read = !srv_is_signing_active(xconn); int encrypt_caps = 0; if (!lp_unix_extensions()) { @@ -3457,6 +3862,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned case SMB_SIGNING_OFF: encrypt_caps = 0; break; + case SMB_SIGNING_DESIRED: case SMB_SIGNING_IF_REQUIRED: case SMB_SIGNING_DEFAULT: encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP; @@ -3498,7 +3904,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned return NT_STATUS_INVALID_LEVEL; } - rc = SMB_VFS_STATVFS(conn, filename, &svfs); + rc = SMB_VFS_STATVFS(conn, &smb_fname, &svfs); if (!rc) { data_len = 56; @@ -3613,7 +4019,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned &conn->session_info->security_token->sids[i], 0); - sid_linearize(pdata + data_len, sid_len, + sid_linearize((uint8_t *)(pdata + data_len), + sid_len, &conn->session_info->security_token->sids[i]); data_len += sid_len; } @@ -3640,6 +4047,86 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned return status; } +static NTSTATUS smb_set_fsquota(connection_struct *conn, + struct smb_request *req, + files_struct *fsp, + const DATA_BLOB *qdata) +{ + NTSTATUS status; + SMB_NTQUOTA_STRUCT quotas; + + ZERO_STRUCT(quotas); + + /* 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)), + conn->session_info->unix_info->unix_name)); + return NT_STATUS_ACCESS_DENIED; + } + + if (!check_fsp_ntquota_handle(conn, req, + fsp)) { + DEBUG(1, ("set_fsquota: no valid QUOTA HANDLE\n")); + return NT_STATUS_INVALID_HANDLE; + } + + /* note: normally there're 48 bytes, + * but we didn't use the last 6 bytes for now + * --metze + */ + if (qdata->length < 42) { + DEBUG(0,("set_fsquota: requires total_data(%u) >= 42 bytes!\n", + (unsigned int)qdata->length)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* unknown_1 24 NULL bytes in pdata*/ + + /* the soft quotas 8 bytes (uint64_t)*/ + quotas.softlim = BVAL(qdata->data,24); + + /* the hard quotas 8 bytes (uint64_t)*/ + quotas.hardlim = BVAL(qdata->data,32); + + /* quota_flags 2 bytes **/ + quotas.qflags = SVAL(qdata->data,40); + + /* unknown_2 6 NULL bytes follow*/ + + /* 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)))); + status = map_nt_error_from_unix(errno); + } else { + status = NT_STATUS_OK; + } + return status; +} + +NTSTATUS smbd_do_setfsinfo(connection_struct *conn, + struct smb_request *req, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + const DATA_BLOB *pdata) +{ + switch (info_level) { + case SMB_FS_QUOTA_INFORMATION: + { + return smb_set_fsquota(conn, + req, + fsp, + pdata); + } + + default: + break; + } + return NT_STATUS_INVALID_LEVEL; +} + /**************************************************************************** Reply to a TRANS2_QFSINFO (query filesystem info). ****************************************************************************/ @@ -3675,7 +4162,7 @@ static void call_trans2qfsinfo(connection_struct *conn, DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - status = smbd_do_qfsinfo(conn, req, + status = smbd_do_qfsinfo(req->xconn, conn, req, info_level, req->flags2, max_data_bytes, @@ -3706,10 +4193,10 @@ static void call_trans2setfsinfo(connection_struct *conn, char **ppdata, int total_data, unsigned int max_data_bytes) { - struct smbd_server_connection *sconn = req->sconn; + struct smbXsrv_connection *xconn = req->xconn; char *pdata = *ppdata; char *params = *pparams; - uint16 info_level; + uint16_t info_level; DEBUG(10,("call_trans2setfsinfo: for service [%s]\n", lp_servicename(talloc_tos(), SNUM(conn)))); @@ -3763,31 +4250,31 @@ static void call_trans2setfsinfo(connection_struct *conn, NT_STATUS_INVALID_PARAMETER); return; } - sconn->smb1.unix_info.client_major = SVAL(pdata,0); - sconn->smb1.unix_info.client_minor = SVAL(pdata,2); - sconn->smb1.unix_info.client_cap_low = IVAL(pdata,4); - sconn->smb1.unix_info.client_cap_high = IVAL(pdata,8); + xconn->smb1.unix_info.client_major = SVAL(pdata,0); + xconn->smb1.unix_info.client_minor = SVAL(pdata,2); + xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4); + xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8); /* Just print these values for now. */ DEBUG(10, ("call_trans2setfsinfo: set unix_info info. " "major = %u, minor = %u cap_low = 0x%x, " "cap_high = 0x%xn", - (unsigned int)sconn-> + (unsigned int)xconn-> smb1.unix_info.client_major, - (unsigned int)sconn-> + (unsigned int)xconn-> smb1.unix_info.client_minor, - (unsigned int)sconn-> + (unsigned int)xconn-> smb1.unix_info.client_cap_low, - (unsigned int)sconn-> + (unsigned int)xconn-> smb1.unix_info.client_cap_high)); /* Here is where we must switch to posix pathname processing... */ - if (sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) { + if (xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) { lp_set_posix_pathnames(); mangle_change_to_posix(); } - if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) && - !(sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) { + if ((xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) && + !(xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) { /* Client that knows how to do posix locks, * but not posix open/mkdir operations. Set a * default type for read/write checks. */ @@ -3817,7 +4304,7 @@ static void call_trans2setfsinfo(connection_struct *conn, return; } - if (req->sconn->smb1.echo_handler.trusted_fde) { + if (xconn->smb1.echo_handler.trusted_fde) { DEBUG( 2,("call_trans2setfsinfo: " "request transport encryption disabled" "with 'fork echo handler = yes'\n")); @@ -3867,63 +4354,22 @@ static void call_trans2setfsinfo(connection_struct *conn, case SMB_FS_QUOTA_INFORMATION: { + NTSTATUS status; + DATA_BLOB qdata = { + .data = (uint8_t *)pdata, + .length = total_data + }; files_struct *fsp = NULL; - SMB_NTQUOTA_STRUCT quotas; - - ZERO_STRUCT(quotas); - - /* access check */ - if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) { - DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", - lp_servicename(talloc_tos(), SNUM(conn)), - conn->session_info->unix_info->unix_name)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - /* note: normaly there're 48 bytes, - * but we didn't use the last 6 bytes for now - * --metze - */ fsp = file_fsp(req, SVAL(params,0)); - if (!check_fsp_ntquota_handle(conn, req, - fsp)) { - DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); - reply_nterror( - req, NT_STATUS_INVALID_HANDLE); - return; - } - - if (total_data < 42) { - DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n", - total_data)); - reply_nterror( - req, - NT_STATUS_INVALID_PARAMETER); - return; - } - - /* unknown_1 24 NULL bytes in pdata*/ - - /* the soft quotas 8 bytes (uint64_t)*/ - quotas.softlim = BVAL(pdata,24); - - /* the hard quotas 8 bytes (uint64_t)*/ - quotas.hardlim = BVAL(pdata,32); - - /* quota_flags 2 bytes **/ - quotas.qflags = SVAL(pdata,40); - - /* unknown_2 6 NULL bytes follow*/ - - /* now set the quotas */ - if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { - DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn)))); - reply_nterror(req, map_nt_error_from_unix(errno)); + status = smb_set_fsquota(conn, + req, + fsp, + &qdata); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); return; } - break; } default: @@ -4160,7 +4606,7 @@ static const struct {unsigned stat_fflag; unsigned smb_fflag;} }; static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf, - uint32 *smb_fflags, uint32 *smb_fmask) + uint32_t *smb_fflags, uint32_t *smb_fmask) { int i; @@ -4173,11 +4619,11 @@ static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf, } static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf, - const uint32 smb_fflags, - const uint32 smb_fmask, + const uint32_t smb_fflags, + const uint32_t smb_fmask, int *stat_fflags) { - uint32 max_fmask = 0; + uint32_t max_fmask = 0; int i; *stat_fflags = psbuf->st_ex_flags; @@ -4217,8 +4663,8 @@ static char *store_file_unix_basic_info2(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *psbuf) { - uint32 file_flags = 0; - uint32 flags_mask = 0; + uint32_t file_flags = 0; + uint32_t flags_mask = 0; pdata = store_file_unix_basic(conn, pdata, fsp, psbuf); @@ -4330,7 +4776,7 @@ static void call_trans2qpipeinfo(connection_struct *conn, char *pdata = *ppdata; unsigned int data_size = 0; unsigned int param_size = 2; - uint16 info_level; + uint16_t info_level; files_struct *fsp; if (!params) { @@ -4423,6 +4869,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, uint64_t allocation_size = 0; uint64_t file_index = 0; uint32_t access_mask = 0; + size_t len = 0; if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { return NT_STATUS_INVALID_LEVEL; @@ -4552,8 +4999,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, srv_put_dos_date2(pdata,l1_fdateCreation,create_time); srv_put_dos_date2(pdata,l1_fdateLastAccess,atime); srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */ - SIVAL(pdata,l1_cbFile,(uint32)file_size); - SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size); + SIVAL(pdata,l1_cbFile,(uint32_t)file_size); + SIVAL(pdata,l1_cbFileAlloc,(uint32_t)allocation_size); SSVAL(pdata,l1_attrFile,mode); break; @@ -4567,8 +5014,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, srv_put_dos_date2(pdata,0,create_time); srv_put_dos_date2(pdata,4,atime); srv_put_dos_date2(pdata,8,mtime); /* write time */ - SIVAL(pdata,12,(uint32)file_size); - SIVAL(pdata,16,(uint32)allocation_size); + SIVAL(pdata,12,(uint32_t)file_size); + SIVAL(pdata,16,(uint32_t)allocation_size); SSVAL(pdata,20,mode); SIVAL(pdata,22,ea_size); break; @@ -4724,17 +5171,19 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_ALT_NAME_INFO: case SMB_FILE_ALTERNATE_NAME_INFORMATION: { - int len; char mangled_name[13]; DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); if (!name_to_8_3(base_name,mangled_name, True,conn->params)) { return NT_STATUS_NO_MEMORY; } - len = srvstr_push(dstart, flags2, + status = srvstr_push(dstart, flags2, pdata+4, mangled_name, PTR_DIFF(dend, pdata+4), - STR_UNICODE); + STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } data_size = 4 + len; SIVAL(pdata,0,len); *fixed_portion = 8; @@ -4743,14 +5192,16 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_NAME_INFO: { - int len; /* this must be *exactly* right for ACLs on mapped drives to work */ - len = srvstr_push(dstart, flags2, + status = srvstr_push(dstart, flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), - STR_UNICODE); + STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n")); data_size = 4 + len; SIVAL(pdata,0,len); @@ -4774,7 +5225,6 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_ALL_INFO: case SMB_FILE_ALL_INFORMATION: { - int len; unsigned int ea_size = estimate_ea_size(conn, fsp, smb_fname); DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n")); @@ -4794,10 +5244,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, pdata += 24; SIVAL(pdata,0,ea_size); pdata += 4; /* EA info */ - len = srvstr_push(dstart, flags2, + status = srvstr_push(dstart, flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), - STR_UNICODE); + STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(pdata,0,len); pdata += 4 + len; data_size = PTR_DIFF(pdata,(*ppdata)); @@ -4807,7 +5260,6 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/ { - int len; unsigned int ea_size = estimate_ea_size(conn, fsp, smb_fname); DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n")); @@ -4832,10 +5284,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, pdata += 0x60; - len = srvstr_push(dstart, flags2, + status = srvstr_push(dstart, flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), - STR_UNICODE); + STR_UNICODE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } SIVAL(pdata,0,len); pdata += 4 + len; data_size = PTR_DIFF(pdata,(*ppdata)); @@ -4916,8 +5371,12 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - status = vfs_streaminfo(conn, fsp, smb_fname->base_name, - talloc_tos(), &num_streams, &streams); + status = vfs_streaminfo(conn, + fsp, + smb_fname, + talloc_tos(), + &num_streams, + &streams); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("could not get stream info: %s\n", @@ -5007,7 +5466,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_UNIX_LINK: { - int len; + int link_len = 0; char *buffer = talloc_array(mem_ctx, char, PATH_MAX+1); if (!buffer) { @@ -5022,17 +5481,20 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, #else return NT_STATUS_DOS(ERRDOS, ERRbadlink); #endif - len = SMB_VFS_READLINK(conn, - smb_fname->base_name, + link_len = SMB_VFS_READLINK(conn, + smb_fname, buffer, PATH_MAX); - if (len == -1) { + if (link_len == -1) { return map_nt_error_from_unix(errno); } - buffer[len] = 0; - len = srvstr_push(dstart, flags2, + buffer[link_len] = 0; + status = srvstr_push(dstart, flags2, pdata, buffer, PTR_DIFF(dend, pdata), - STR_TERMINATE); + STR_TERMINATE, &len); + if (!NT_STATUS_IS_OK(status)) { + return status; + } pdata += len; data_size = PTR_DIFF(pdata,(*ppdata)); @@ -5044,8 +5506,15 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, { SMB_ACL_T file_acl = NULL; SMB_ACL_T def_acl = NULL; - uint16 num_file_acls = 0; - uint16 num_def_acls = 0; + uint16_t num_file_acls = 0; + uint16_t num_def_acls = 0; + + status = refuse_symlink(conn, + fsp, + smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (fsp && fsp->fh->fd != -1) { file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, @@ -5053,7 +5522,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, } else { file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, - smb_fname->base_name, + smb_fname, SMB_ACL_TYPE_ACCESS, talloc_tos()); } @@ -5071,14 +5540,14 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, - fsp->fsp_name->base_name, + fsp->fsp_name, SMB_ACL_TYPE_DEFAULT, talloc_tos()); } else { def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, - smb_fname->base_name, + smb_fname, SMB_ACL_TYPE_DEFAULT, talloc_tos()); } @@ -5166,15 +5635,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, } smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET); -#if defined(HAVE_LONGLONG) - offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) | - ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET)); - count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) | - ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET)); -#else /* HAVE_LONGLONG */ - offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET); - count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET); -#endif /* HAVE_LONGLONG */ + offset = BVAL(pdata,POSIX_LOCK_START_OFFSET); + count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET); status = query_lock(fsp, &smblctx, @@ -5190,15 +5652,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type); SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0); SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx); -#if defined(HAVE_LONGLONG) - SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF)); - SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF)); - SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF)); - SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF)); -#else /* HAVE_LONGLONG */ - SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset); - SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count); -#endif /* HAVE_LONGLONG */ + SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset); + SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count); } else if (NT_STATUS_IS_OK(status)) { /* For success we just return a copy of what we sent @@ -5234,7 +5689,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, { char *params = *pparams; char *pdata = *ppdata; - uint16 info_level; + uint16_t info_level; unsigned int data_size = 0; unsigned int param_size = 2; struct smb_filename *smb_fname = NULL; @@ -5346,7 +5801,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, } else { uint32_t name_hash; char *fname = NULL; - uint32_t ucf_flags = 0; + uint32_t ucf_flags = ucf_flags_from_smb_request(req); /* qpathinfo */ if (total_params < 7) { @@ -5365,14 +5820,31 @@ static void call_trans2qfilepathinfo(connection_struct *conn, } if (info_level == SMB_QUERY_FILE_UNIX_BASIC || info_level == SMB_QUERY_FILE_UNIX_INFO2 || - info_level == SMB_QUERY_FILE_UNIX_LINK) { + info_level == SMB_QUERY_FILE_UNIX_LINK || + req->posix_pathnames) { ucf_flags |= UCF_UNIX_NAME_LOOKUP; } } - srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], + if (req->posix_pathnames) { + srvstr_get_path_posix(req, + params, + req->flags2, + &fname, + ¶ms[6], total_params - 6, - STR_TERMINATE, &status); + STR_TERMINATE, + &status); + } else { + srvstr_get_path(req, + params, + req->flags2, + &fname, + ¶ms[6], + total_params - 6, + STR_TERMINATE, + &status); + } if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; @@ -5380,7 +5852,6 @@ static void call_trans2qfilepathinfo(connection_struct *conn, status = filename_convert(req, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, fname, ucf_flags, NULL, @@ -5403,14 +5874,17 @@ static void call_trans2qfilepathinfo(connection_struct *conn, /* Create an smb_filename with stream_name == NULL. */ smb_fname_base = synthetic_smb_fname( - talloc_tos(), smb_fname->base_name, - NULL, NULL); + talloc_tos(), + smb_fname->base_name, + NULL, + NULL, + smb_fname->flags); if (smb_fname_base == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); return; } - if (INFO_LEVEL_IS_UNIX(info_level)) { + if (INFO_LEVEL_IS_UNIX(info_level) || req->posix_pathnames) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) { DEBUG(3,("call_trans2qfilepathinfo: " @@ -5456,7 +5930,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, } } - if (INFO_LEVEL_IS_UNIX(info_level)) { + if (INFO_LEVEL_IS_UNIX(info_level) || req->posix_pathnames) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn, smb_fname)) { DEBUG(3,("call_trans2qfilepathinfo: " @@ -5506,7 +5980,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, case SMB_INFO_QUERY_EAS_FROM_LIST: { /* Pull any EA list from the data portion. */ - uint32 ea_size; + uint32_t ea_size; if (total_data < 4) { reply_nterror( @@ -5674,8 +6148,7 @@ 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->base_name, - smb_fname_new->base_name) != 0) { + if (SMB_VFS_LINK(conn, smb_fname_old, smb_fname_new) != 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, @@ -5697,7 +6170,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn, bool setting_write_time) { struct smb_filename smb_fname_base; - uint32 action = + uint32_t action = FILE_NOTIFY_CHANGE_LAST_ACCESS |FILE_NOTIFY_CHANGE_LAST_WRITE |FILE_NOTIFY_CHANGE_CREATION; @@ -5792,7 +6265,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn, static NTSTATUS smb_set_file_dosmode(connection_struct *conn, const struct smb_filename *smb_fname, - uint32 dosmode) + uint32_t dosmode) { struct smb_filename *smb_fname_base; NTSTATUS status; @@ -5802,8 +6275,11 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn, } /* Always operate on the base_name, even if a stream was passed in. */ - smb_fname_base = synthetic_smb_fname( - talloc_tos(), smb_fname->base_name, NULL, &smb_fname->st); + smb_fname_base = synthetic_smb_fname(talloc_tos(), + smb_fname->base_name, + NULL, + &smb_fname->st, + smb_fname->flags); if (smb_fname_base == NULL) { return NT_STATUS_NO_MEMORY; } @@ -5901,12 +6377,14 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, 0, /* create_options */ FILE_ATTRIBUTE_NORMAL, /* file_attributes */ 0, /* oplock_request */ + NULL, /* lease */ 0, /* allocation_size */ 0, /* private_flags */ NULL, /* sd */ NULL, /* ea_list */ &new_fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + NULL, NULL); /* create context */ TALLOC_FREE(smb_fname_tmp); @@ -6036,7 +6514,7 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, { NTSTATUS status = NT_STATUS_OK; bool delete_on_close; - uint32 dosmode = 0; + uint32_t dosmode = 0; if (total_data < 1) { return NT_STATUS_INVALID_PARAMETER; @@ -6109,7 +6587,7 @@ static NTSTATUS smb_file_mode_information(connection_struct *conn, const char *pdata, int total_data) { - uint32 mode; + uint32_t mode; if (total_data < 4) { return NT_STATUS_INVALID_PARAMETER; @@ -6129,10 +6607,9 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - const struct smb_filename *smb_fname) + const struct smb_filename *new_smb_fname) { char *link_target = NULL; - const char *newname = smb_fname->base_name; TALLOC_CTX *ctx = talloc_tos(); /* Set a symbolic link. */ @@ -6154,9 +6631,9 @@ 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", - newname, link_target )); + new_smb_fname->base_name, link_target )); - if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) { + if (SMB_VFS_SYMLINK(conn,link_target,new_smb_fname) != 0) { return map_nt_error_from_unix(errno); } @@ -6174,6 +6651,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, { char *oldname = NULL; struct smb_filename *smb_fname_old = NULL; + uint32_t ucf_flags = ucf_flags_from_smb_request(req); TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status = NT_STATUS_OK; @@ -6182,8 +6660,25 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata, - total_data, STR_TERMINATE, &status); + if (req->posix_pathnames) { + srvstr_get_path_posix(ctx, + pdata, + req->flags2, + &oldname, + pdata, + total_data, + STR_TERMINATE, + &status); + } else { + srvstr_get_path(ctx, + pdata, + req->flags2, + &oldname, + pdata, + total_data, + STR_TERMINATE, + &status); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6193,9 +6688,8 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, oldname, - 0, + ucf_flags, NULL, &smb_fname_old); if (!NT_STATUS_IS_OK(status)) { @@ -6221,6 +6715,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); NTSTATUS status = NT_STATUS_OK; TALLOC_CTX *ctx = talloc_tos(); @@ -6239,9 +6735,25 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - srvstr_get_path(ctx, pdata, req->flags2, &newname, - &pdata[20], len, STR_TERMINATE, + if (req->posix_pathnames) { + srvstr_get_path_posix(ctx, + pdata, + req->flags2, + &newname, + &pdata[20], + len, + STR_TERMINATE, + &status); + } else { + srvstr_get_path(ctx, + pdata, + req->flags2, + &newname, + &pdata[20], + len, + STR_TERMINATE, &status); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6251,9 +6763,8 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, newname, - UCF_SAVE_LCOMP, + ucf_flags, NULL, &smb_fname_dst); if (!NT_STATUS_IS_OK(status)) { @@ -6267,9 +6778,11 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, } /* Create an smb_fname to call rename_internals_fsp() with. */ - smb_fname_dst = synthetic_smb_fname( - talloc_tos(), fsp->base_fsp->fsp_name->base_name, - newname, NULL); + smb_fname_dst = synthetic_smb_fname(talloc_tos(), + fsp->base_fsp->fsp_name->base_name, + newname, + NULL, + fsp->base_fsp->fsp_name->flags); if (smb_fname_dst == NULL) { status = NT_STATUS_NO_MEMORY; goto out; @@ -6313,6 +6826,8 @@ 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); TALLOC_CTX *ctx = talloc_tos(); if (!fsp) { @@ -6330,9 +6845,25 @@ static NTSTATUS smb_file_link_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - srvstr_get_path(ctx, pdata, req->flags2, &newname, - &pdata[20], len, STR_TERMINATE, + if (req->posix_pathnames) { + srvstr_get_path_posix(ctx, + pdata, + req->flags2, + &newname, + &pdata[20], + len, + STR_TERMINATE, &status); + } else { + srvstr_get_path(ctx, + pdata, + req->flags2, + &newname, + &pdata[20], + len, + STR_TERMINATE, + &status); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6342,9 +6873,8 @@ static NTSTATUS smb_file_link_information(connection_struct *conn, status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, newname, - UCF_SAVE_LCOMP, + ucf_flags, NULL, &smb_fname_dst); if (!NT_STATUS_IS_OK(status)) { @@ -6383,8 +6913,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, struct smb_filename *smb_fname_src) { bool overwrite; - uint32 root_fid; - uint32 len; + uint32_t root_fid; + uint32_t len; char *newname = NULL; struct smb_filename *smb_fname_dst = NULL; bool dest_has_wcard = False; @@ -6404,9 +6934,27 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12], - len, 0, &status, - &dest_has_wcard); + if (req->posix_pathnames) { + srvstr_get_path_wcard_posix(ctx, + pdata, + req->flags2, + &newname, + &pdata[12], + len, + 0, + &status, + &dest_has_wcard); + } else { + srvstr_get_path_wcard(ctx, + pdata, + req->flags2, + &newname, + &pdata[12], + len, + 0, + &status, + &dest_has_wcard); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6414,15 +6962,16 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, DEBUG(10,("smb_file_rename_information: got name |%s|\n", newname)); - status = resolve_dfspath_wcard(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, + if (req->flags2 & FLAGS2_DFS_PATHNAMES) { + status = resolve_dfspath_wcard(ctx, conn, newname, - true, + UCF_COND_ALLOW_WCARD_LCOMP, !conn->sconn->using_smb2, &newname, &dest_has_wcard); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (!NT_STATUS_IS_OK(status)) { + return status; + } } /* Check the new name has no '/' characters. */ @@ -6437,9 +6986,11 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, } /* Create an smb_fname to call rename_internals_fsp() with. */ - smb_fname_dst = synthetic_smb_fname( - talloc_tos(), fsp->base_fsp->fsp_name->base_name, - newname, NULL); + smb_fname_dst = synthetic_smb_fname(talloc_tos(), + fsp->base_fsp->fsp_name->base_name, + newname, + NULL, + fsp->base_fsp->fsp_name->flags); if (smb_fname_dst == NULL) { status = NT_STATUS_NO_MEMORY; goto out; @@ -6463,6 +7014,12 @@ 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); + + if (dest_has_wcard) { + ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP; + } /* newname must *not* be a stream name. */ if (newname[0] == ':') { @@ -6495,10 +7052,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, } status = unix_convert(ctx, conn, base_name, &smb_fname_dst, - (UCF_SAVE_LCOMP | - (dest_has_wcard ? - UCF_ALWAYS_ALLOW_WCARD_LCOMP : - 0))); + ucf_flags); /* If an error we expect this to be * NT_STATUS_OBJECT_PATH_NOT_FOUND */ @@ -6509,8 +7063,11 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, goto out; } /* Create an smb_fname to call rename_internals_fsp() */ - smb_fname_dst = synthetic_smb_fname( - ctx, base_name, NULL, NULL); + smb_fname_dst = synthetic_smb_fname(ctx, + base_name, + NULL, + NULL, + smb_fname_src->flags); if (smb_fname_dst == NULL) { status = NT_STATUS_NO_MEMORY; goto out; @@ -6551,11 +7108,12 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname) { - uint16 posix_acl_version; - uint16 num_file_acls; - uint16 num_def_acls; + uint16_t posix_acl_version; + uint16_t num_file_acls; + uint16_t num_def_acls; bool valid_file_acls = True; bool valid_def_acls = True; + NTSTATUS status; if (total_data < SMB_POSIX_ACL_HEADER_SIZE) { return NT_STATUS_INVALID_PARAMETER; @@ -6583,19 +7141,24 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } + status = refuse_symlink(conn, fsp, smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n", smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp), (unsigned int)num_file_acls, (unsigned int)num_def_acls)); if (valid_file_acls && !set_unix_posix_acl(conn, fsp, - smb_fname->base_name, num_file_acls, + smb_fname, num_file_acls, pdata + SMB_POSIX_ACL_HEADER_SIZE)) { return map_nt_error_from_unix(errno); } if (valid_def_acls && !set_unix_posix_default_acl(conn, - smb_fname->base_name, &smb_fname->st, num_def_acls, + smb_fname, num_def_acls, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) { return map_nt_error_from_unix(errno); @@ -6661,15 +7224,10 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, } smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET); -#if defined(HAVE_LONGLONG) offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) | ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET)); count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) | ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET)); -#else /* HAVE_LONGLONG */ - offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET); - count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET); -#endif /* HAVE_LONGLONG */ DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u," "smblctx = %llu, count = %.0f, offset = %.0f\n", @@ -6698,8 +7256,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, POSIX_LOCK, blocking_lock, &status, - &block_smblctx, - NULL); + &block_smblctx); if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) { /* @@ -6740,7 +7297,7 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, { /* Patch to do this correctly from Paul Eggert . */ struct smb_file_time ft; - uint32 dosmode = 0; + uint32_t dosmode = 0; NTSTATUS status = NT_STATUS_OK; ZERO_STRUCT(ft); @@ -6892,12 +7449,14 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, 0, /* create_options */ FILE_ATTRIBUTE_NORMAL, /* file_attributes */ 0, /* oplock_request */ + NULL, /* lease */ 0, /* allocation_size */ 0, /* private_flags */ NULL, /* sd */ NULL, /* ea_list */ &new_fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + NULL, NULL); /* create context */ if (!NT_STATUS_IS_OK(status)) { /* NB. We check for open_was_deferred in the caller. */ @@ -6964,13 +7523,13 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, int total_data, const struct smb_filename *smb_fname) { - uint32 file_type = IVAL(pdata,56); + uint32_t file_type = IVAL(pdata,56); #if defined(HAVE_MAKEDEV) - uint32 dev_major = IVAL(pdata,60); - uint32 dev_minor = IVAL(pdata,68); + uint32_t dev_major = IVAL(pdata,60); + uint32_t dev_minor = IVAL(pdata,68); #endif SMB_DEV_T dev = (SMB_DEV_T)0; - uint32 raw_unixmode = IVAL(pdata,84); + uint32_t raw_unixmode = IVAL(pdata,84); NTSTATUS status; mode_t unixmode; @@ -7018,7 +7577,7 @@ 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->base_name, unixmode, dev) != 0) { + if (SMB_VFS_MKNOD(conn, smb_fname, unixmode, dev) != 0) { return map_nt_error_from_unix(errno); } @@ -7032,7 +7591,7 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, &parent, NULL)) { return NT_STATUS_NO_MEMORY; } - inherit_access_posix_acl(conn, parent, smb_fname->base_name, + inherit_access_posix_acl(conn, parent, smb_fname, unixmode); TALLOC_FREE(parent); } @@ -7052,7 +7611,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, const struct smb_filename *smb_fname) { struct smb_file_time ft; - uint32 raw_unixmode; + uint32_t raw_unixmode; mode_t unixmode; off_t size = 0; uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE; @@ -7174,7 +7733,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, if (fsp && fsp->fh->fd != -1) { ret = SMB_VFS_FCHMOD(fsp, unixmode); } else { - ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode); + ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode); } if (ret != 0) { return map_nt_error_from_unix(errno); @@ -7201,7 +7760,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * UNIX extensions calls must always operate * on symlinks. */ - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, + ret = SMB_VFS_LCHOWN(conn, smb_fname, set_owner, (gid_t)-1); } @@ -7233,7 +7792,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * UNIX extensions calls must always operate * on symlinks. */ - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, (uid_t)-1, + ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1, set_grp); } if (ret != 0) { @@ -7308,8 +7867,8 @@ static NTSTATUS smb_set_file_unix_info2(connection_struct *conn, const struct smb_filename *smb_fname) { NTSTATUS status; - uint32 smb_fflags; - uint32 smb_fmask; + uint32_t smb_fflags; + uint32_t smb_fmask; if (total_data < 116) { return NT_STATUS_INVALID_PARAMETER; @@ -7343,7 +7902,7 @@ static NTSTATUS smb_set_file_unix_info2(connection_struct *conn, /* XXX: we should be using SMB_VFS_FCHFLAGS here. */ return NT_STATUS_NOT_SUPPORTED; } else { - if (SMB_VFS_CHFLAGS(conn, smb_fname->base_name, + if (SMB_VFS_CHFLAGS(conn, smb_fname, stat_fflags) != 0) { return map_nt_error_from_unix(errno); } @@ -7370,11 +7929,11 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, int *pdata_return_size) { NTSTATUS status = NT_STATUS_OK; - uint32 raw_unixmode = 0; - uint32 mod_unixmode = 0; + uint32_t raw_unixmode = 0; + uint32_t mod_unixmode = 0; mode_t unixmode = (mode_t)0; files_struct *fsp = NULL; - uint16 info_level_return = 0; + uint16_t info_level_return = 0; int info; char *pdata = *ppdata; @@ -7391,7 +7950,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, return status; } - mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS; + mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS; DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n", smb_fname_str_dbg(smb_fname), (unsigned int)unixmode)); @@ -7407,12 +7966,14 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, FILE_DIRECTORY_FILE, /* create_options */ mod_unixmode, /* file_attributes */ 0, /* oplock_request */ + NULL, /* lease */ 0, /* allocation_size */ 0, /* private_flags */ NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + NULL, NULL); /* create context */ if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); @@ -7478,19 +8039,19 @@ static NTSTATUS smb_posix_open(connection_struct *conn, { bool extended_oplock_granted = False; char *pdata = *ppdata; - uint32 flags = 0; - uint32 wire_open_mode = 0; - uint32 raw_unixmode = 0; - uint32 mod_unixmode = 0; - uint32 create_disp = 0; - uint32 access_mask = 0; - uint32 create_options = FILE_NON_DIRECTORY_FILE; + uint32_t flags = 0; + uint32_t wire_open_mode = 0; + uint32_t raw_unixmode = 0; + uint32_t mod_unixmode = 0; + uint32_t create_disp = 0; + uint32_t access_mask = 0; + uint32_t create_options = FILE_NON_DIRECTORY_FILE; NTSTATUS status = NT_STATUS_OK; mode_t unixmode = (mode_t)0; files_struct *fsp = NULL; int oplock_request = 0; int info = 0; - uint16 info_level_return = 0; + uint16_t info_level_return = 0; if (total_data < 18) { return NT_STATUS_INVALID_PARAMETER; @@ -7601,7 +8162,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, return status; } - mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS; + mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS; if (wire_open_mode & SMB_O_SYNC) { create_options |= FILE_WRITE_THROUGH; @@ -7639,12 +8200,14 @@ static NTSTATUS smb_posix_open(connection_struct *conn, create_options, /* create_options */ mod_unixmode, /* file_attributes */ oplock_request, /* oplock_request */ + NULL, /* lease */ 0, /* allocation_size */ 0, /* private_flags */ NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + NULL, NULL); /* create context */ if (!NT_STATUS_IS_OK(status)) { return status; @@ -7727,7 +8290,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, { NTSTATUS status = NT_STATUS_OK; files_struct *fsp = NULL; - uint16 flags = 0; + uint16_t flags = 0; char del = 1; int info = 0; int create_options = 0; @@ -7769,12 +8332,14 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, create_options, /* create_options */ FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */ 0, /* oplock_request */ + NULL, /* lease */ 0, /* allocation_size */ 0, /* private_flags */ NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + NULL, NULL); /* create context */ if (!NT_STATUS_IS_OK(status)) { return status; @@ -8130,7 +8695,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, { char *params = *pparams; char *pdata = *ppdata; - uint16 info_level; + uint16_t info_level; struct smb_filename *smb_fname = NULL; files_struct *fsp = NULL; NTSTATUS status = NT_STATUS_OK; @@ -8222,7 +8787,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } } else { char *fname = NULL; - uint32_t ucf_flags = 0; + uint32_t ucf_flags = ucf_flags_from_smb_request(req); /* set path info */ if (total_params < 7) { @@ -8231,9 +8796,25 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } info_level = SVAL(params,0); - srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], - total_params - 6, STR_TERMINATE, + if (req->posix_pathnames) { + srvstr_get_path_posix(req, + params, + req->flags2, + &fname, + ¶ms[6], + total_params - 6, + STR_TERMINATE, &status); + } else { + srvstr_get_path(req, + params, + req->flags2, + &fname, + ¶ms[6], + total_params - 6, + STR_TERMINATE, + &status); + } if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; @@ -8247,7 +8828,6 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } status = filename_convert(req, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, fname, ucf_flags, NULL, @@ -8304,7 +8884,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, ppdata, total_data, &data_return_size); if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->sconn, req->mid)) { + if (open_was_deferred(req->xconn, req->mid)) { /* We have re-scheduled this call. */ return; } @@ -8356,6 +8936,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, char *directory = NULL; NTSTATUS status = NT_STATUS_OK; struct ea_list *ea_list = NULL; + uint32_t ucf_flags = ucf_flags_from_smb_request(req); TALLOC_CTX *ctx = talloc_tos(); if (!CAN_WRITE(conn)) { @@ -8368,9 +8949,25 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, return; } - srvstr_get_path(ctx, params, req->flags2, &directory, ¶ms[4], - total_params - 4, STR_TERMINATE, + if (req->posix_pathnames) { + srvstr_get_path_posix(ctx, + params, + req->flags2, + &directory, + ¶ms[4], + total_params - 4, + STR_TERMINATE, &status); + } else { + srvstr_get_path(ctx, + params, + req->flags2, + &directory, + ¶ms[4], + total_params - 4, + STR_TERMINATE, + &status); + } if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; @@ -8380,9 +8977,8 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - 0, + ucf_flags, NULL, &smb_dname); @@ -8479,7 +9075,7 @@ static void call_trans2findnotifyfirst(connection_struct *conn, unsigned int max_data_bytes) { char *params = *pparams; - uint16 info_level; + uint16_t info_level; if (total_params < 6) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -8616,6 +9212,8 @@ static void call_trans2ioctl(connection_struct *conn, { char *pdata = *ppdata; files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0)); + NTSTATUS status; + size_t len = 0; /* check for an invalid fid before proceeding */ @@ -8639,12 +9237,20 @@ static void call_trans2ioctl(connection_struct *conn, /* Job number */ SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file)); - srvstr_push(pdata, req->flags2, pdata + 2, + status = srvstr_push(pdata, req->flags2, pdata + 2, lp_netbios_name(), 15, - STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ - srvstr_push(pdata, req->flags2, pdata+18, + STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */ + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + status = srvstr_push(pdata, req->flags2, pdata+18, lp_servicename(talloc_tos(), SNUM(conn)), 13, - STR_ASCII|STR_TERMINATE); /* Service name */ + STR_ASCII|STR_TERMINATE, &len); /* Service name */ + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32, max_data_bytes); return;