diff options
Diffstat (limited to 'source/smbd/nttrans.c')
-rw-r--r-- | source/smbd/nttrans.c | 515 |
1 files changed, 306 insertions, 209 deletions
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index b5af173d45e..e69fd86995d 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -1,7 +1,7 @@ /* Unix SMB/CIFS implementation. SMB NT transaction handling - Copyright (C) Jeremy Allison 1994-1998 + Copyright (C) Jeremy Allison 1994-2007 Copyright (C) Stefan (metze) Metzmacher 2003 This program is free software; you can redistribute it and/or modify @@ -51,7 +51,7 @@ static char *nttrans_realloc(char **ptr, size_t size) if (ptr==NULL) { smb_panic("nttrans_realloc() called with NULL ptr"); } - + *ptr = (char *)SMB_REALLOC(*ptr, size); if(*ptr == NULL) { return NULL; @@ -80,7 +80,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, int alignment_offset = 3; int data_alignment_offset = 0; - /* + /* * If there genuinely are no parameters or data to send just send * the empty packet. */ @@ -101,10 +101,10 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, data_alignment_offset = 4 - (params_to_send % 4); } - /* + /* * Space is bufsize minus Netbios over TCP header minus SMB header. * The alignment_offset is to align the param bytes on a four byte - * boundary (2 bytes for data len, one byte pad). + * boundary (2 bytes for data len, one byte pad). * NT needs this to work correctly. */ @@ -131,7 +131,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, total_sent_thistime = params_to_send + data_to_send + alignment_offset + data_alignment_offset; - /* + /* * We can never send more than useable_space. */ @@ -146,7 +146,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, SIVAL(req->outbuf,smb_ntr_TotalParameterCount,paramsize); SIVAL(req->outbuf,smb_ntr_TotalDataCount,datasize); - /* + /* * Calculate how many parameters and data we can fit into * this packet. Parameters get precedence. */ @@ -172,7 +172,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, SIVAL(req->outbuf,smb_ntr_ParameterOffset, ((smb_buf(req->outbuf)+alignment_offset) - smb_base(req->outbuf))); - /* + /* * Absolute displacement of param bytes sent in this packet. */ @@ -202,7 +202,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, SIVAL(req->outbuf,smb_ntr_DataDisplacement, pd - pdata); } - /* + /* * Copy the param bytes into the packet. */ @@ -229,7 +229,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, +params_sent_thistime+data_alignment_offset, pd,data_sent_thistime); } - + DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", params_sent_thistime, data_sent_thistime, useable_space)); DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", @@ -240,7 +240,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, 0, 0, nt_error, __LINE__,__FILE__); } - + /* Send the packet */ show_msg((char *)req->outbuf); if (!send_smb(smbd_server_fd(),(char *)req->outbuf)) { @@ -248,10 +248,10 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, } TALLOC_FREE(req->outbuf); - + pp += params_sent_thistime; pd += data_sent_thistime; - + params_to_send -= params_sent_thistime; data_to_send -= data_sent_thistime; @@ -264,7 +264,7 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, params_to_send, data_to_send)); return; } - } + } } /**************************************************************************** @@ -385,14 +385,20 @@ static void nt_open_pipe(char *fname, connection_struct *conn, static void do_ntcreate_pipe_open(connection_struct *conn, struct smb_request *req) { - pstring fname; + char *fname = NULL; int pnum = -1; char *p = NULL; uint32 flags = IVAL(req->inbuf,smb_ntcreate_Flags); + TALLOC_CTX *ctx = talloc_tos(); - srvstr_pull_buf((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf), sizeof(fname), STR_TERMINATE); + srvstr_pull_buf_talloc(ctx, (char *)req->inbuf, req->flags2, &fname, + smb_buf(req->inbuf), STR_TERMINATE); + if (!fname) { + reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERRbadpipe); + return; + } nt_open_pipe(fname, conn, req, &pnum); if (req->outbuf) { @@ -402,7 +408,7 @@ static void do_ntcreate_pipe_open(connection_struct *conn, /* * Deal with pipe return. - */ + */ if (flags & EXTENDED_RESPONSE_REQUIRED) { /* This is very strange. We @@ -434,7 +440,7 @@ static void do_ntcreate_pipe_open(connection_struct *conn, if (flags & EXTENDED_RESPONSE_REQUIRED) { p += 25; SIVAL(p,0,FILE_GENERIC_ALL); - /* + /* * For pipes W2K3 seems to return * 0x12019B next. * This is ((FILE_GENERIC_READ|FILE_GENERIC_WRITE) & ~FILE_APPEND_DATA) @@ -470,9 +476,9 @@ static void reply_ntcreate_and_X_quota(connection_struct *conn, } reply_outbuf(req, 34, 0); - + p = (char *)req->outbuf + smb_vwv2; - + /* SCVAL(p,0,NO_OPLOCK_RETURN); */ p++; SSVAL(p,0,fsp->fnum); @@ -488,8 +494,8 @@ static void reply_ntcreate_and_X_quota(connection_struct *conn, void reply_ntcreate_and_X(connection_struct *conn, struct smb_request *req) -{ - pstring fname; +{ + char *fname = NULL; uint32 flags; uint32 access_mask; uint32 file_attributes; @@ -513,6 +519,7 @@ void reply_ntcreate_and_X(connection_struct *conn, BOOL extended_oplock_granted = False; NTSTATUS status; struct case_semantics_state *case_state = NULL; + TALLOC_CTX *ctx = talloc_tos(); START_PROFILE(SMBntcreateX); @@ -576,10 +583,9 @@ void reply_ntcreate_and_X(connection_struct *conn, /* * This filename is relative to a directory fid. */ - pstring rel_fname; + char *rel_fname = NULL; files_struct *dir_fsp = file_fsp( SVAL(req->inbuf, smb_ntcreate_RootDirectoryFid)); - size_t dir_name_len; if(!dir_fsp) { reply_doserror(req, ERRDOS, ERRbadfid); @@ -589,8 +595,9 @@ void reply_ntcreate_and_X(connection_struct *conn, if(!dir_fsp->is_directory) { - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf), sizeof(fname), 0, + srvstr_get_path(ctx, (char *)req->inbuf, + req->flags2, &fname, + smb_buf(req->inbuf), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -621,34 +628,68 @@ void reply_ntcreate_and_X(connection_struct *conn, return; } - /* - * Copy in the base directory name. - */ + if (ISDOT(dir_fsp->fsp_name)) { + /* + * We're at the toplevel dir, the final file name + * must not contain ./, as this is filtered out + * normally by srvstr_get_path and unix_convert + * explicitly rejects paths containing ./. + */ + fname = talloc_strdup(ctx,""); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBntcreateX); + return; + } + } else { + size_t dir_name_len = strlen(dir_fsp->fsp_name); + + /* + * Copy in the base directory name. + */ - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); + fname = TALLOC_ARRAY(ctx, char, dir_name_len+2); + if (!fname) { + reply_nterror( + req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBntcreateX); + return; + } + memcpy(fname, dir_fsp->fsp_name, dir_name_len+1); - /* - * Ensure it ends in a '\'. - */ + /* + * Ensure it ends in a '/'. + * We used TALLOC_SIZE +2 to add space for the '/'. + */ - if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { - pstrcat(fname, "/"); - dir_name_len++; + if(dir_name_len && + (fname[dir_name_len-1] != '\\') && + (fname[dir_name_len-1] != '/')) { + fname[dir_name_len] = '/'; + fname[dir_name_len+1] = '\0'; + } } - srvstr_get_path((char *)req->inbuf, req->flags2, rel_fname, - smb_buf(req->inbuf), sizeof(rel_fname), 0, + srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &rel_fname, + smb_buf(req->inbuf), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBntcreateX); return; } - pstrcat(fname, rel_fname); + fname = talloc_asprintf(ctx, "%s%s", + fname, + rel_fname); + if (!fname) { + reply_nterror( + req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBntcreateX); + return; + } } else { - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf), sizeof(fname), 0, + srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, + smb_buf(req->inbuf), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -681,12 +722,15 @@ void reply_ntcreate_and_X(connection_struct *conn, return; } } - + /* - * Now contruct the smb_open_mode value from the filename, + * Now contruct the smb_open_mode value from the filename, * desired access and the share access. */ - status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname); + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -707,17 +751,17 @@ void reply_ntcreate_and_X(connection_struct *conn, /* * Ordinary file or directory. */ - + /* * Check if POSIX semantics are wanted. */ - + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { case_state = set_posix_case_semantics(NULL, conn); file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; } - - status = unix_convert(conn, fname, False, NULL, &sbuf); + + status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(case_state); reply_nterror(req, status); @@ -885,8 +929,8 @@ void reply_ntcreate_and_X(connection_struct *conn, reply_doserror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBntcreateX); return; - } - + } + /* Save the requested allocation size. */ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { if (allocation_size && (allocation_size > (SMB_BIG_UINT)file_len)) { @@ -909,7 +953,7 @@ void reply_ntcreate_and_X(connection_struct *conn, } } - /* + /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the * correct bit for extended oplock reply. @@ -936,7 +980,7 @@ void reply_ntcreate_and_X(connection_struct *conn, } p = (char *)req->outbuf + smb_vwv2; - + /* * Currently as we don't support level II oplocks we just report * exclusive & batch here. @@ -953,7 +997,7 @@ void reply_ntcreate_and_X(connection_struct *conn, } else { SCVAL(p,0,NO_OPLOCK_RETURN); } - + p++; SSVAL(p,0,fsp->fnum); p += 2; @@ -1023,13 +1067,14 @@ static void do_nt_transact_create_pipe(connection_struct *conn, char **ppparams, uint32 parameter_count, char **ppdata, uint32 data_count) { - pstring fname; + char *fname = NULL; char *params = *ppparams; int pnum = -1; char *p = NULL; NTSTATUS status; size_t param_len; uint32 flags; + TALLOC_CTX *ctx = talloc_tos(); /* * Ensure minimum number of parameters sent. @@ -1043,8 +1088,8 @@ static void do_nt_transact_create_pipe(connection_struct *conn, flags = IVAL(params,0); - srvstr_get_path(params, req->flags2, fname, params+53, - sizeof(fname), parameter_count-53, STR_TERMINATE, + srvstr_get_path(ctx, params, req->flags2, &fname, params+53, + parameter_count-53, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1057,7 +1102,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn, /* Error return */ return; } - + /* Realloc the size of parameters and data we will return */ if (flags & EXTENDED_RESPONSE_REQUIRED) { /* Extended response is 32 more byyes. */ @@ -1070,16 +1115,16 @@ static void do_nt_transact_create_pipe(connection_struct *conn, reply_doserror(req, ERRDOS, ERRnomem); return; } - + p = params; SCVAL(p,0,NO_OPLOCK_RETURN); - + p += 2; SSVAL(p,0,pnum); p += 2; SIVAL(p,0,FILE_WAS_OPENED); p += 8; - + p += 32; SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */ p += 20; @@ -1088,11 +1133,11 @@ static void do_nt_transact_create_pipe(connection_struct *conn, /* Device state. */ SSVAL(p,2, 0x5FF); /* ? */ p += 4; - + if (flags & EXTENDED_RESPONSE_REQUIRED) { p += 25; SIVAL(p,0,FILE_GENERIC_ALL); - /* + /* * For pipes W2K3 seems to return * 0x12019B next. * This is ((FILE_GENERIC_READ|FILE_GENERIC_WRITE) & ~FILE_APPEND_DATA) @@ -1101,10 +1146,10 @@ static void do_nt_transact_create_pipe(connection_struct *conn, } DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname)); - + /* Send the required number of replies */ send_nt_replies(req, NT_STATUS_OK, params, param_len, *ppdata, 0); - + return; } @@ -1118,7 +1163,7 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu SEC_DESC *psd = NULL; TALLOC_CTX *mem_ctx; NTSTATUS status; - + if (sd_len == 0 || !lp_nt_acl_support(SNUM(fsp->conn))) { return NT_STATUS_OK; } @@ -1138,7 +1183,7 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu * Setup the prs_struct to point at the memory we just * allocated. */ - + prs_give_memory( &pd, data, sd_len, False); /* @@ -1149,11 +1194,11 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu DEBUG(0,("set_sd: Error in unmarshalling security descriptor.\n")); /* * Return access denied for want of a better error message.. - */ + */ talloc_destroy(mem_ctx); return NT_STATUS_NO_MEMORY; } - + if (psd->owner_sid==0) { security_info_sent &= ~OWNER_SECURITY_INFORMATION; } @@ -1166,9 +1211,9 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu if (psd->dacl==0) { security_info_sent &= ~DACL_SECURITY_INFORMATION; } - + status = SMB_VFS_FSET_NT_ACL( fsp, fsp->fh->fd, security_info_sent, psd); - + talloc_destroy(mem_ctx); return status; } @@ -1176,7 +1221,7 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu /**************************************************************************** Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. ****************************************************************************/ - + static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) { struct ea_list *ea_list_head = NULL; @@ -1200,7 +1245,7 @@ static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, } offset += next_offset; } - + return ea_list_head; } @@ -1215,7 +1260,7 @@ static void call_nt_transact_create(connection_struct *conn, char **ppdata, uint32 data_count, uint32 max_data_count) { - pstring fname; + char *fname = NULL; char *params = *ppparams; char *data = *ppdata; /* Breakout the oplock request bits so we can set the reply bits separately. */ @@ -1240,11 +1285,11 @@ static void call_nt_transact_create(connection_struct *conn, struct timespec a_timespec; struct timespec m_timespec; struct ea_list *ea_list = NULL; - TALLOC_CTX *ctx = NULL; char *pdata = NULL; NTSTATUS status; size_t param_len; struct case_semantics_state *case_state = NULL; + TALLOC_CTX *ctx = talloc_tos(); DEBUG(5,("call_nt_transact_create\n")); @@ -1325,8 +1370,8 @@ static void call_nt_transact_create(connection_struct *conn, /* * This filename is relative to a directory fid. */ + char *tmpname = NULL; files_struct *dir_fsp = file_fsp(SVAL(params,4)); - size_t dir_name_len; if(!dir_fsp) { reply_doserror(req, ERRDOS, ERRbadfid); @@ -1334,8 +1379,8 @@ static void call_nt_transact_create(connection_struct *conn, } if(!dir_fsp->is_directory) { - srvstr_get_path(params, req->flags2, fname, - params+53, sizeof(fname), + srvstr_get_path(ctx, params, req->flags2, &fname, + params+53, parameter_count-53, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { @@ -1357,37 +1402,64 @@ static void call_nt_transact_create(connection_struct *conn, return; } - /* - * Copy in the base directory name. - */ + if (ISDOT(dir_fsp->fsp_name)) { + /* + * We're at the toplevel dir, the final file name + * must not contain ./, as this is filtered out + * normally by srvstr_get_path and unix_convert + * explicitly rejects paths containing ./. + */ + fname = talloc_strdup(ctx,""); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + } else { + size_t dir_name_len = strlen(dir_fsp->fsp_name); - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); + /* + * Copy in the base directory name. + */ - /* - * Ensure it ends in a '\'. - */ + fname = TALLOC_ARRAY(ctx, char, dir_name_len+2); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + memcpy(fname, dir_fsp->fsp_name, dir_name_len+1); - if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { - pstrcat(fname, "/"); - dir_name_len++; - } + /* + * Ensure it ends in a '/'. + * We used TALLOC_SIZE +2 to add space for the '/'. + */ - { - pstring tmpname; - srvstr_get_path(params, req->flags2, tmpname, - params+53, sizeof(tmpname), - parameter_count-53, STR_TERMINATE, - &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; + if(dir_name_len && + (fname[dir_name_len-1] != '\\') && + (fname[dir_name_len-1] != '/')) { + fname[dir_name_len] = '/'; + fname[dir_name_len+1] = '\0'; } - pstrcat(fname, tmpname); + } + + srvstr_get_path(ctx, params, req->flags2, &tmpname, + params+53, + parameter_count-53, STR_TERMINATE, + &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + fname = talloc_asprintf(ctx, "%s%s", + fname, + tmpname); + if (!fname) { + reply_nterror( + req, NT_STATUS_NO_MEMORY); + return; } } else { - srvstr_get_path(params, req->flags2, fname, params+53, - sizeof(fname), parameter_count-53, + srvstr_get_path(ctx, params, req->flags2, &fname, params+53, + parameter_count-53, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1412,7 +1484,7 @@ static void call_nt_transact_create(connection_struct *conn, /* * Ordinary file or directory. */ - + /* * Check if POSIX semantics are wanted. */ @@ -1421,9 +1493,11 @@ static void call_nt_transact_create(connection_struct *conn, case_state = set_posix_case_semantics(NULL, conn); file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; } - - status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &fname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(case_state); if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -1435,7 +1509,7 @@ static void call_nt_transact_create(connection_struct *conn, return; } - status = unix_convert(conn, fname, False, NULL, &sbuf); + status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(case_state); reply_nterror(req, status); @@ -1576,7 +1650,7 @@ static void call_nt_transact_create(connection_struct *conn, * According to the MS documentation, the only time the security * descriptor is applied to the opened file is iff we *created* the * file; an existing file stays the same. - * + * * Also, it seems (from observation) that you can open the file with * any access mask but you can still write the sd. We need to override * the granted access before we call set_sd @@ -1592,7 +1666,6 @@ static void call_nt_transact_create(connection_struct *conn, status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION); if (!NT_STATUS_IS_OK(status)) { - talloc_destroy(ctx); close_file(fsp,ERROR_CLOSE); TALLOC_FREE(case_state); reply_nterror(req, status); @@ -1600,7 +1673,7 @@ static void call_nt_transact_create(connection_struct *conn, } fsp->access_mask = saved_access_mask; } - + if (ea_len && (info == FILE_WAS_CREATED)) { status = set_ea(conn, fsp, fname, ea_list); if (!NT_STATUS_IS_OK(status)) { @@ -1622,8 +1695,8 @@ static void call_nt_transact_create(connection_struct *conn, close_file(fsp,ERROR_CLOSE); reply_doserror(req, ERRDOS, ERRnoaccess); return; - } - + } + /* Save the requested allocation size. */ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(params,12); @@ -1648,7 +1721,7 @@ static void call_nt_transact_create(connection_struct *conn, } } - /* + /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the * correct bit for extended oplock reply. @@ -1687,7 +1760,7 @@ static void call_nt_transact_create(connection_struct *conn, } else { SCVAL(p,0,NO_OPLOCK_RETURN); } - + p += 2; SSVAL(p,0,fsp->fnum); p += 2; @@ -1758,12 +1831,12 @@ void reply_ntcancel(connection_struct *conn, struct smb_request *req) /* * Go through and cancel any pending change notifies. */ - + START_PROFILE(SMBntcancel); remove_pending_change_notify_requests_by_mid(req->mid); remove_pending_lock_requests_by_mid(req->mid); srv_cancel_sign_response(req->mid); - + DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", req->mid)); END_PROFILE(SMBntcancel); @@ -1774,13 +1847,18 @@ void reply_ntcancel(connection_struct *conn, struct smb_request *req) Copy a file. ****************************************************************************/ -static NTSTATUS copy_internals(connection_struct *conn, - struct smb_request *req, - char *oldname, char *newname, uint32 attrs) +static NTSTATUS copy_internals(TALLOC_CTX *ctx, + connection_struct *conn, + struct smb_request *req, + const char *oldname_in, + const char *newname_in, + uint32 attrs) { SMB_STRUCT_STAT sbuf1, sbuf2; - pstring last_component_oldname; - pstring last_component_newname; + char *oldname = NULL; + char *newname = NULL; + char *last_component_oldname = NULL; + char *last_component_newname = NULL; files_struct *fsp1,*fsp2; uint32 fattr; int info; @@ -1794,7 +1872,8 @@ static NTSTATUS copy_internals(connection_struct *conn, return NT_STATUS_MEDIA_WRITE_PROTECTED; } - status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1); + status = unix_convert(ctx, conn, oldname_in, False, &oldname, + &last_component_oldname, &sbuf1); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1814,7 +1893,8 @@ static NTSTATUS copy_internals(connection_struct *conn, return NT_STATUS_NO_SUCH_FILE; } - status = unix_convert(conn, newname, False, last_component_newname, &sbuf2); + status = unix_convert(ctx, conn, newname_in, False, &newname, + &last_component_newname, &sbuf2); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1840,7 +1920,8 @@ static NTSTATUS copy_internals(connection_struct *conn, return status; } - DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname)); + DEBUG(10,("copy_internals: doing file copy %s to %s\n", + oldname, newname)); status = open_file_ntcreate(conn, req, oldname, &sbuf1, FILE_READ_DATA, /* Read-only. */ @@ -1909,14 +1990,15 @@ static NTSTATUS copy_internals(connection_struct *conn, void reply_ntrename(connection_struct *conn, struct smb_request *req) { - pstring oldname; - pstring newname; + char *oldname = NULL; + char *newname = NULL; char *p; NTSTATUS status; BOOL src_has_wcard = False; BOOL dest_has_wcard = False; uint32 attrs; uint16 rename_type; + TALLOC_CTX *ctx = talloc_tos(); START_PROFILE(SMBntrename); @@ -1930,8 +2012,8 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) rename_type = SVAL(req->inbuf,smb_vwv1); p = smb_buf(req->inbuf) + 1; - p += srvstr_get_path_wcard((char *)req->inbuf, req->flags2, oldname, p, - sizeof(oldname), 0, STR_TERMINATE, &status, + p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &oldname, p, + 0, STR_TERMINATE, &status, &src_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1953,17 +2035,19 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) } p++; - p += srvstr_get_path_wcard((char *)req->inbuf, req->flags2, newname, p, - sizeof(newname), 0, STR_TERMINATE, &status, + p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p, + 0, STR_TERMINATE, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBntrename); return; } - - status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - oldname); + + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + oldname, + &oldname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1976,8 +2060,10 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) return; } - status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - newname); + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + &newname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1991,19 +2077,22 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) } DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname)); - + switch(rename_type) { case RENAME_FLAG_RENAME: - status = rename_internals(conn, req, oldname, newname, - attrs, False, src_has_wcard, - dest_has_wcard); + status = rename_internals(ctx, conn, req, oldname, + newname, attrs, False, src_has_wcard, + dest_has_wcard); break; case RENAME_FLAG_HARD_LINK: if (src_has_wcard || dest_has_wcard) { /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { - status = hardlink_internals(conn, oldname, newname); + status = hardlink_internals(ctx, + conn, + oldname, + newname); } break; case RENAME_FLAG_COPY: @@ -2011,7 +2100,7 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { - status = copy_internals(conn, req, oldname, + status = copy_internals(ctx, conn, req, oldname, newname, attrs); } break; @@ -2036,13 +2125,13 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) } reply_outbuf(req, 0, 0); - + END_PROFILE(SMBntrename); return; } /**************************************************************************** - Reply to a notify change - queue the request and + Reply to a notify change - queue the request and don't allow a directory to be opened. ****************************************************************************/ @@ -2154,11 +2243,12 @@ static void call_nt_transact_rename(connection_struct *conn, uint32 max_data_count) { char *params = *ppparams; - pstring new_name; + char *new_name = NULL; files_struct *fsp = NULL; BOOL replace_if_exists = False; BOOL dest_has_wcard = False; NTSTATUS status; + TALLOC_CTX *ctx = talloc_tos(); if(parameter_count < 5) { reply_doserror(req, ERRDOS, ERRbadfunc); @@ -2170,16 +2260,23 @@ static void call_nt_transact_rename(connection_struct *conn, if (!check_fsp(conn, req, fsp, ¤t_user)) { return; } - srvstr_get_path_wcard(params, req->flags2, new_name, params+4, - sizeof(new_name), parameter_count - 4, + srvstr_get_path_wcard(ctx, params, req->flags2, &new_name, params+4, + parameter_count - 4, STR_TERMINATE, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; } - status = rename_internals(conn, req, fsp->fsp_name, - new_name, 0, replace_if_exists, False, dest_has_wcard); + status = rename_internals(ctx, + conn, + req, + fsp->fsp_name, + new_name, + 0, + replace_if_exists, + False, + dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { @@ -2194,10 +2291,10 @@ static void call_nt_transact_rename(connection_struct *conn, * Rename was successful. */ send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); - - DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", + + DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", fsp->fsp_name, new_name)); - + return; } @@ -2330,7 +2427,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, security descriptor.\n")); /* * Return access denied for want of a better error message.. - */ + */ talloc_destroy(mem_ctx); reply_unixerror(req, ERRDOS, ERRnoaccess); return; @@ -2400,7 +2497,7 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); return; } - + /**************************************************************************** Reply to NT IOCTL ****************************************************************************/ @@ -2448,7 +2545,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum)); send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); return; - + case FSCTL_CREATE_OR_GET_OBJECT_ID: { unsigned char objid[16]; @@ -2494,7 +2591,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); reply_nterror(req, NT_STATUS_NOT_A_REPARSE_POINT); return; - + case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/ { /* @@ -2543,9 +2640,9 @@ static void call_nt_transact_ioctl(connection_struct *conn, reply_nterror(req, NT_STATUS_NO_MEMORY); return; } - + shadow_data->mem_ctx = shadow_mem_ctx; - + /* * Call the VFS routine to actually do the work. */ @@ -2585,7 +2682,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, talloc_destroy(shadow_data->mem_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; - } + } cur_pdata = pdata; @@ -2622,11 +2719,11 @@ static void call_nt_transact_ioctl(connection_struct *conn, return; } - + case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */ { - /* pretend this succeeded - - * + /* pretend this succeeded - + * * we have to send back a list with all files owned by this SID * * but I have to check that --metze @@ -2634,7 +2731,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, DOM_SID sid; uid_t uid; size_t sid_len = MIN(data_count-4,SID_MAX_SIZE); - + DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum)); if (!fsp_belongs_conn(conn, req, fsp, ¤t_user)) { @@ -2643,7 +2740,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, /* unknown 4 bytes: this is not the length of the sid :-( */ /*unknown = IVAL(pdata,0);*/ - + sid_parse(pdata+4,sid_len,&sid); DEBUGADD(10,("for SID: %s\n",sid_string_static(&sid))); @@ -2652,7 +2749,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, sid_string_static(&sid),(unsigned long)sid_len)); uid = (-1); } - + /* we can take a look at the find source :-) * * find ./ -uid $uid -name '*' is what we need here @@ -2665,16 +2762,16 @@ static void call_nt_transact_ioctl(connection_struct *conn, * (maybe we can hang the result anywhere in the fsp struct) * * we don't send all files at once - * and at the next we should *not* start from the beginning, - * so we have to cache the result + * and at the next we should *not* start from the beginning, + * so we have to cache the result * * --metze */ - + /* this works for now... */ send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); return; - } + } default: if (!logged_message) { logged_message = True; /* Only print this once... */ @@ -2689,7 +2786,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, #ifdef HAVE_SYS_QUOTAS /**************************************************************************** - Reply to get user quota + Reply to get user quota ****************************************************************************/ static void call_nt_transact_get_user_quota(connection_struct *conn, @@ -2737,7 +2834,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, reply_doserror(req, ERRDOS, ERRinvalidparam); return; } - + /* maybe we can check the quota_fnum */ fsp = file_fsp(SVAL(params,0)); if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { @@ -2752,16 +2849,16 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->pd; level = SVAL(params,2); - - /* unknown 12 bytes leading in params */ - + + /* unknown 12 bytes leading in params */ + switch (level) { case TRANSACT_GET_USER_QUOTA_LIST_CONTINUE: /* seems that we should continue with the enum here --metze */ - if (qt_handle->quota_list!=NULL && + if (qt_handle->quota_list!=NULL && qt_handle->tmp_list==NULL) { - + /* free the list */ free_ntquota_list(&(qt_handle->quota_list)); @@ -2803,7 +2900,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, /* we should not trust the value in max_data_count*/ max_data_count = MIN(max_data_count,2048); - + pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/ if(pdata == NULL) { reply_doserror(req, ERRDOS, ERRnomem); @@ -2814,7 +2911,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, /* set params Size of returned Quota Data 4 bytes*/ /* but set it later when we know it */ - + /* for each entry push the data */ if (start_enum) { @@ -2831,28 +2928,28 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, /* nextoffset entry 4 bytes */ SIVAL(entry,0,entry_len); - + /* then the len of the SID 4 bytes */ SIVAL(entry,4,sid_len); - + /* unknown data 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-metze*/ - + /* the used disk space 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,16,tmp_list->quotas->usedspace); - + /* the soft quotas 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,24,tmp_list->quotas->softlim); - + /* the hard quotas 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,32,tmp_list->quotas->hardlim); - + /* and now the SID */ sid_linearize(entry+40, sid_len, &tmp_list->quotas->sid); } - + qt_handle->tmp_list = tmp_list; - + /* overwrite the offset of the last entry */ SIVAL(entry-entry_len,0,0); @@ -2863,9 +2960,9 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, break; case TRANSACT_GET_USER_QUOTA_FOR_SID: - - /* unknown 4 bytes IVAL(pdata,0) */ - + + /* unknown 4 bytes IVAL(pdata,0) */ + if (data_count < 8) { DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8)); reply_doserror(req, ERRDOS, ERRunknownlevel); @@ -2898,11 +2995,11 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, } sid_parse(pdata+8,sid_len,&sid); - + if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) { ZERO_STRUCT(qt); - /* - * we have to return zero's in all fields + /* + * we have to return zero's in all fields * instead of returning an error here * --metze */ @@ -2926,25 +3023,25 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, /* set params Size of returned Quota Data 4 bytes*/ SIVAL(params,0,data_len); - + /* nextoffset entry 4 bytes */ SIVAL(entry,0,0); - + /* then the len of the SID 4 bytes */ SIVAL(entry,4,sid_len); - + /* unknown data 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-mezte*/ - + /* the used disk space 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,16,qt.usedspace); - + /* the soft quotas 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,24,qt.softlim); - + /* the hard quotas 8 bytes SMB_BIG_UINT */ SBIG_UINT(entry,32,qt.hardlim); - + /* and now the SID */ sid_linearize(entry+40, sid_len, &sid); @@ -3002,7 +3099,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, reply_doserror(req, ERRDOS, ERRinvalidparam); return; } - + /* maybe we can check the quota_fnum */ fsp = file_fsp(SVAL(params,0)); if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { @@ -3031,7 +3128,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, return; } - /* unknown 8 bytes in pdata + /* unknown 8 bytes in pdata * maybe its the change time in NTTIME */ @@ -3076,7 +3173,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, return; } #endif /* LARGE_SMB_OFF_T */ - + sid_parse(pdata+40,sid_len,&sid); DEBUGADD(8,("SID: %s\n",sid_string_static(&sid))); @@ -3206,7 +3303,7 @@ static void handle_nttrans(connection_struct *conn, &state->data, state->total_data, state->max_data_return); END_PROFILE(NT_transact_set_user_quota); - break; + break; } #endif /* HAVE_SYS_QUOTAS */ @@ -3286,7 +3383,7 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) state->setup = NULL; state->call = function_code; - /* + /* * All nttrans messages we handle have smb_wct == 19 + * state->setup_count. Ensure this is so as a sanity check. */ @@ -3318,7 +3415,7 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) reply_doserror(req, ERRDOS, ERRnomem); END_PROFILE(SMBnttrans); return; - } + } if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt)) goto bad_param; if ((smb_base(req->inbuf)+dsoff+dscnt @@ -3340,7 +3437,7 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) reply_doserror(req, ERRDOS, ERRnomem); END_PROFILE(SMBnttrans); return; - } + } if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt)) goto bad_param; if ((smb_base(req->inbuf)+psoff+pscnt @@ -3410,7 +3507,7 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) END_PROFILE(SMBnttrans); return; } - + /**************************************************************************** Reply to a SMBnttranss ****************************************************************************/ @@ -3468,7 +3565,7 @@ void reply_nttranss(connection_struct *conn, struct smb_request *req) state->received_param += pcnt; state->received_data += dcnt; - + if ((state->received_data > state->total_data) || (state->received_param > state->total_param)) goto bad_param; @@ -3508,7 +3605,7 @@ void reply_nttranss(connection_struct *conn, struct smb_request *req) goto bad_param; memcpy(state->data+ddisp, smb_base(req->inbuf)+doff, - dcnt); + dcnt); } if ((state->received_param < state->total_param) || |