diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/aio.c | 2 | ||||
-rw-r--r-- | source3/smbd/blocking.c | 85 | ||||
-rw-r--r-- | source3/smbd/close.c | 8 | ||||
-rw-r--r-- | source3/smbd/dosmode.c | 160 | ||||
-rw-r--r-- | source3/smbd/fake_file.c | 1 | ||||
-rw-r--r-- | source3/smbd/filename.c | 42 | ||||
-rw-r--r-- | source3/smbd/files.c | 74 | ||||
-rw-r--r-- | source3/smbd/ipc.c | 191 | ||||
-rw-r--r-- | source3/smbd/map_username.c | 2 | ||||
-rw-r--r-- | source3/smbd/msdfs.c | 31 | ||||
-rw-r--r-- | source3/smbd/notify.c | 86 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 147 | ||||
-rw-r--r-- | source3/smbd/open.c | 230 | ||||
-rw-r--r-- | source3/smbd/password.c | 2 | ||||
-rw-r--r-- | source3/smbd/pipes.c | 2 | ||||
-rw-r--r-- | source3/smbd/posix_acls.c | 14 | ||||
-rw-r--r-- | source3/smbd/process.c | 4 | ||||
-rw-r--r-- | source3/smbd/reply.c | 74 | ||||
-rw-r--r-- | source3/smbd/server.c | 6 | ||||
-rw-r--r-- | source3/smbd/service.c | 32 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 4 | ||||
-rw-r--r-- | source3/smbd/share_access.c | 6 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 197 | ||||
-rw-r--r-- | source3/smbd/uid.c | 11 |
24 files changed, 766 insertions, 645 deletions
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c index fd553c3fc4..8beed0744c 100644 --- a/source3/smbd/aio.c +++ b/source3/smbd/aio.c @@ -506,7 +506,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) ERROR_BOTH(map_nt_error_from_unix(ret), ERRHRD, ERRdiskfull); srv_set_message(outbuf,0,0,true); } else { - bool write_through = BITSETW(aio_ex->req->inbuf+smb_vwv7,0); + bool write_through = BITSETW(aio_ex->req->vwv+7,0); NTSTATUS status; SSVAL(outbuf,smb_vwv2,nwritten); diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 555033b7df..2237a89ace 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -505,7 +505,6 @@ static bool process_trans2(blocking_lock_record *blr) /* We finally got the lock, return success. */ - SCVAL(blr->req->inbuf, smb_com, SMBtrans2); SSVAL(params,0,0); /* Fake up max_data_bytes here - we know it fits. */ send_trans2_replies(blr->fsp->conn, blr->req, params, 2, NULL, 0, 0xffff); @@ -666,86 +665,18 @@ static void process_blocking_lock_queue(void) */ for (blr = blocking_lock_queue; blr; blr = next) { - connection_struct *conn = NULL; - uint16 vuid; - files_struct *fsp = NULL; next = blr->next; /* - * Ensure we don't have any old chain_fsp values - * sitting around.... - */ - chain_size = 0; - fsp = blr->fsp; - - conn = conn_find(blr->req->tid); - vuid = (lp_security() == SEC_SHARE) - ? UID_FIELD_INVALID : blr->req->vuid; - - DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n", - fsp->fnum, fsp->fsp_name )); - - if(!change_to_user(conn,vuid)) { - struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp); - - /* - * Remove the entry and return an error to the client. - */ - - if (br_lck) { - brl_lock_cancel(br_lck, - blr->lock_pid, - procid_self(), - blr->offset, - blr->count, - blr->lock_flav); - TALLOC_FREE(br_lck); - } - - DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n", - vuid )); - blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED); - DLIST_REMOVE(blocking_lock_queue, blr); - TALLOC_FREE(blr); - recalc_timeout = True; - continue; - } - - if(!set_current_service(conn,SVAL(blr->req->inbuf,smb_flg),True)) { - struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp); - - /* - * Remove the entry and return an error to the client. - */ - - if (br_lck) { - brl_lock_cancel(br_lck, - blr->lock_pid, - procid_self(), - blr->offset, - blr->count, - blr->lock_flav); - TALLOC_FREE(br_lck); - } - - DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) )); - blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED); - DLIST_REMOVE(blocking_lock_queue, blr); - TALLOC_FREE(blr); - recalc_timeout = True; - change_to_root_user(); - continue; - } - - /* * Go through the remaining locks and try and obtain them. * The call returns True if all locks were obtained successfully * and False if we still need to wait. */ if(blocking_lock_record_process(blr)) { - struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp); + struct byte_range_lock *br_lck = brl_get_locks( + talloc_tos(), blr->fsp); if (br_lck) { brl_lock_cancel(br_lck, @@ -760,19 +691,17 @@ static void process_blocking_lock_queue(void) DLIST_REMOVE(blocking_lock_queue, blr); TALLOC_FREE(blr); recalc_timeout = True; - change_to_root_user(); continue; } - change_to_root_user(); - /* * We couldn't get the locks for this record on the list. * If the time has expired, return a lock error. */ if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) { - struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp); + struct byte_range_lock *br_lck = brl_get_locks( + talloc_tos(), blr->fsp); /* * Lock expired - throw away all previously @@ -780,8 +709,10 @@ static void process_blocking_lock_queue(void) */ if (br_lck) { - DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n", - fsp->fnum, fsp->fsp_name )); + DEBUG(5,("process_blocking_lock_queue: " + "pending lock fnum = %d for file %s " + "timed out.\n", blr->fsp->fnum, + blr->fsp->fsp_name )); brl_lock_cancel(br_lck, blr->lock_pid, diff --git a/source3/smbd/close.c b/source3/smbd/close.c index d4c531ab19..ce918ab6a3 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -106,8 +106,7 @@ static void check_magic(struct files_struct *fsp) static NTSTATUS close_filestruct(files_struct *fsp) { NTSTATUS status = NT_STATUS_OK; - connection_struct *conn = fsp->conn; - + if (fsp->fh->fd != -1) { if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) { status = map_nt_error_from_unix(errno); @@ -115,9 +114,8 @@ static NTSTATUS close_filestruct(files_struct *fsp) delete_write_cache(fsp); } - conn->num_files_open--; return status; -} +} /**************************************************************************** If any deferred opens are waiting on this close, notify them. @@ -583,7 +581,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, DEBUG(2,("%s closed file %s (numopen=%d) %s\n", conn->server_info->unix_name,fsp->fsp_name, - conn->num_files_open, + conn->num_files_open - 1, nt_errstr(status) )); file_free(req, fsp); diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 784b36d9bd..954cd5a4d2 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -30,6 +30,17 @@ static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf) return 0; } +static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf) +{ +#ifdef S_ISLNK +#if LINKS_READ_ONLY + if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) + return aRONLY; +#endif +#endif + return 0; +} + /**************************************************************************** Change a dos mode to a unix mode. Base permission for files: @@ -159,13 +170,7 @@ static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_ result = aDIR | (result & aRONLY); result |= set_sparse_flag(sbuf); - -#ifdef S_ISLNK -#if LINKS_READ_ONLY - if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) - result |= aRONLY; -#endif -#endif + result |= set_link_read_only_flag(sbuf); DEBUG(8,("dos_mode_from_sbuf returning ")); @@ -343,6 +348,113 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT return(result); } +#ifdef HAVE_STAT_DOS_FLAGS +/**************************************************************************** + Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*) +****************************************************************************/ + +static int dos_attributes_to_stat_dos_flags(uint32_t dosmode) +{ + uint32_t dos_stat_flags = 0; + + if (dosmode & aARCH) + dos_stat_flags |= UF_DOS_ARCHIVE; + if (dosmode & aHIDDEN) + dos_stat_flags |= UF_DOS_HIDDEN; + if (dosmode & aRONLY) + dos_stat_flags |= UF_DOS_RO; + if (dosmode & aSYSTEM) + dos_stat_flags |= UF_DOS_SYSTEM; + if (dosmode & FILE_ATTRIBUTE_NONINDEXED) + dos_stat_flags |= UF_DOS_NOINDEX; + + return dos_stat_flags; +} + +/**************************************************************************** + Gets DOS attributes, accessed via st_flags in the stat struct. +****************************************************************************/ + +static bool get_stat_dos_flags(connection_struct *conn, + const char *fname, + const SMB_STRUCT_STAT *sbuf, + uint32_t *dosmode) +{ + SMB_ASSERT(sbuf && VALID_STAT(*sbuf)); + SMB_ASSERT(dosmode); + + if (!lp_store_dos_attributes(SNUM(conn))) { + return false; + } + + DEBUG(5, ("Getting stat dos attributes for %s.\n", fname)); + + if (sbuf->st_flags & UF_DOS_ARCHIVE) + *dosmode |= aARCH; + if (sbuf->st_flags & UF_DOS_HIDDEN) + *dosmode |= aHIDDEN; + if (sbuf->st_flags & UF_DOS_RO) + *dosmode |= aRONLY; + if (sbuf->st_flags & UF_DOS_SYSTEM) + *dosmode |= aSYSTEM; + if (sbuf->st_flags & UF_DOS_NOINDEX) + *dosmode |= FILE_ATTRIBUTE_NONINDEXED; + if (S_ISDIR(sbuf->st_mode)) + *dosmode |= aDIR; + + *dosmode |= set_sparse_flag(sbuf); + *dosmode |= set_link_read_only_flag(sbuf); + + return true; +} + +/**************************************************************************** + Sets DOS attributes, stored in st_flags of the inode. +****************************************************************************/ + +static bool set_stat_dos_flags(connection_struct *conn, + const char *fname, + SMB_STRUCT_STAT *sbuf, + uint32_t dosmode, + bool *attributes_changed) +{ + uint32_t new_flags = 0; + int error = 0; + + SMB_ASSERT(sbuf && VALID_STAT(*sbuf)); + SMB_ASSERT(attributes_changed); + + *attributes_changed = false; + + if (!lp_store_dos_attributes(SNUM(conn))) { + return false; + } + + DEBUG(5, ("Setting stat dos attributes for %s.\n", fname)); + + new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) | + dos_attributes_to_stat_dos_flags(dosmode); + + /* Return early if no flags changed. */ + if (new_flags == sbuf->st_flags) + return true; + + DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags, + sbuf->st_flags)); + + /* Set new flags with chflags. */ + error = SMB_VFS_CHFLAGS(conn, fname, new_flags); + if (error) { + DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on " + "file %s! errno=%d\n", new_flags, fname, errno)); + return false; + } + + *attributes_changed = true; + return true; +} +#endif /* HAVE_STAT_DOS_FLAGS */ + /**************************************************************************** Change a unix mode to a dos mode. ****************************************************************************/ @@ -350,7 +462,7 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) { uint32 result = 0; - bool offline; + bool offline, used_stat_dos_flags = false; DEBUG(8,("dos_mode: %s\n", path)); @@ -373,11 +485,16 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) } } - /* Get the DOS attributes from an EA by preference. */ - if (get_ea_dos_attribute(conn, path, sbuf, &result)) { - result |= set_sparse_flag(sbuf); - } else { - result |= dos_mode_from_sbuf(conn, path, sbuf); +#ifdef HAVE_STAT_DOS_FLAGS + used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result); +#endif + if (!used_stat_dos_flags) { + /* Get the DOS attributes from an EA by preference. */ + if (get_ea_dos_attribute(conn, path, sbuf, &result)) { + result |= set_sparse_flag(sbuf); + } else { + result |= dos_mode_from_sbuf(conn, path, sbuf); + } } @@ -468,6 +585,23 @@ int file_set_dosmode(connection_struct *conn, const char *fname, return(0); } +#ifdef HAVE_STAT_DOS_FLAGS + { + bool attributes_changed; + + if (set_stat_dos_flags(conn, fname, st, dosmode, + &attributes_changed)) + { + if (!newfile && attributes_changed) { + notify_fname(conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); + } + st->st_mode = unixmode; + return 0; + } + } +#endif + /* Store the DOS attributes in an EA by preference. */ if (set_ea_dos_attribute(conn, fname, st, dosmode)) { if (!newfile) { diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c index 58b09604c4..7feedcc9f9 100644 --- a/source3/smbd/fake_file.c +++ b/source3/smbd/fake_file.c @@ -141,7 +141,6 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, return NT_STATUS_NO_MEMORY; } - conn->num_files_open++; *result = fsp; return NT_STATUS_OK; } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 562f1e8d94..392264bfc0 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -194,25 +194,39 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, return result; } + if (!(name = talloc_strdup(ctx, orig_path))) { + DEBUG(0, ("talloc_strdup failed\n")); + return NT_STATUS_NO_MEMORY; + } + + /* + * Large directory fix normalization. If we're case sensitive, and + * the case preserving parameters are set to "no", normalize the case of + * the incoming filename from the client WHETHER IT EXISTS OR NOT ! + * This is in conflict with the current (3.0.20) man page, but is + * what people expect from the "large directory howto". I'll update + * the man page. Thanks to jht@samba.org for finding this. JRA. + */ + + if (conn->case_sensitive && !conn->case_preserve && + !conn->short_case_preserve) { + strnorm(name, lp_defaultcase(SNUM(conn))); + } + /* * Ensure saved_last_component is valid even if file exists. */ if(pp_saved_last_component) { - end = strrchr_m(orig_path, '/'); + end = strrchr_m(name, '/'); if (end) { *pp_saved_last_component = talloc_strdup(ctx, end + 1); } else { *pp_saved_last_component = talloc_strdup(ctx, - orig_path); + name); } } - if (!(name = talloc_strdup(ctx, orig_path))) { - DEBUG(0, ("talloc_strdup failed\n")); - return NT_STATUS_NO_MEMORY; - } - if (!lp_posix_pathnames()) { stream = strchr_m(name, ':'); @@ -227,20 +241,6 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } } - /* - * Large directory fix normalization. If we're case sensitive, and - * the case preserving parameters are set to "no", normalize the case of - * the incoming filename from the client WHETHER IT EXISTS OR NOT ! - * This is in conflict with the current (3.0.20) man page, but is - * what people expect from the "large directory howto". I'll update - * the man page. Thanks to jht@samba.org for finding this. JRA. - */ - - if (conn->case_sensitive && !conn->case_preserve && - !conn->short_case_preserve) { - strnorm(name, lp_defaultcase(SNUM(conn))); - } - start = name; /* If we're providing case insentive semantics or diff --git a/source3/smbd/files.c b/source3/smbd/files.c index d3bfce7499..1a3a997e59 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -129,6 +129,8 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, ZERO_STRUCT(fsp_fi_cache); + conn->num_files_open++; + *result = fsp; return NT_STATUS_OK; } @@ -420,9 +422,7 @@ void file_free(struct smb_request *req, files_struct *fsp) DEBUG(5,("freed files structure %d (%d used)\n", fsp->fnum, files_used)); - /* this is paranoia, just in case someone tries to reuse the - information */ - ZERO_STRUCTP(fsp); + fsp->conn->num_files_open--; if ((req != NULL) && (fsp == req->chain_fsp)) { req->chain_fsp = NULL; @@ -438,6 +438,10 @@ void file_free(struct smb_request *req, files_struct *fsp) vfs_remove_fsp_extension(fsp->vfs_extension->owner, fsp); } + /* this is paranoia, just in case someone tries to reuse the + information */ + ZERO_STRUCTP(fsp); + SAFE_FREE(fsp); } @@ -484,46 +488,34 @@ files_struct *file_fsp(struct smb_request *req, uint16 fid) Duplicate the file handle part for a DOS or FCB open. ****************************************************************************/ -NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *fsp, +void dup_file_fsp(struct smb_request *req, files_struct *from, uint32 access_mask, uint32 share_access, - uint32 create_options, files_struct **result) + uint32 create_options, files_struct *to) { - NTSTATUS status; - files_struct *dup_fsp; - - status = file_new(NULL, fsp->conn, &dup_fsp); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - SAFE_FREE(dup_fsp->fh); - - dup_fsp->fh = fsp->fh; - dup_fsp->fh->ref_count++; - - dup_fsp->file_id = fsp->file_id; - dup_fsp->initial_allocation_size = fsp->initial_allocation_size; - dup_fsp->mode = fsp->mode; - dup_fsp->file_pid = fsp->file_pid; - dup_fsp->vuid = fsp->vuid; - dup_fsp->open_time = fsp->open_time; - dup_fsp->access_mask = access_mask; - dup_fsp->share_access = share_access; - dup_fsp->oplock_type = fsp->oplock_type; - dup_fsp->can_lock = fsp->can_lock; - dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; - if (!CAN_WRITE(fsp->conn)) { - dup_fsp->can_write = False; + SAFE_FREE(to->fh); + + to->fh = from->fh; + to->fh->ref_count++; + + to->file_id = from->file_id; + to->initial_allocation_size = from->initial_allocation_size; + to->mode = from->mode; + to->file_pid = from->file_pid; + to->vuid = from->vuid; + to->open_time = from->open_time; + to->access_mask = access_mask; + to->share_access = share_access; + to->oplock_type = from->oplock_type; + to->can_lock = from->can_lock; + to->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; + if (!CAN_WRITE(from->conn)) { + to->can_write = False; } else { - dup_fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False; + to->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False; } - dup_fsp->print_file = fsp->print_file; - dup_fsp->modified = fsp->modified; - dup_fsp->is_directory = fsp->is_directory; - dup_fsp->aio_write_behind = fsp->aio_write_behind; - string_set(&dup_fsp->fsp_name,fsp->fsp_name); - - *result = dup_fsp; - return NT_STATUS_OK; + to->print_file = from->print_file; + to->modified = from->modified; + to->is_directory = from->is_directory; + to->aio_write_behind = from->aio_write_behind; + string_set(&to->fsp_name,from->fsp_name); } diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index b9460e5211..649ead4682 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -91,7 +91,6 @@ void send_trans_reply(connection_struct *conn, int tot_data_sent = 0; int tot_param_sent = 0; int align; - char *outbuf; int ldata = rdata ? rdata_len : 0; int lparam = rparam ? rparam_len : 0; @@ -104,38 +103,43 @@ void send_trans_reply(connection_struct *conn, align = ((this_lparam)%4); - if (!create_outbuf(talloc_tos(), (char *)req->inbuf, &outbuf, - 10, 1+align+this_ldata+this_lparam)) { - smb_panic("could not allocate outbuf"); - } + reply_outbuf(req, 10, 1+align+this_ldata+this_lparam); + + /* + * We might have SMBtranss in req which was transferred to the outbuf, + * fix that. + */ + SCVAL(req->outbuf, smb_com, SMBtrans); - copy_trans_params_and_data(outbuf, align, + copy_trans_params_and_data((char *)req->outbuf, align, rparam, tot_param_sent, this_lparam, rdata, tot_data_sent, this_ldata); - SSVAL(outbuf,smb_vwv0,lparam); - SSVAL(outbuf,smb_vwv1,ldata); - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); - SSVAL(outbuf,smb_vwv5,0); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align, - outbuf)); - SSVAL(outbuf,smb_vwv8,0); - SSVAL(outbuf,smb_vwv9,0); + SSVAL(req->outbuf,smb_vwv0,lparam); + SSVAL(req->outbuf,smb_vwv1,ldata); + SSVAL(req->outbuf,smb_vwv3,this_lparam); + SSVAL(req->outbuf,smb_vwv4, + smb_offset(smb_buf(req->outbuf)+1, req->outbuf)); + SSVAL(req->outbuf,smb_vwv5,0); + SSVAL(req->outbuf,smb_vwv6,this_ldata); + SSVAL(req->outbuf,smb_vwv7, + smb_offset(smb_buf(req->outbuf)+1+this_lparam+align, + req->outbuf)); + SSVAL(req->outbuf,smb_vwv8,0); + SSVAL(req->outbuf,smb_vwv9,0); if (buffer_too_large) { - error_packet_set((char *)outbuf, ERRDOS, ERRmoredata, + error_packet_set((char *)req->outbuf, ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__); } - show_msg(outbuf); - if (!srv_send_smb(smbd_server_fd(), (char *)outbuf, + show_msg((char *)req->outbuf); + if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, IS_CONN_ENCRYPTED(conn))) { exit_server_cleanly("send_trans_reply: srv_send_smb failed."); } - TALLOC_FREE(outbuf); + TALLOC_FREE(req->outbuf); tot_data_sent = this_ldata; tot_param_sent = this_lparam; @@ -155,39 +159,45 @@ void send_trans_reply(connection_struct *conn, align = (this_lparam%4); - if (!create_outbuf(talloc_tos(), (char *)req->inbuf, &outbuf, - 10, 1+align+this_ldata+this_lparam)) { - smb_panic("could not allocate outbuf"); - } + reply_outbuf(req, 10, 1+align+this_ldata+this_lparam); + + /* + * We might have SMBtranss in req which was transferred to the + * outbuf, fix that. + */ + SCVAL(req->outbuf, smb_com, SMBtrans); - copy_trans_params_and_data(outbuf, align, + copy_trans_params_and_data((char *)req->outbuf, align, rparam, tot_param_sent, this_lparam, rdata, tot_data_sent, this_ldata); - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); - SSVAL(outbuf,smb_vwv5,tot_param_sent); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7, - smb_offset(smb_buf(outbuf)+1+this_lparam+align, outbuf)); - SSVAL(outbuf,smb_vwv8,tot_data_sent); - SSVAL(outbuf,smb_vwv9,0); + SSVAL(req->outbuf,smb_vwv3,this_lparam); + SSVAL(req->outbuf,smb_vwv4, + smb_offset(smb_buf(req->outbuf)+1,req->outbuf)); + SSVAL(req->outbuf,smb_vwv5,tot_param_sent); + SSVAL(req->outbuf,smb_vwv6,this_ldata); + SSVAL(req->outbuf,smb_vwv7, + smb_offset(smb_buf(req->outbuf)+1+this_lparam+align, + req->outbuf)); + SSVAL(req->outbuf,smb_vwv8,tot_data_sent); + SSVAL(req->outbuf,smb_vwv9,0); if (buffer_too_large) { - error_packet_set(outbuf, ERRDOS, ERRmoredata, + error_packet_set((char *)req->outbuf, + ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__); } - show_msg(outbuf); - if (!srv_send_smb(smbd_server_fd(), outbuf, + show_msg((char *)req->outbuf); + if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, IS_CONN_ENCRYPTED(conn))) exit_server_cleanly("send_trans_reply: srv_send_smb " "failed."); tot_data_sent += this_ldata; tot_param_sent += this_lparam; - TALLOC_FREE(outbuf); + TALLOC_FREE(req->outbuf); } } @@ -493,8 +503,6 @@ void reply_trans(struct smb_request *req) unsigned int pscnt; struct trans_state *state; NTSTATUS result; - unsigned int size; - unsigned int av_size; START_PROFILE(SMBtrans); @@ -504,8 +512,6 @@ void reply_trans(struct smb_request *req) return; } - size = smb_len(req->inbuf) + 4; - av_size = smb_len(req->inbuf); dsoff = SVAL(req->vwv+12, 0); dscnt = SVAL(req->vwv+11, 0); psoff = SVAL(req->vwv+10, 0); @@ -551,6 +557,12 @@ void reply_trans(struct smb_request *req) goto bad_param; if (state->total_data) { + + if (trans_oob(state->total_data, 0, dscnt) + || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. Out of paranoia, 100 bytes too many. */ state->data = (char *)SMB_MALLOC(state->total_data+100); @@ -565,21 +577,16 @@ void reply_trans(struct smb_request *req) /* null-terminate the slack space */ memset(&state->data[state->total_data], 0, 100); - if (dscnt > state->total_data || - dsoff+dscnt < dsoff) { - goto bad_param; - } - - if (dsoff > av_size || - dscnt > av_size || - dsoff+dscnt > av_size) { - goto bad_param; - } - memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt); } if (state->total_param) { + + if (trans_oob(state->total_param, 0, pscnt) + || trans_oob(smb_len(req->inbuf), psoff, pscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. Out of paranoia, 100 bytes too many */ state->param = (char *)SMB_MALLOC(state->total_param+100); @@ -595,17 +602,6 @@ void reply_trans(struct smb_request *req) /* null-terminate the slack space */ memset(&state->param[state->total_param], 0, 100); - if (pscnt > state->total_param || - psoff+pscnt < psoff) { - goto bad_param; - } - - if (psoff > av_size || - pscnt > av_size || - psoff+pscnt > av_size) { - goto bad_param; - } - memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt); } @@ -614,6 +610,19 @@ void reply_trans(struct smb_request *req) if (state->setup_count) { unsigned int i; + + /* + * No overflow possible here, state->setup_count is an + * unsigned int, being filled by a single byte from + * CVAL(req->vwv+13, 0) above. The cast in the comparison + * below is not necessary, it's here to clarify things. The + * validity of req->vwv and req->wct has been checked in + * init_smb_request already. + */ + if (state->setup_count + 14 > (unsigned int)req->wct) { + goto bad_param; + } + if((state->setup = TALLOC_ARRAY( state, uint16, state->setup_count)) == NULL) { DEBUG(0,("reply_trans: setup malloc fail for %u " @@ -626,17 +635,10 @@ void reply_trans(struct smb_request *req) END_PROFILE(SMBtrans); return; } - if (req->inbuf+smb_vwv14+(state->setup_count*SIZEOFWORD) > - req->inbuf + size) - goto bad_param; - if ((smb_vwv14+(state->setup_count*SIZEOFWORD) < smb_vwv14) || - (smb_vwv14+(state->setup_count*SIZEOFWORD) < - (state->setup_count*SIZEOFWORD))) - goto bad_param; - for (i=0;i<state->setup_count;i++) - state->setup[i] = SVAL(req->inbuf, - smb_vwv14+i*SIZEOFWORD); + for (i=0;i<state->setup_count;i++) { + state->setup[i] = SVAL(req->vwv + 14 + i, 0); + } } state->received_param = pscnt; @@ -682,7 +684,6 @@ void reply_transs(struct smb_request *req) connection_struct *conn = req->conn; unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp; struct trans_state *state; - unsigned int av_size; START_PROFILE(SMBtranss); @@ -715,8 +716,6 @@ void reply_transs(struct smb_request *req) if (SVAL(req->vwv+1, 0) < state->total_data) state->total_data = SVAL(req->vwv+1, 0); - av_size = smb_len(req->inbuf); - pcnt = SVAL(req->vwv+2, 0); poff = SVAL(req->vwv+3, 0); pdisp = SVAL(req->vwv+4, 0); @@ -733,41 +732,19 @@ void reply_transs(struct smb_request *req) goto bad_param; if (pcnt) { - if (pdisp > state->total_param || - pcnt > state->total_param || - pdisp+pcnt > state->total_param || - pdisp+pcnt < pdisp) { - goto bad_param; - } - - if (poff > av_size || - pcnt > av_size || - poff+pcnt > av_size || - poff+pcnt < poff) { + if (trans_oob(state->total_param, pdisp, pcnt) + || trans_oob(smb_len(req->inbuf), poff, pcnt)) { goto bad_param; } - - memcpy(state->param+pdisp,smb_base(req->inbuf)+poff, - pcnt); + memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt); } if (dcnt) { - if (ddisp > state->total_data || - dcnt > state->total_data || - ddisp+dcnt > state->total_data || - ddisp+dcnt < ddisp) { + if (trans_oob(state->total_data, ddisp, dcnt) + || trans_oob(smb_len(req->inbuf), doff, dcnt)) { goto bad_param; } - - if (ddisp > av_size || - dcnt > av_size || - ddisp+dcnt > av_size || - ddisp+dcnt < ddisp) { - goto bad_param; - } - - memcpy(state->data+ddisp, smb_base(req->inbuf)+doff, - dcnt); + memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt); } if ((state->received_param < state->total_param) || @@ -776,12 +753,6 @@ void reply_transs(struct smb_request *req) return; } - /* - * construct_reply_common will copy smb_com from inbuf to - * outbuf. SMBtranss is wrong here. - */ - SCVAL(req->inbuf,smb_com,SMBtrans); - handle_trans(conn, req, state); DLIST_REMOVE(conn->pending_trans, state); diff --git a/source3/smbd/map_username.c b/source3/smbd/map_username.c index a8899dd538..f549f0c9f3 100644 --- a/source3/smbd/map_username.c +++ b/source3/smbd/map_username.c @@ -178,7 +178,7 @@ bool map_username(fstring user) /* skip lines like 'user = ' */ - dosuserlist = str_list_make(talloc_tos(), dosname, NULL); + dosuserlist = str_list_make_v3(talloc_tos(), dosname, NULL); if (!dosuserlist) { DEBUG(0,("Bad username map entry. Unable to build user list. Ignoring.\n")); continue; diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 32240ff0d5..d46be64262 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -219,6 +219,7 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, connection_struct **pconn, int snum, const char *path, + struct auth_serversupplied_info *server_info, char **poldcwd) { connection_struct *conn; @@ -254,6 +255,15 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, conn->params->service = snum; + if (server_info != NULL) { + conn->server_info = copy_serverinfo(conn, server_info); + if (conn->server_info == NULL) { + DEBUG(0, ("copy_serverinfo failed\n")); + TALLOC_FREE(conn); + return NT_STATUS_NO_MEMORY; + } + } + set_conn_connectpath(conn, connpath); if (!smbd_vfs_init(conn)) { @@ -881,7 +891,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, } status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum), - &oldpath); + NULL, &oldpath); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(pdp); return status; @@ -923,7 +933,6 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, static int setup_ver2_dfs_referral(const char *pathname, char **ppdata, struct junction_map *junction, - int consumedcnt, bool self_referral) { char* pdata = *ppdata; @@ -988,7 +997,8 @@ static int setup_ver2_dfs_referral(const char *pathname, memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen); /* create the header */ - SSVAL(pdata,0,consumedcnt * 2); /* path consumed */ + SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus + 2 byte null */ /* number of referral in this pkt */ SSVAL(pdata,2,junction->referral_count); if(self_referral) { @@ -1037,7 +1047,6 @@ static int setup_ver2_dfs_referral(const char *pathname, static int setup_ver3_dfs_referral(const char *pathname, char **ppdata, struct junction_map *junction, - int consumedcnt, bool self_referral) { char *pdata = *ppdata; @@ -1084,7 +1093,8 @@ static int setup_ver3_dfs_referral(const char *pathname, *ppdata = pdata; /* create the header */ - SSVAL(pdata,0,consumedcnt * 2); /* path consumed */ + SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus + 2 byte null */ SSVAL(pdata,2,junction->referral_count); /* number of referral */ if(self_referral) { SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER); @@ -1224,11 +1234,11 @@ int setup_dfs_referral(connection_struct *orig_conn, case 2: reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, junction, - consumedcnt, self_referral); + self_referral); break; case 3: reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, - junction, consumedcnt, self_referral); + junction, self_referral); break; default: DEBUG(0,("setup_dfs_referral: Invalid dfs referral " @@ -1321,7 +1331,7 @@ static bool junction_to_local_path(const struct junction_map *jucn, return False; } status = create_conn_struct(talloc_tos(), conn_out, snum, - lp_pathname(snum), oldpath); + lp_pathname(snum), NULL, oldpath); if (!NT_STATUS_IS_OK(status)) { return False; } @@ -1455,7 +1465,7 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) */ status = create_conn_struct(talloc_tos(), &conn, snum, connect_path, - &cwd); + NULL, &cwd); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("create_conn_struct failed: %s\n", nt_errstr(status))); @@ -1523,7 +1533,8 @@ static int form_junctions(TALLOC_CTX *ctx, * Fake up a connection struct for the VFS layer. */ - status = create_conn_struct(ctx, &conn, snum, connect_path, &cwd); + status = create_conn_struct(ctx, &conn, snum, connect_path, NULL, + &cwd); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("create_conn_struct failed: %s\n", nt_errstr(status))); diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index b2d0f20f89..2d0811bc1c 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -24,7 +24,7 @@ struct notify_change_request { struct notify_change_request *prev, *next; struct files_struct *fsp; /* backpointer for cancel by mid */ - uint8 request_buf[smb_size]; + struct smb_request *req; uint32 filter; uint32 max_param; struct notify_mid_map *mid_map; @@ -133,40 +133,33 @@ static bool notify_marshall_changes(int num_changes, *****************************************************************************/ static void change_notify_reply_packet(connection_struct *conn, - const uint8 *request_buf, + struct smb_request *req, NTSTATUS error_code) { - char outbuf[smb_size+38]; + reply_outbuf(req, 18, 0); - memset(outbuf, '\0', sizeof(outbuf)); - construct_reply_common((char *)request_buf, outbuf); - - ERROR_NT(error_code); - - /* - * Seems NT needs a transact command with an error code - * in it. This is a longer packet than a simple error. - */ - srv_set_message(outbuf,18,0,False); + if (!NT_STATUS_IS_OK(error_code)) { + error_packet_set((char *)req->outbuf, 0, 0, error_code, + __LINE__,__FILE__); + } - show_msg(outbuf); - if (!srv_send_smb(smbd_server_fd(), - outbuf, - IS_CONN_ENCRYPTED(conn))) + show_msg((char *)req->outbuf); + if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, + req->encrypted)) { exit_server_cleanly("change_notify_reply_packet: srv_send_smb " "failed."); + } + TALLOC_FREE(req->outbuf); } void change_notify_reply(connection_struct *conn, - const uint8 *request_buf, uint32 max_param, + struct smb_request *req, uint32 max_param, struct notify_change_buf *notify_buf) { prs_struct ps; - struct smb_request *req = NULL; - uint8 tmp_request[smb_size]; if (notify_buf->num_changes == -1) { - change_notify_reply_packet(conn, request_buf, NT_STATUS_OK); + change_notify_reply_packet(conn, req, NT_STATUS_OK); notify_buf->num_changes = 0; return; } @@ -179,32 +172,14 @@ void change_notify_reply(connection_struct *conn, * We exceed what the client is willing to accept. Send * nothing. */ - change_notify_reply_packet(conn, request_buf, NT_STATUS_OK); - goto done; - } - - if (!(req = talloc(talloc_tos(), struct smb_request))) { - change_notify_reply_packet(conn, request_buf, NT_STATUS_NO_MEMORY); + change_notify_reply_packet(conn, req, NT_STATUS_OK); goto done; } - memcpy(tmp_request, request_buf, smb_size); - - /* - * We're only interested in the header fields here - */ - - smb_setlen((char *)tmp_request, smb_size); - SCVAL(tmp_request, smb_wct, 0); - - init_smb_request(req, tmp_request,0, conn->encrypted_tid); - req->inbuf = tmp_request; - send_nt_replies(conn, req, NT_STATUS_OK, prs_data_p(&ps), prs_offset(&ps), NULL, 0); done: - TALLOC_FREE(req); prs_mem_free(&ps); TALLOC_FREE(notify_buf->changes); @@ -252,7 +227,7 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, return status; } -NTSTATUS change_notify_add_request(const struct smb_request *req, +NTSTATUS change_notify_add_request(struct smb_request *req, uint32 max_param, uint32 filter, bool recursive, struct files_struct *fsp) @@ -263,16 +238,16 @@ NTSTATUS change_notify_add_request(const struct smb_request *req, DEBUG(10, ("change_notify_add_request: Adding request for %s: " "max_param = %d\n", fsp->fsp_name, (int)max_param)); - if (!(request = SMB_MALLOC_P(struct notify_change_request)) - || !(map = SMB_MALLOC_P(struct notify_mid_map))) { - SAFE_FREE(request); + if (!(request = talloc(NULL, struct notify_change_request)) + || !(map = talloc(request, struct notify_mid_map))) { + TALLOC_FREE(request); return NT_STATUS_NO_MEMORY; } request->mid_map = map; map->req = request; - memcpy(request->request_buf, req->inbuf, sizeof(request->request_buf)); + request->req = talloc_move(request, &req); request->max_param = max_param; request->filter = filter; request->fsp = fsp; @@ -281,11 +256,11 @@ NTSTATUS change_notify_add_request(const struct smb_request *req, DLIST_ADD_END(fsp->notify->requests, request, struct notify_change_request *); - map->mid = SVAL(req->inbuf, smb_mid); + map->mid = request->req->mid; DLIST_ADD(notify_changes_by_mid, map); /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(req->inbuf,smb_mid)); + srv_defer_sign_response(request->req->mid); return NT_STATUS_OK; } @@ -315,9 +290,7 @@ static void change_notify_remove_request(struct notify_change_request *remove_re DLIST_REMOVE(fsp->notify->requests, req); DLIST_REMOVE(notify_changes_by_mid, req->mid_map); - SAFE_FREE(req->mid_map); - TALLOC_FREE(req->backend_data); - SAFE_FREE(req); + TALLOC_FREE(req); } /**************************************************************************** @@ -338,8 +311,8 @@ void remove_pending_change_notify_requests_by_mid(uint16 mid) return; } - change_notify_reply_packet(map->req->fsp->conn, - map->req->request_buf, NT_STATUS_CANCELLED); + change_notify_reply_packet(map->req->fsp->conn, map->req->req, + NT_STATUS_CANCELLED); change_notify_remove_request(map->req); } @@ -355,8 +328,8 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp, } while (fsp->notify->requests != NULL) { - change_notify_reply_packet(fsp->conn, - fsp->notify->requests->request_buf, status); + change_notify_reply_packet( + fsp->conn, fsp->notify->requests->req, status); change_notify_remove_request(fsp->notify->requests); } } @@ -366,6 +339,9 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter, { char *fullpath; + if (path[0] == '.' && path[1] == '/') { + path += 2; + } if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) { DEBUG(0, ("asprintf failed\n")); return; @@ -450,7 +426,7 @@ static void notify_fsp(files_struct *fsp, uint32 action, const char *name) */ change_notify_reply(fsp->conn, - fsp->notify->requests->request_buf, + fsp->notify->requests->req, fsp->notify->requests->max_param, fsp->notify); diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index f711b588c5..777073e6ba 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -120,6 +120,11 @@ void send_nt_replies(connection_struct *conn, + data_alignment_offset); /* + * We might have had SMBnttranss in req->inbuf, fix that. + */ + SCVAL(req->outbuf, smb_com, SMBnttrans); + + /* * Set total params and data to be sent. */ @@ -279,7 +284,7 @@ static void nt_open_pipe(char *fname, connection_struct *conn, /* Strip \\ off the name. */ fname++; - status = np_open(req, conn, fname, &fsp); + status = np_open(req, fname, &fsp); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, @@ -716,23 +721,22 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len, return status; } - if (psd->owner_sid==0) { + if (psd->owner_sid == NULL) { security_info_sent &= ~OWNER_SECURITY_INFORMATION; } - if (psd->group_sid==0) { + if (psd->group_sid == NULL) { security_info_sent &= ~GROUP_SECURITY_INFORMATION; } - if (psd->sacl==0) { - security_info_sent &= ~SACL_SECURITY_INFORMATION; - } - if (psd->dacl==0) { - security_info_sent &= ~DACL_SECURITY_INFORMATION; - } /* Convert all the generic bits. */ security_acl_map_generic(psd->dacl, &file_generic_mapping); security_acl_map_generic(psd->sacl, &file_generic_mapping); + if (DEBUGLEVEL >= 10) { + DEBUG(10,("set_sd for file %s\n", fsp->fsp_name )); + NDR_PRINT_DEBUG(security_descriptor, psd); + } + status = SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, psd); TALLOC_FREE(psd); @@ -1440,7 +1444,8 @@ static void call_nt_transact_notify_change(connection_struct *conn, * here. */ - change_notify_reply(fsp->conn, req->inbuf, max_param_count, fsp->notify); + change_notify_reply(fsp->conn, req, max_param_count, + fsp->notify); /* * change_notify_reply() above has independently sent its @@ -1582,16 +1587,29 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, status = SMB_VFS_FGET_NT_ACL( fsp, security_info_wanted, &psd); } - if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; } + /* If the SACL/DACL is NULL, but was requested, we mark that it is + * present in the reply to match Windows behavior */ + if (psd->sacl == NULL && + security_info_wanted & SACL_SECURITY_INFORMATION) + psd->type |= SEC_DESC_SACL_PRESENT; + if (psd->dacl == NULL && + security_info_wanted & DACL_SECURITY_INFORMATION) + psd->type |= SEC_DESC_DACL_PRESENT; + sd_size = ndr_size_security_descriptor(psd, 0); DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size)); + if (DEBUGLEVEL >= 10) { + DEBUG(10,("call_nt_transact_query_security_desc for file %s\n", fsp->fsp_name)); + NDR_PRINT_DEBUG(security_descriptor, psd); + } + SIVAL(params,0,(uint32)sd_size); if (max_data_count < sd_size) { @@ -2519,8 +2537,6 @@ void reply_nttrans(struct smb_request *req) uint16 function_code; NTSTATUS result; struct trans_state *state; - uint32_t size; - uint32_t av_size; START_PROFILE(SMBnttrans); @@ -2530,8 +2546,6 @@ void reply_nttrans(struct smb_request *req) return; } - size = smb_len(req->inbuf) + 4; - av_size = smb_len(req->inbuf); pscnt = IVAL(req->vwv+9, 1); psoff = IVAL(req->vwv+11, 1); dscnt = IVAL(req->vwv+13, 1); @@ -2608,6 +2622,12 @@ void reply_nttrans(struct smb_request *req) goto bad_param; if (state->total_data) { + + if (trans_oob(state->total_data, 0, dscnt) + || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. */ if ((state->data = (char *)SMB_MALLOC(state->total_data)) == NULL) { @@ -2619,21 +2639,16 @@ void reply_nttrans(struct smb_request *req) return; } - if (dscnt > state->total_data || - dsoff+dscnt < dsoff) { - goto bad_param; - } - - if (dsoff > av_size || - dscnt > av_size || - dsoff+dscnt > av_size) { - goto bad_param; - } - memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt); } if (state->total_param) { + + if (trans_oob(state->total_param, 0, pscnt) + || trans_oob(smb_len(req->inbuf), psoff, pscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. */ if ((state->param = (char *)SMB_MALLOC(state->total_param)) == NULL) { @@ -2646,17 +2661,6 @@ void reply_nttrans(struct smb_request *req) return; } - if (pscnt > state->total_param || - psoff+pscnt < psoff) { - goto bad_param; - } - - if (psoff > av_size || - pscnt > av_size || - psoff+pscnt > av_size) { - goto bad_param; - } - memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt); } @@ -2666,6 +2670,19 @@ void reply_nttrans(struct smb_request *req) if(state->setup_count > 0) { DEBUG(10,("reply_nttrans: state->setup_count = %d\n", state->setup_count)); + + /* + * No overflow possible here, state->setup_count is an + * unsigned int, being filled by a single byte from + * CVAL(req->vwv+13, 0) above. The cast in the comparison + * below is not necessary, it's here to clarify things. The + * validity of req->vwv and req->wct has been checked in + * init_smb_request already. + */ + if ((state->setup_count/2) + 19 > (unsigned int)req->wct) { + goto bad_param; + } + state->setup = (uint16 *)TALLOC(state, state->setup_count); if (state->setup == NULL) { DEBUG(0,("reply_nttrans : Out of memory\n")); @@ -2677,16 +2694,7 @@ void reply_nttrans(struct smb_request *req) return; } - if ((smb_nt_SetupStart + state->setup_count < smb_nt_SetupStart) || - (smb_nt_SetupStart + state->setup_count < state->setup_count)) { - goto bad_param; - } - if (smb_nt_SetupStart + state->setup_count > size) { - goto bad_param; - } - - memcpy( state->setup, &req->inbuf[smb_nt_SetupStart], - state->setup_count); + memcpy(state->setup, req->vwv+19, state->setup_count); dump_data(10, (uint8 *)state->setup, state->setup_count); } @@ -2729,8 +2737,6 @@ void reply_nttranss(struct smb_request *req) connection_struct *conn = req->conn; uint32_t pcnt,poff,dcnt,doff,pdisp,ddisp; struct trans_state *state; - uint32_t av_size; - uint32_t size; START_PROFILE(SMBnttranss); @@ -2764,9 +2770,6 @@ void reply_nttranss(struct smb_request *req) state->total_data = IVAL(req->vwv+3, 1); } - size = smb_len(req->inbuf) + 4; - av_size = smb_len(req->inbuf); - pcnt = IVAL(req->vwv+5, 1); poff = IVAL(req->vwv+7, 1); pdisp = IVAL(req->vwv+9, 1); @@ -2783,41 +2786,19 @@ void reply_nttranss(struct smb_request *req) goto bad_param; if (pcnt) { - if (pdisp > state->total_param || - pcnt > state->total_param || - pdisp+pcnt > state->total_param || - pdisp+pcnt < pdisp) { + if (trans_oob(state->total_param, pdisp, pcnt) + || trans_oob(smb_len(req->inbuf), poff, pcnt)) { goto bad_param; } - - if (poff > av_size || - pcnt > av_size || - poff+pcnt > av_size || - poff+pcnt < poff) { - goto bad_param; - } - - memcpy(state->param+pdisp, smb_base(req->inbuf)+poff, - pcnt); + memcpy(state->param+pdisp, smb_base(req->inbuf)+poff,pcnt); } if (dcnt) { - if (ddisp > state->total_data || - dcnt > state->total_data || - ddisp+dcnt > state->total_data || - ddisp+dcnt < ddisp) { + if (trans_oob(state->total_data, ddisp, dcnt) + || trans_oob(smb_len(req->inbuf), doff, dcnt)) { goto bad_param; } - - if (ddisp > av_size || - dcnt > av_size || - ddisp+dcnt > av_size || - ddisp+dcnt < ddisp) { - goto bad_param; - } - - memcpy(state->data+ddisp, smb_base(req->inbuf)+doff, - dcnt); + memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt); } if ((state->received_param < state->total_param) || @@ -2826,12 +2807,6 @@ void reply_nttranss(struct smb_request *req) return; } - /* - * construct_reply_common will copy smb_com from inbuf to - * outbuf. SMBnttranss is wrong here. - */ - SCVAL(req->inbuf,smb_com,SMBnttrans); - handle_nttrans(conn, state, req); DLIST_REMOVE(conn->pending_trans, state); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 480352beda..f98415ee33 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -332,6 +332,7 @@ static NTSTATUS open_file(files_struct *fsp, if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || (!file_existed && (local_flags & O_CREAT)) || ((local_flags & O_TRUNC) == O_TRUNC) ) { + const char *wild; /* * We can't actually truncate here as the file may be locked. @@ -353,8 +354,17 @@ static NTSTATUS open_file(files_struct *fsp, #endif /* Don't create files with Microsoft wildcard characters. */ + if (fsp->base_fsp) { + /* + * wildcard characters are allowed in stream names + * only test the basefilename + */ + wild = fsp->base_fsp->fsp_name; + } else { + wild = path; + } if ((local_flags & O_CREAT) && !file_existed && - ms_has_wild(path)) { + ms_has_wild(wild)) { return NT_STATUS_OBJECT_NAME_INVALID; } @@ -462,7 +472,7 @@ static NTSTATUS open_file(files_struct *fsp, conn->server_info->unix_name, fsp->fsp_name, BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), - conn->num_files_open + 1)); + conn->num_files_open)); errno = 0; return NT_STATUS_OK; @@ -951,9 +961,10 @@ static bool open_match_attributes(connection_struct *conn, Try and find a duplicated file handle. ****************************************************************************/ -static files_struct *fcb_or_dos_open(struct smb_request *req, +static NTSTATUS fcb_or_dos_open(struct smb_request *req, connection_struct *conn, - const char *fname, + files_struct *fsp_to_dup_into, + const char *fname, struct file_id id, uint16 file_pid, uint16 vuid, @@ -962,7 +973,6 @@ static files_struct *fcb_or_dos_open(struct smb_request *req, uint32 create_options) { files_struct *fsp; - files_struct *dup_fsp; DEBUG(5,("fcb_or_dos_open: attempting old open semantics for " "file %s.\n", fname )); @@ -991,23 +1001,21 @@ static files_struct *fcb_or_dos_open(struct smb_request *req, } if (!fsp) { - return NULL; + return NT_STATUS_NOT_FOUND; } /* quite an insane set of semantics ... */ if (is_executable(fname) && (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) { DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n")); - return NULL; + return NT_STATUS_INVALID_PARAMETER; } /* We need to duplicate this fsp. */ - if (!NT_STATUS_IS_OK(dup_file_fsp(req, fsp, access_mask, share_access, - create_options, &dup_fsp))) { - return NULL; - } + dup_file_fsp(req, fsp, access_mask, share_access, + create_options, fsp_to_dup_into); - return dup_fsp; + return NT_STATUS_OK; } /**************************************************************************** @@ -1249,10 +1257,10 @@ static NTSTATUS calculate_access_mask(connection_struct *conn, } /**************************************************************************** - Open a file with a share mode. + Open a file with a share mode. Passed in an already created files_struct *. ****************************************************************************/ -NTSTATUS open_file_ntcreate(connection_struct *conn, +static NTSTATUS open_file_ntcreate_internal(connection_struct *conn, struct smb_request *req, const char *fname, SMB_STRUCT_STAT *psbuf, @@ -1264,7 +1272,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, int oplock_request, /* internal Samba oplock codes. */ /* Information (FILE_EXISTS etc.) */ int *pinfo, - files_struct **result) + files_struct *fsp) { int flags=0; int flags2=0; @@ -1274,7 +1282,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, bool new_file_created = False; struct file_id id; NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED; - files_struct *fsp = NULL; mode_t new_unx_mode = (mode_t)0; mode_t unx_mode = (mode_t)0; int info; @@ -1291,7 +1298,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, ZERO_STRUCT(id); if (conn->printer) { - /* + /* * Printers are handled completely differently. * Most of the passed parameters are ignored. */ @@ -1302,7 +1309,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname)); - return print_fsp_open(req, conn, fname, req->vuid, result); + return print_fsp_open(req, conn, fname, req->vuid, fsp); } if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir, @@ -1366,7 +1373,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { return status; - } + } if (!posix_open) { new_dos_attributes &= SAMBA_ATTRIBUTES_MASK; @@ -1533,7 +1540,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, flags2 |= O_SYNC; } #endif /* O_SYNC */ - + if (posix_open && (access_mask & FILE_APPEND_DATA)) { flags2 |= O_APPEND; } @@ -1560,11 +1567,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } - status = file_new(req, conn, &fsp); - if(!NT_STATUS_IS_OK(status)) { - return status; - } - fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); fsp->share_access = share_access; fsp->fh->private_options = create_options; @@ -1589,7 +1591,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, fname, &old_write_time); if (lck == NULL) { - file_free(req, fsp); DEBUG(0, ("Could not get share mode lock\n")); return NT_STATUS_SHARING_VIOLATION; } @@ -1600,7 +1601,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, oplock_request)) { schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1620,7 +1620,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, oplock_request)) { schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } } @@ -1628,7 +1627,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) { /* DELETE_PENDING is not deferred for a second */ TALLOC_FREE(lck); - file_free(req, fsp); return status; } @@ -1643,33 +1641,31 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, if (create_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { - files_struct *fsp_dup; - if (req == NULL) { DEBUG(0, ("DOS open without an SMB " "request!\n")); TALLOC_FREE(lck); - file_free(req, fsp); return NT_STATUS_INTERNAL_ERROR; } /* Use the client requested access mask here, * not the one we open with. */ - fsp_dup = fcb_or_dos_open(req, conn, fname, id, - req->smbpid, - req->vuid, - access_mask, - share_access, - create_options); - - if (fsp_dup) { + status = fcb_or_dos_open(req, + conn, + fsp, + fname, + id, + req->smbpid, + req->vuid, + access_mask, + share_access, + create_options); + + if (NT_STATUS_IS_OK(status)) { TALLOC_FREE(lck); - file_free(req, fsp); if (pinfo) { *pinfo = FILE_WAS_OPENED; } - conn->num_files_open++; - *result = fsp_dup; return NT_STATUS_OK; } } @@ -1697,7 +1693,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, can_access = False; } - /* + /* * If we're returning a share violation, ensure we * cope with the braindead 1 second delay. */ @@ -1750,7 +1746,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } else { status = NT_STATUS_ACCESS_DENIED; } - file_free(req, fsp); return status; } @@ -1788,7 +1783,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, if (lck != NULL) { TALLOC_FREE(lck); } - file_free(req, fsp); return fsp_open; } @@ -1819,7 +1813,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, DEBUG(0, ("open_file_ntcreate: Could not get share " "mode lock for %s\n", fname)); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1830,7 +1823,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1849,7 +1841,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } } @@ -1858,7 +1849,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, struct deferred_open_record state; fd_close(fsp); - file_free(req, fsp); state.delayed_for_oplocks = False; state.id = id; @@ -1900,7 +1890,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1926,7 +1915,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, status = map_nt_error_from_unix(errno); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return status; } } @@ -1958,7 +1946,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, *pinfo = info; } - /* + /* * Setup the oplock info in both the shared memory and * file structs. */ @@ -1990,14 +1978,13 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, del_share_mode(lck, fsp); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return status; } /* Note that here we set the *inital* delete on close flag, not the regular one. The magic gets handled in close. */ fsp->initial_delete_on_close = True; } - + if (new_file_created) { /* Files should be initially set as archive */ if (lp_map_archive(SNUM(conn)) || @@ -2066,10 +2053,57 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } TALLOC_FREE(lck); - conn->num_files_open++; + return NT_STATUS_OK; +} + +/**************************************************************************** + Open a file with a share mode. +****************************************************************************/ + +NTSTATUS open_file_ntcreate(connection_struct *conn, + struct smb_request *req, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */ + uint32 share_access, /* share constants (FILE_SHARE_READ etc) */ + uint32 create_disposition, /* FILE_OPEN_IF etc. */ + uint32 create_options, /* options such as delete on close. */ + uint32 new_dos_attributes, /* attributes used for new file. */ + int oplock_request, /* internal Samba oplock codes. */ + /* Information (FILE_EXISTS etc.) */ + int *pinfo, + files_struct **result) +{ + NTSTATUS status; + files_struct *fsp = NULL; + + *result = NULL; + + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + return status; + } + + status = open_file_ntcreate_internal(conn, + req, + fname, + psbuf, + access_mask, + share_access, + create_disposition, + create_options, + new_dos_attributes, + oplock_request, + pinfo, + fsp); + + if(!NT_STATUS_IS_OK(status)) { + file_free(req, fsp); + return status; + } *result = fsp; - return NT_STATUS_OK; + return status; } /**************************************************************************** @@ -2097,10 +2131,9 @@ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn, status = open_file(fsp, conn, NULL, NULL, NULL, fname, psbuf, O_WRONLY, 0, FILE_WRITE_DATA, FILE_WRITE_DATA); - /* + /* * This is not a user visible file open. - * Don't set a share mode and don't increment - * the conn->num_files_open. + * Don't set a share mode. */ if (!NT_STATUS_IS_OK(status)) { @@ -2431,8 +2464,6 @@ NTSTATUS open_directory(connection_struct *conn, *pinfo = info; } - conn->num_files_open++; - *result = fsp; return NT_STATUS_OK; } @@ -2821,6 +2852,8 @@ NTSTATUS create_file_unixpath(connection_struct *conn, "%s\n", base, nt_errstr(status))); goto fail; } + /* we don't need to low level fd */ + fd_close(base_fsp); } /* @@ -2857,13 +2890,52 @@ NTSTATUS create_file_unixpath(connection_struct *conn, * Ordinary file case. */ - status = open_file_ntcreate( - conn, req, fname, &sbuf, access_mask, share_access, - create_disposition, create_options, file_attributes, - oplock_request, &info, &fsp); + if (base_fsp) { + /* + * We're opening the stream element of a base_fsp + * we already opened. We need to initialize + * the fsp first, and set up the base_fsp pointer. + */ + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fsp->base_fsp = base_fsp; + + status = open_file_ntcreate_internal(conn, + req, + fname, + &sbuf, + access_mask, + share_access, + create_disposition, + create_options, + file_attributes, + oplock_request, + &info, + fsp); + + if(!NT_STATUS_IS_OK(status)) { + file_free(req, fsp); + fsp = NULL; + } + } else { + status = open_file_ntcreate( + conn, req, fname, &sbuf, access_mask, share_access, + create_disposition, create_options, file_attributes, + oplock_request, &info, &fsp); + } if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { + /* A stream open never opens a directory */ + + if (base_fsp) { + status = NT_STATUS_FILE_IS_A_DIRECTORY; + goto fail; + } + /* * Fail the open if it was explicitly a non-directory * file. @@ -2887,6 +2959,8 @@ NTSTATUS create_file_unixpath(connection_struct *conn, goto fail; } + fsp->base_fsp = base_fsp; + /* * According to the MS documentation, the only time the security * descriptor is applied to the opened file is iff we *created* the @@ -2923,7 +2997,12 @@ NTSTATUS create_file_unixpath(connection_struct *conn, security_acl_map_generic(sd->dacl, &file_generic_mapping); security_acl_map_generic(sd->sacl, &file_generic_mapping); - status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd); + if (sec_info_sent & (OWNER_SECURITY_INFORMATION| + GROUP_SECURITY_INFORMATION| + DACL_SECURITY_INFORMATION| + SACL_SECURITY_INFORMATION)) { + status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd); + } fsp->access_mask = saved_access_mask; @@ -2968,16 +3047,6 @@ NTSTATUS create_file_unixpath(connection_struct *conn, DEBUG(10, ("create_file_unixpath: info=%d\n", info)); - /* - * Set fsp->base_fsp late enough that we can't "goto fail" anymore. In - * the fail: branch we call close_file(fsp, ERROR_CLOSE) which would - * also close fsp->base_fsp which we have to also do explicitly in - * this routine here, as not in all "goto fail:" we have the fsp set - * up already to be initialized with the base_fsp. - */ - - fsp->base_fsp = base_fsp; - *result = fsp; if (pinfo != NULL) { *pinfo = info; @@ -2996,6 +3065,13 @@ NTSTATUS create_file_unixpath(connection_struct *conn, DEBUG(10, ("create_file_unixpath: %s\n", nt_errstr(status))); if (fsp != NULL) { + if (base_fsp && fsp->base_fsp == base_fsp) { + /* + * The close_file below will close + * fsp->base_fsp. + */ + base_fsp = NULL; + } close_file(req, fsp, ERROR_CLOSE); fsp = NULL; } diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 88e7b766be..84b40f28cc 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -576,7 +576,7 @@ static bool user_ok(const char *user, int snum) TALLOC_FREE(valid); if (ret && lp_onlyuser(snum)) { - char **user_list = str_list_make( + char **user_list = str_list_make_v3( talloc_tos(), lp_username(snum), NULL); if (user_list && str_list_substitute(user_list, "%S", diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index b52b1b02d0..261f12cb08 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -78,7 +78,7 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) } #endif - status = np_open(req, conn, fname, &fsp); + status = np_open(req, fname, &fsp); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index cccf3087f7..97fd3b2bbe 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -870,7 +870,7 @@ static void merge_aces( canon_ace **pp_list_head ) Check if we need to return NT4.x compatible ACL entries. ****************************************************************************/ -static bool nt4_compatible_acls(void) +bool nt4_compatible_acls(void) { int compat = lp_acl_compatibility(); @@ -3211,6 +3211,9 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) return ret; } +#if 0 +/* Disable this - prevents ACL inheritance from the ACL editor. JRA. */ + /**************************************************************************** Take care of parent ACL inheritance. ****************************************************************************/ @@ -3398,6 +3401,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, *pp_new_sd = psd; return status; } +#endif /**************************************************************************** Reply to set a security descriptor on an fsp. security_info_sent is the @@ -3510,8 +3514,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); +#if 0 + /* Disable this - prevents ACL inheritance from the ACL editor. JRA. */ + /* See here: http://www.codeproject.com/KB/winsdk/accessctrl2.aspx - * for details. JRA. + * for details and also the log trace in bug #4308. JRA. */ if ((security_info_sent & DACL_SECURITY_INFORMATION) && @@ -3527,6 +3534,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC } psd = new_sd; } +#endif acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid, &file_ace_list, &dir_ace_list, security_info_sent, psd); @@ -4301,7 +4309,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) finfo.fh->fd = -1; finfo.fsp_name = CONST_DISCARD(char *,fname); - if (!NT_STATUS_IS_OK(posix_fget_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd))) { + if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) { DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n")); conn_free_internal( conn ); return NULL; diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 7931fbebab..b3cd2f26c8 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -37,6 +37,8 @@ SIG_ATOMIC_T got_sig_term = 0; extern bool global_machine_password_needs_changing; extern int max_send; +static void construct_reply_common(const char *inbuf, char *outbuf); + /* Accessor function for smb_read_error for smbd functions. */ /**************************************************************************** @@ -1590,7 +1592,7 @@ void remove_from_common_flags2(uint32 v) common_flags2 &= ~v; } -void construct_reply_common(const char *inbuf, char *outbuf) +static void construct_reply_common(const char *inbuf, char *outbuf) { srv_set_message(outbuf,0,0,false); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 377ba4e530..11c713ab4a 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -52,11 +52,45 @@ static NTSTATUS check_path_syntax_internal(char *path, const char *s = path; NTSTATUS ret = NT_STATUS_OK; bool start_of_name_component = True; + bool stream_started = false; *p_last_component_contains_wcard = False; while (*s) { - if (IS_PATH_SEP(*s,posix_path)) { + if (stream_started) { + switch (*s) { + case '/': + case '\\': + return NT_STATUS_OBJECT_NAME_INVALID; + case ':': + if (s[1] == '\0') { + return NT_STATUS_OBJECT_NAME_INVALID; + } + if (strchr_m(&s[1], ':')) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + if (StrCaseCmp(s, ":$DATA") != 0) { + return NT_STATUS_INVALID_PARAMETER; + } + break; + } + } + + if (!stream_started && *s == ':') { + if (*p_last_component_contains_wcard) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + /* stream names allow more characters than file names */ + stream_started = true; + start_of_name_component = false; + posix_path = true; + + if (s[1] == '\0') { + return NT_STATUS_OBJECT_NAME_INVALID; + } + } + + if (!stream_started && IS_PATH_SEP(*s,posix_path)) { /* * Safe to assume is not the second part of a mb char * as this is handled below. @@ -119,7 +153,7 @@ static NTSTATUS check_path_syntax_internal(char *path, if (!(*s & 0x80)) { if (!posix_path) { - if (*s <= 0x1f) { + if (*s <= 0x1f || *s == '|') { return NT_STATUS_OBJECT_NAME_INVALID; } switch (*s) { @@ -2894,7 +2928,7 @@ void reply_lockread(struct smb_request *req) return; } - if (!CHECK_READ(fsp,req->inbuf)) { + if (!CHECK_READ(fsp,req)) { reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBlockread); return; @@ -3002,7 +3036,7 @@ void reply_read(struct smb_request *req) return; } - if (!CHECK_READ(fsp,req->inbuf)) { + if (!CHECK_READ(fsp,req)) { reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBread); return; @@ -3255,7 +3289,7 @@ void reply_read_and_X(struct smb_request *req) return; } - if (!CHECK_READ(fsp,req->inbuf)) { + if (!CHECK_READ(fsp,req)) { reply_doserror(req, ERRDOS,ERRbadaccess); END_PROFILE(SMBreadX); return; @@ -4558,8 +4592,15 @@ void reply_printopen(struct smb_request *req) return; } + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBsplopen); + return; + } + /* Open for exclusive use, write only. */ - status = print_fsp_open(req, conn, NULL, req->vuid, &fsp); + status = print_fsp_open(req, conn, NULL, req->vuid, fsp); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -4989,8 +5030,16 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, } } - /* We only have veto files/directories. Recursive delete. */ + /* We only have veto files/directories. + * Are we allowed to delete them ? */ + if(!lp_recursive_veto_delete(SNUM(conn))) { + TALLOC_FREE(dir_hnd); + errno = ENOTEMPTY; + goto err; + } + + /* Do a recursive delete. */ RewindDir(dir_hnd,&dirpos); while ((dname = ReadDirName(dir_hnd,&dirpos))) { char *fullname = NULL; @@ -5016,9 +5065,8 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, break; } if(st.st_mode & S_IFDIR) { - if(lp_recursive_veto_delete(SNUM(conn))) { - if(!recursive_rmdir(ctx, conn, fullname)) - break; + if(!recursive_rmdir(ctx, conn, fullname)) { + break; } if(SMB_VFS_RMDIR(conn,fullname) != 0) { break; @@ -5448,6 +5496,12 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, return NT_STATUS_OBJECT_NAME_COLLISION; } + if(replace_if_exists && dst_exists) { + if (is_ntfs_stream_name(newname)) { + return NT_STATUS_INVALID_PARAMETER; + } + } + if (dst_exists) { struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf1); files_struct *dst_fsp = file_find_di_first(fileid); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 7583da65a5..fff05a3aac 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -80,7 +80,7 @@ struct event_context *smbd_event_context(void) { static struct event_context *ctx; - if (!ctx && !(ctx = event_context_init(NULL))) { + if (!ctx && !(ctx = event_context_init(talloc_autofree_context()))) { smb_panic("Could not init smbd event context"); } return ctx; @@ -91,7 +91,7 @@ struct messaging_context *smbd_messaging_context(void) static struct messaging_context *ctx; if (ctx == NULL) { - ctx = messaging_init(NULL, server_id_self(), + ctx = messaging_init(talloc_autofree_context(), server_id_self(), smbd_event_context()); } if (ctx == NULL) { @@ -105,7 +105,7 @@ struct memcache *smbd_memcache(void) static struct memcache *cache; if (!cache - && !(cache = memcache_init(NULL, + && !(cache = memcache_init(talloc_autofree_context(), lp_max_stat_cache_size()*1024))) { smb_panic("Could not init smbd memcache"); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 05197021a3..0dea615fb5 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -1123,38 +1123,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } -/*************************************************************************************** - Simple wrapper function for make_connection() to include a call to - vfs_chdir() - **************************************************************************************/ - -connection_struct *make_connection_with_chdir(const char *service_in, - DATA_BLOB password, - const char *dev, uint16 vuid, - NTSTATUS *status) -{ - connection_struct *conn = NULL; - - conn = make_connection(service_in, password, dev, vuid, status); - - /* - * make_connection() does not change the directory for us any more - * so we have to do it as a separate step --jerry - */ - - if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) { - DEBUG(0,("make_connection_with_chdir: Can't change " - "directory to %s for [print$] (%s)\n", - conn->connectpath,strerror(errno))); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; - return NULL; - } - - return conn; -} - /**************************************************************************** Make a connection to a service. * diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index fde6cdc160..24a201013a 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -1171,7 +1171,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) const char *p2; uint16 data_blob_len = SVAL(req->vwv+7, 0); enum remote_arch_types ra_type = get_remote_arch(); - int vuid = SVAL(req->inbuf,smb_uid); + int vuid = req->vuid; user_struct *vuser = NULL; NTSTATUS status = NT_STATUS_OK; uint16 smbpid = req->smbpid; @@ -1203,7 +1203,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) file_save("negotiate.dat", blob1.data, blob1.length); #endif - p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len; + p2 = (char *)req->buf + data_blob_len; p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2, STR_TERMINATE); diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c index f5f79c86e5..9dbacc2998 100644 --- a/source3/smbd/share_access.c +++ b/source3/smbd/share_access.c @@ -252,9 +252,11 @@ bool user_ok_token(const char *username, const char *domain, bool is_share_read_only_for_token(const char *username, const char *domain, - struct nt_user_token *token, int snum) + struct nt_user_token *token, + connection_struct *conn) { - bool result = lp_readonly(snum); + int snum = SNUM(conn); + bool result = conn->read_only; if (lp_readlist(snum) != NULL) { if (token_contains_name_in_list(username, domain, diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index d0e3a68e8a..7b051d389f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -768,6 +768,12 @@ void send_trans2_replies(connection_struct *conn, reply_outbuf(req, 10, total_sent_thistime + alignment_offset + data_alignment_offset); + /* + * We might have SMBtrans2s in req which was transferred to + * the outbuf, fix that. + */ + SCVAL(req->outbuf, smb_com, SMBtrans2); + /* Set total params and data to be sent */ SSVAL(req->outbuf,smb_tprcnt,paramsize); SSVAL(req->outbuf,smb_tdrcnt,datasize); @@ -1129,7 +1135,7 @@ static uint32 unix_filetype(mode_t mode) return UNIX_TYPE_SOCKET; #endif - DEBUG(0,("unix_filetype: unknown filetype %u", (unsigned)mode)); + DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode)); return UNIX_TYPE_UNKNOWN; } @@ -3993,6 +3999,46 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && is_ntfs_stream_name(fname)) { + char *base; + SMB_STRUCT_STAT bsbuf; + + status = split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("create_file_unixpath: " + "split_ntfs_stream_name failed: %s\n", + nt_errstr(status))); + reply_nterror(req, status); + return; + } + + SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */ + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn,base,&bsbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",base,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } else { + if (SMB_VFS_STAT(conn,base,&bsbuf) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",base,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } + + fileid = vfs_file_id_from_sbuf(conn, &bsbuf); + get_file_infos(fileid, &delete_pending, NULL); + if (delete_pending) { + reply_nterror(req, NT_STATUS_DELETE_PENDING); + return; + } + } + if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { @@ -4911,7 +4957,11 @@ NTSTATUS smb_set_file_time(connection_struct *conn, time_to_asc(convert_timespec_to_time_t(ts[1])) )); if (fsp != NULL) { - set_sticky_write_time_fsp(fsp, ts[1]); + if (fsp->base_fsp) { + set_sticky_write_time_fsp(fsp->base_fsp, ts[1]); + } else { + set_sticky_write_time_fsp(fsp, ts[1]); + } } else { set_sticky_write_time_path(conn, fname, vfs_file_id_from_sbuf(conn, psbuf), @@ -4921,6 +4971,10 @@ NTSTATUS smb_set_file_time(connection_struct *conn, DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); + if (fsp && fsp->base_fsp) { + fname = fsp->base_fsp->fsp_name; + } + if(file_ntimes(conn, fname, ts)!=0) { return map_nt_error_from_unix(errno); } @@ -5347,26 +5401,42 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_NOT_SUPPORTED; } - /* Create the base directory. */ - base_name = talloc_strdup(ctx, fname); - if (!base_name) { - return NT_STATUS_NO_MEMORY; - } - p = strrchr_m(base_name, '/'); - if (p) { - p[1] = '\0'; + if (fsp && fsp->base_fsp) { + if (newname[0] != ':') { + return NT_STATUS_NOT_SUPPORTED; + } + base_name = talloc_asprintf(ctx, "%s%s", + fsp->base_fsp->fsp_name, + newname); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } } else { - base_name = talloc_strdup(ctx, "./"); + if (is_ntfs_stream_name(newname)) { + return NT_STATUS_NOT_SUPPORTED; + } + + /* Create the base directory. */ + base_name = talloc_strdup(ctx, fname); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } + p = strrchr_m(base_name, '/'); + if (p) { + p[1] = '\0'; + } else { + base_name = talloc_strdup(ctx, "./"); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } + } + /* Append the new name. */ + base_name = talloc_asprintf_append(base_name, + "%s", + newname); if (!base_name) { return NT_STATUS_NO_MEMORY; } - } - /* Append the new name. */ - base_name = talloc_asprintf_append(base_name, - "%s", - newname); - if (!base_name) { - return NT_STATUS_NO_MEMORY; } if (fsp) { @@ -7263,8 +7333,8 @@ static void call_trans2ioctl(connection_struct *conn, return; } - if ((SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL) - && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + if ((SVAL(req->vwv+16, 0) == LMCAT_SPL) + && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) { *ppdata = (char *)SMB_REALLOC(*ppdata, 32); if (*ppdata == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); @@ -7527,8 +7597,6 @@ void reply_trans2(struct smb_request *req) unsigned int psoff; unsigned int pscnt; unsigned int tran_call; - unsigned int size; - unsigned int av_size; struct trans_state *state; NTSTATUS result; @@ -7545,8 +7613,6 @@ void reply_trans2(struct smb_request *req) psoff = SVAL(req->vwv+10, 0); pscnt = SVAL(req->vwv+9, 0); tran_call = SVAL(req->vwv+14, 0); - size = smb_len(req->inbuf) + 4; - av_size = smb_len(req->inbuf); result = allow_new_trans(conn->pending_trans, req->mid); if (!NT_STATUS_IS_OK(result)) { @@ -7611,8 +7677,8 @@ void reply_trans2(struct smb_request *req) */ if ( (state->setup_count == 4) && (tran_call == TRANSACT2_IOCTL) - && (SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL) - && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + && (SVAL(req->vwv+16, 0) == LMCAT_SPL) + && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) { DEBUG(2,("Got Trans2 DevIOctl jobid\n")); } else { DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count)); @@ -7628,6 +7694,12 @@ void reply_trans2(struct smb_request *req) goto bad_param; if (state->total_data) { + + if (trans_oob(state->total_data, 0, dscnt) + || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. */ state->data = (char *)SMB_MALLOC(state->total_data); @@ -7640,21 +7712,16 @@ void reply_trans2(struct smb_request *req) return; } - if (dscnt > state->total_data || - dsoff+dscnt < dsoff) { - goto bad_param; - } - - if (dsoff > av_size || - dscnt > av_size || - dsoff+dscnt > av_size) { - goto bad_param; - } - memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt); } if (state->total_param) { + + if (trans_oob(state->total_param, 0, pscnt) + || trans_oob(smb_len(req->inbuf), psoff, pscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. */ state->param = (char *)SMB_MALLOC(state->total_param); @@ -7668,17 +7735,6 @@ void reply_trans2(struct smb_request *req) return; } - if (pscnt > state->total_param || - psoff+pscnt < psoff) { - goto bad_param; - } - - if (psoff > av_size || - pscnt > av_size || - psoff+pscnt > av_size) { - goto bad_param; - } - memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt); } @@ -7726,8 +7782,6 @@ void reply_transs2(struct smb_request *req) connection_struct *conn = req->conn; unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp; struct trans_state *state; - unsigned int size; - unsigned int av_size; START_PROFILE(SMBtranss2); @@ -7739,9 +7793,6 @@ void reply_transs2(struct smb_request *req) return; } - size = smb_len(req->inbuf)+4; - av_size = smb_len(req->inbuf); - for (state = conn->pending_trans; state != NULL; state = state->next) { if (state->mid == req->mid) { @@ -7779,41 +7830,19 @@ void reply_transs2(struct smb_request *req) goto bad_param; if (pcnt) { - if (pdisp > state->total_param || - pcnt > state->total_param || - pdisp+pcnt > state->total_param || - pdisp+pcnt < pdisp) { - goto bad_param; - } - - if (poff > av_size || - pcnt > av_size || - poff+pcnt > av_size || - poff+pcnt < poff) { + if (trans_oob(state->total_param, pdisp, pcnt) + || trans_oob(smb_len(req->inbuf), poff, pcnt)) { goto bad_param; } - - memcpy(state->param+pdisp,smb_base(req->inbuf)+poff, - pcnt); + memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt); } if (dcnt) { - if (ddisp > state->total_data || - dcnt > state->total_data || - ddisp+dcnt > state->total_data || - ddisp+dcnt < ddisp) { - goto bad_param; - } - - if (ddisp > av_size || - dcnt > av_size || - ddisp+dcnt > av_size || - ddisp+dcnt < ddisp) { + if (trans_oob(state->total_data, ddisp, dcnt) + || trans_oob(smb_len(req->inbuf), doff, dcnt)) { goto bad_param; } - - memcpy(state->data+ddisp, smb_base(req->inbuf)+doff, - dcnt); + memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt); } if ((state->received_param < state->total_param) || @@ -7822,12 +7851,6 @@ void reply_transs2(struct smb_request *req) return; } - /* - * construct_reply_common will copy smb_com from inbuf to - * outbuf. SMBtranss2 is wrong here. - */ - SCVAL(req->inbuf,smb_com,SMBtrans2); - handle_trans2(conn, req, state); DLIST_REMOVE(conn->pending_trans, state); diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 8998f6a371..ca7df264e2 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -32,7 +32,7 @@ bool change_to_guest(void) if (!pass) { /* Don't need to free() this as its stored in a static */ - pass = getpwnam_alloc(NULL, lp_guestaccount()); + pass = getpwnam_alloc(talloc_autofree_context(), lp_guestaccount()); if (!pass) return(False); } @@ -88,7 +88,8 @@ static bool check_user_ok(connection_struct *conn, uint16_t vuid, readonly_share = is_share_read_only_for_token( server_info->unix_name, pdb_get_domain(server_info->sam_account), - server_info->ptok, snum); + server_info->ptok, + conn); if (!readonly_share && !share_access_check(server_info->ptok, lp_servicename(snum), @@ -317,9 +318,9 @@ bool become_authenticated_pipe_user(pipes_struct *p) if (!push_sec_ctx()) return False; - set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid, - p->pipe_user.ut.ngroups, p->pipe_user.ut.groups, - p->pipe_user.nt_user_token); + set_sec_ctx(p->server_info->utok.uid, p->server_info->utok.gid, + p->server_info->utok.ngroups, p->server_info->utok.groups, + p->server_info->ptok); return True; } |