diff options
Diffstat (limited to 'source3/smbd/reply.c')
-rw-r--r-- | source3/smbd/reply.c | 969 |
1 files changed, 587 insertions, 382 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index ca3a08f872..8db9c623f7 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -32,6 +32,7 @@ #include "fake_file.h" #include "rpc_client/rpc_client.h" #include "../librpc/gen_ndr/ndr_spoolss_c.h" +#include "../librpc/gen_ndr/open_files.h" #include "rpc_client/cli_spoolss.h" #include "rpc_client/init_spoolss.h" #include "rpc_server/rpc_ncacn_np.h" @@ -39,6 +40,9 @@ #include "libsmb/nmblib.h" #include "auth.h" #include "smbprofile.h" +#include "../lib/tsocket/tsocket.h" +#include "lib/tevent_wait.h" +#include "libcli/smb/smb_signing.h" /**************************************************************************** Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext @@ -314,7 +318,7 @@ size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req, char **pp_dest, const char *src, int flags, NTSTATUS *err, bool *contains_wcard) { - return srvstr_get_path_wcard(mem_ctx, (char *)req->inbuf, req->flags2, + return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2, pp_dest, src, smbreq_bufrem(req, src), flags, err, contains_wcard); } @@ -408,13 +412,13 @@ static bool netbios_session_retarget(struct smbd_server_connection *sconn, char *retarget; char *p; int retarget_type = 0x20; - int retarget_port = 139; + int retarget_port = NBT_SMB_PORT; struct sockaddr_storage retarget_addr; struct sockaddr_in *in_addr; bool ret = false; uint8_t outbuf[10]; - if (get_socket_port(sconn->sock) != 139) { + if (get_socket_port(sconn->sock) != NBT_SMB_PORT) { return false; } @@ -481,7 +485,7 @@ static bool netbios_session_retarget(struct smbd_server_connection *sconn, if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false, NULL)) { - exit_server_cleanly("netbios_session_regarget: srv_send_smb " + exit_server_cleanly("netbios_session_retarget: srv_send_smb " "failed."); } @@ -491,6 +495,13 @@ static bool netbios_session_retarget(struct smbd_server_connection *sconn, return ret; } +static void reply_called_name_not_present(char *outbuf) +{ + smb_setlen(outbuf, 1); + SCVAL(outbuf, 0, 0x83); + SCVAL(outbuf, 4, 0x82); +} + /**************************************************************************** Reply to a (netbios-level) special message. ****************************************************************************/ @@ -511,7 +522,7 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inb smb_setlen(outbuf,0); switch (msg_type) { - case 0x81: /* session request */ + case NBSSrequest: /* session request */ { /* inbuf_size is guarenteed to be at least 4. */ fstring name1,name2; @@ -524,18 +535,20 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inb exit_server_cleanly("multiple session request not permitted"); } - SCVAL(outbuf,0,0x82); + SCVAL(outbuf,0,NBSSpositive); SCVAL(outbuf,3,0); /* inbuf_size is guaranteed to be at least 4. */ name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4); if (name_len1 <= 0 || name_len1 > inbuf_size - 4) { DEBUG(0,("Invalid name length in session request\n")); + reply_called_name_not_present(outbuf); break; } name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1); if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) { DEBUG(0,("Invalid name length in session request\n")); + reply_called_name_not_present(outbuf); break; } @@ -546,6 +559,7 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inb if (name_type1 == -1 || name_type2 == -1) { DEBUG(0,("Invalid name type in session request\n")); + reply_called_name_not_present(outbuf); break; } @@ -562,12 +576,33 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inb */ if (strequal(name1, "*SMBSERVER ") || strequal(name1, "*SMBSERV ")) { - fstrcpy(name1, sconn->client_id.addr); + char *raddr; + + raddr = tsocket_address_inet_addr_string(sconn->remote_address, + talloc_tos()); + if (raddr == NULL) { + exit_server_cleanly("could not allocate raddr"); + } + + fstrcpy(name1, raddr); } set_local_machine_name(name1, True); set_remote_machine_name(name2, True); + if (is_ipaddress(sconn->remote_hostname)) { + char *p = discard_const_p(char, sconn->remote_hostname); + + talloc_free(p); + + sconn->remote_hostname = talloc_strdup(sconn, + get_remote_machine_name()); + if (sconn->remote_hostname == NULL) { + exit_server_cleanly("could not copy remote name"); + } + sconn->conn->remote_hostname = sconn->remote_hostname; + } + DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n", get_local_machine_name(), get_remote_machine_name(), name_type2)); @@ -575,18 +610,11 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inb if (name_type2 == 'R') { /* We are being asked for a pathworks session --- no thanks! */ - SCVAL(outbuf, 0,0x83); + reply_called_name_not_present(outbuf); break; } - /* only add the client's machine name to the list - of possibly valid usernames if we are operating - in share mode security */ - if (lp_security() == SEC_SHARE) { - add_session_user(sconn, get_remote_machine_name()); - } - - reload_services(sconn->msg_ctx, sconn->sock, True); + reload_services(sconn, conn_snum_used, true); reopen_logs(); sconn->nbt.got_session = true; @@ -595,17 +623,17 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inb case 0x89: /* session keepalive request (some old clients produce this?) */ - SCVAL(outbuf,0,SMBkeepalive); + SCVAL(outbuf,0,NBSSkeepalive); SCVAL(outbuf,3,0); break; - case 0x82: /* positive session response */ - case 0x83: /* negative session response */ - case 0x84: /* retarget session response */ + case NBSSpositive: /* positive session response */ + case NBSSnegative: /* negative session response */ + case NBSSretarget: /* retarget session response */ DEBUG(0,("Unexpected session response\n")); break; - case SMBkeepalive: /* session keepalive */ + case NBSSkeepalive: /* session keepalive */ default: return; } @@ -614,6 +642,10 @@ void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inb msg_type, msg_flags)); srv_send_smb(sconn, outbuf, false, 0, false, NULL); + + if (CVAL(outbuf, 0) != 0x82) { + exit_server_cleanly("invalid netbios session"); + } return; } @@ -632,9 +664,9 @@ void reply_tcon(struct smb_request *req) int pwlen=0; NTSTATUS nt_status; const char *p; - DATA_BLOB password_blob; TALLOC_CTX *ctx = talloc_tos(); struct smbd_server_connection *sconn = req->sconn; + NTTIME now = timeval_to_nttime(&req->request_time); START_PROFILE(SMBtcon); @@ -664,14 +696,10 @@ void reply_tcon(struct smb_request *req) service = service_buf; } - password_blob = data_blob(password, pwlen+1); - - conn = make_connection(sconn,service,password_blob,dev, + conn = make_connection(sconn, now, service, dev, req->vuid,&nt_status); req->conn = conn; - data_blob_clear_free(&password_blob); - if (!conn) { reply_nterror(req, nt_status); END_PROFILE(SMBtcon); @@ -699,7 +727,6 @@ void reply_tcon_and_X(struct smb_request *req) { connection_struct *conn = req->conn; const char *service = NULL; - DATA_BLOB password; TALLOC_CTX *ctx = talloc_tos(); /* what the cleint thinks the device is */ char *client_devicetype = NULL; @@ -709,7 +736,11 @@ void reply_tcon_and_X(struct smb_request *req) int passlen; char *path = NULL; const char *p, *q; - uint16 tcon_flags; + uint16_t tcon_flags; + struct smbXsrv_session *session = NULL; + NTTIME now = timeval_to_nttime(&req->request_time); + bool session_key_updated = false; + uint16_t optional_support = 0; struct smbd_server_connection *sconn = req->sconn; START_PROFILE(SMBtconX); @@ -724,10 +755,32 @@ void reply_tcon_and_X(struct smb_request *req) tcon_flags = SVAL(req->vwv+2, 0); /* we might have to close an old one */ - if ((tcon_flags & 0x1) && conn) { - close_cnum(conn,req->vuid); + if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) { + struct smbXsrv_tcon *tcon; + NTSTATUS status; + + tcon = conn->tcon; req->conn = NULL; conn = NULL; + + /* + * TODO: cancel all outstanding requests on the tcon + */ + status = smbXsrv_tcon_disconnect(tcon, req->vuid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("reply_tcon_and_X: " + "smbXsrv_tcon_disconnect() failed: %s\n", + nt_errstr(status))); + /* + * If we hit this case, there is something completely + * wrong, so we better disconnect the transport connection. + */ + END_PROFILE(SMBtconX); + exit_server(__location__ ": smbXsrv_tcon_disconnect failed"); + return; + } + + TALLOC_FREE(tcon); } if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) { @@ -737,27 +790,14 @@ void reply_tcon_and_X(struct smb_request *req) } if (sconn->smb1.negprot.encrypted_passwords) { - password = data_blob_talloc(talloc_tos(), req->buf, passlen); - if (lp_security() == SEC_SHARE) { - /* - * Security = share always has a pad byte - * after the password. - */ - p = (const char *)req->buf + passlen + 1; - } else { - p = (const char *)req->buf + passlen; - } + p = (const char *)req->buf + passlen; } else { - password = data_blob_talloc(talloc_tos(), req->buf, passlen+1); - /* Ensure correct termination */ - password.data[passlen]=0; p = (const char *)req->buf + passlen + 1; } p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE); if (path == NULL) { - data_blob_clear_free(&password); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBtconX); return; @@ -770,7 +810,6 @@ void reply_tcon_and_X(struct smb_request *req) if (*path=='\\') { q = strchr_m(path+2,'\\'); if (!q) { - data_blob_clear_free(&password); reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME); END_PROFILE(SMBtconX); return; @@ -785,7 +824,6 @@ void reply_tcon_and_X(struct smb_request *req) MIN(6, smbreq_bufrem(req, p)), STR_ASCII); if (client_devicetype == NULL) { - data_blob_clear_free(&password); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBtconX); return; @@ -793,13 +831,99 @@ void reply_tcon_and_X(struct smb_request *req) DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service)); - conn = make_connection(sconn, service, password, client_devicetype, + nt_status = smb1srv_session_lookup(req->sconn->conn, + req->vuid, now, &session); + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) { + reply_force_doserror(req, ERRSRV, ERRbaduid); + END_PROFILE(SMBtconX); + return; + } + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { + reply_nterror(req, nt_status); + END_PROFILE(SMBtconX); + return; + } + if (!NT_STATUS_IS_OK(nt_status)) { + reply_nterror(req, NT_STATUS_INVALID_HANDLE); + END_PROFILE(SMBtconX); + return; + } + + if (session->global->auth_session_info == NULL) { + reply_nterror(req, NT_STATUS_INVALID_HANDLE); + END_PROFILE(SMBtconX); + return; + } + + /* + * If there is no application key defined yet + * we create one. + * + * This means we setup the application key on the + * first tcon that happens via the given session. + * + * Once the application key is defined, it does not + * change any more. + */ + if (session->global->application_key.length == 0 && + session->global->signing_key.length > 0) + { + struct smbXsrv_session *x = session; + struct auth_session_info *session_info = + session->global->auth_session_info; + uint8_t session_key[16]; + + ZERO_STRUCT(session_key); + memcpy(session_key, x->global->signing_key.data, + MIN(x->global->signing_key.length, sizeof(session_key))); + + /* + * The application key is truncated/padded to 16 bytes + */ + x->global->application_key = data_blob_talloc(x->global, + session_key, + sizeof(session_key)); + ZERO_STRUCT(session_key); + if (x->global->application_key.data == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBtconX); + return; + } + + if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) { + smb_key_derivation(x->global->application_key.data, + x->global->application_key.length, + x->global->application_key.data); + optional_support |= SMB_EXTENDED_SIGNATURES; + } + + /* + * Place the application key into the session_info + */ + data_blob_clear_free(&session_info->session_key); + session_info->session_key = data_blob_dup_talloc(session_info, + x->global->application_key); + if (session_info->session_key.data == NULL) { + data_blob_clear_free(&x->global->application_key); + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBtconX); + return; + } + session_key_updated = true; + } + + conn = make_connection(sconn, now, service, client_devicetype, req->vuid, &nt_status); req->conn =conn; - data_blob_clear_free(&password); - if (!conn) { + if (session_key_updated) { + struct smbXsrv_session *x = session; + struct auth_session_info *session_info = + session->global->auth_session_info; + data_blob_clear_free(&x->global->application_key); + data_blob_clear_free(&session_info->session_key); + } reply_nterror(req, nt_status); END_PROFILE(SMBtconX); return; @@ -822,7 +946,7 @@ void reply_tcon_and_X(struct smb_request *req) } } else { /* NT sets the fstype of IPC$ to the null string */ - const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn)); + const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn)); if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) { /* Return permissions. */ @@ -855,30 +979,32 @@ void reply_tcon_and_X(struct smb_request *req) /* what does setting this bit do? It is set by NT4 and may affect the ability to autorun mounted cdroms */ - SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS| - (lp_csc_policy(SNUM(conn)) << 2)); + optional_support |= SMB_SUPPORT_SEARCH_BITS; + optional_support |= + (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT); if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) { DEBUG(2,("Serving %s as a Dfs root\n", - lp_servicename(SNUM(conn)) )); - SSVAL(req->outbuf, smb_vwv2, - SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2)); + lp_servicename(ctx, SNUM(conn)) )); + optional_support |= SMB_SHARE_IN_DFS; } + + SSVAL(req->outbuf, smb_vwv2, optional_support); } + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ DEBUG(3,("tconX service=%s \n", service)); /* set the incoming and outgoing tid to the just created one */ - SSVAL(req->inbuf,smb_tid,conn->cnum); + SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum); SSVAL(req->outbuf,smb_tid,conn->cnum); END_PROFILE(SMBtconX); req->tid = conn->cnum; - chain_reply(req); - return; } /**************************************************************************** @@ -950,17 +1076,16 @@ void reply_ioctl(struct smb_request *req) return; } /* Job number */ - if (fsp->print_file) { - SSVAL(p, 0, fsp->print_file->rap_jobid); - } else { - SSVAL(p, 0, 0); - } + SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file)); + srvstr_push((char *)req->outbuf, req->flags2, p+2, - global_myname(), 15, + lp_netbios_name(), 15, STR_TERMINATE|STR_ASCII); if (conn) { srvstr_push((char *)req->outbuf, req->flags2, - p+18, lp_servicename(SNUM(conn)), + p+18, + lp_servicename(talloc_tos(), + SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); } else { memset(p+18, 0, 13); @@ -1087,7 +1212,7 @@ void reply_getatr(struct smb_request *req) struct smb_filename *smb_fname = NULL; char *fname = NULL; int mode=0; - SMB_OFF_T size=0; + off_t size=0; time_t mtime=0; const char *p; NTSTATUS status; @@ -1246,19 +1371,19 @@ void reply_setatr(struct smb_request *req) mode = SVAL(req->vwv+0, 0); mtime = srv_make_unix_date3(req->vwv+1); - ft.mtime = convert_time_t_to_timespec(mtime); - status = smb_set_file_time(conn, NULL, smb_fname, &ft, true); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - if (mode != FILE_ATTRIBUTE_NORMAL) { if (VALID_STAT_OF_DIR(smb_fname->st)) mode |= FILE_ATTRIBUTE_DIRECTORY; else mode &= ~FILE_ATTRIBUTE_DIRECTORY; + status = check_access(conn, NULL, smb_fname, + FILE_WRITE_ATTRIBUTES); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; + } + if (file_set_dosmode(conn, smb_fname, mode, NULL, false) != 0) { reply_nterror(req, map_nt_error_from_unix(errno)); @@ -1266,6 +1391,13 @@ void reply_setatr(struct smb_request *req) } } + ft.mtime = convert_time_t_to_timespec(mtime); + status = smb_set_file_time(conn, NULL, smb_fname, &ft, true); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; + } + reply_outbuf(req, 0, 0); DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname), @@ -1373,7 +1505,7 @@ void reply_search(struct smb_request *req) char *directory = NULL; struct smb_filename *smb_fname = NULL; char *fname = NULL; - SMB_OFF_T size; + off_t size; uint32 mode; struct timespec date; uint32 dirtype; @@ -1466,6 +1598,7 @@ void reply_search(struct smb_request *req) SCVAL(status,0,(dirtype & 0x1F)); nt_status = dptr_create(conn, + NULL, /* req */ NULL, /* fsp */ directory, True, @@ -1521,7 +1654,7 @@ void reply_search(struct smb_request *req) if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) { char buf[DIR_STRUCT_SIZE]; memcpy(buf,status,21); - if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)), + if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)), 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) { reply_nterror(req, NT_STATUS_NO_MEMORY); goto out; @@ -1547,8 +1680,8 @@ void reply_search(struct smb_request *req) /DIR_STRUCT_SIZE)); DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - directory,lp_dontdescend(SNUM(conn)))); - if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) { + directory,lp_dontdescend(ctx, SNUM(conn)))); + if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) { check_descend = True; } @@ -1714,7 +1847,7 @@ void reply_open(struct smb_request *req) struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 fattr=0; - SMB_OFF_T size = 0; + off_t size = 0; time_t mtime=0; int info; files_struct *fsp; @@ -1793,7 +1926,7 @@ void reply_open(struct smb_request *req) &info); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -1970,7 +2103,7 @@ void reply_open_and_X(struct smb_request *req) &smb_action); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -1987,7 +2120,7 @@ void reply_open_and_X(struct smb_request *req) reply_nterror(req, NT_STATUS_DISK_FULL); goto out; } - retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size); + retval = vfs_set_filelen(fsp, (off_t)allocation_size); if (retval < 0) { close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, NT_STATUS_DISK_FULL); @@ -2033,6 +2166,9 @@ void reply_open_and_X(struct smb_request *req) reply_outbuf(req, 15, 0); } + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) { SCVAL(req->outbuf, smb_flg, CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED); @@ -2058,7 +2194,6 @@ void reply_open_and_X(struct smb_request *req) SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL); } - chain_reply(req); out: TALLOC_FREE(smb_fname); END_PROFILE(SMBopenX); @@ -2072,32 +2207,55 @@ void reply_open_and_X(struct smb_request *req) void reply_ulogoffX(struct smb_request *req) { struct smbd_server_connection *sconn = req->sconn; - user_struct *vuser; + struct user_struct *vuser; + struct smbXsrv_session *session = NULL; + NTSTATUS status; START_PROFILE(SMBulogoffX); vuser = get_valid_user_struct(sconn, req->vuid); if(vuser == NULL) { - DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", - req->vuid)); + DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n", + (unsigned long long)req->vuid)); + + req->vuid = UID_FIELD_INVALID; + reply_force_doserror(req, ERRSRV, ERRbaduid); + END_PROFILE(SMBulogoffX); + return; } - /* in user level security we are supposed to close any files - open by this user */ - if ((vuser != NULL) && (lp_security() != SEC_SHARE)) { - file_close_user(sconn, req->vuid); + session = vuser->session; + vuser = NULL; + + /* + * TODO: cancel all outstanding requests on the session + */ + status = smbXsrv_session_logoff(session); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("reply_ulogoff: " + "smbXsrv_session_logoff() failed: %s\n", + nt_errstr(status))); + /* + * If we hit this case, there is something completely + * wrong, so we better disconnect the transport connection. + */ + END_PROFILE(SMBulogoffX); + exit_server(__location__ ": smbXsrv_session_logoff failed"); + return; } - invalidate_vuid(sconn, req->vuid); + TALLOC_FREE(session); reply_outbuf(req, 2, 0); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ - DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) ); + DEBUG(3, ("ulogoffX vuid=%llu\n", + (unsigned long long)req->vuid)); END_PROFILE(SMBulogoffX); req->vuid = UID_FIELD_INVALID; - chain_reply(req); } /**************************************************************************** @@ -2192,7 +2350,7 @@ void reply_mknew(struct smb_request *req) NULL); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -2239,14 +2397,13 @@ void reply_ctemp(struct smb_request *req) { connection_struct *conn = req->conn; struct smb_filename *smb_fname = NULL; - char *wire_name = NULL; char *fname = NULL; uint32 fattr; files_struct *fsp; int oplock_request; + int tmpfd; char *s; NTSTATUS status; - int i; TALLOC_CTX *ctx = talloc_tos(); START_PROFILE(SMBctemp); @@ -2259,86 +2416,77 @@ void reply_ctemp(struct smb_request *req) fattr = SVAL(req->vwv+0, 0); oplock_request = CORE_OPLOCK_REQUEST(req->inbuf); - srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1, + srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } + if (*fname) { + fname = talloc_asprintf(ctx, + "%s/TMXXXXXX", + fname); + } else { + fname = talloc_strdup(ctx, "TMXXXXXX"); + } - for (i = 0; i < 10; i++) { - if (*wire_name) { - fname = talloc_asprintf(ctx, - "%s/TMP%s", - wire_name, - generate_random_str_list(ctx, 5, "0123456789")); - } else { - fname = talloc_asprintf(ctx, - "TMP%s", - generate_random_str_list(ctx, 5, "0123456789")); - } - - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; - } + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + goto out; + } - status = filename_convert(ctx, conn, + status = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, 0, NULL, &smb_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, + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); goto out; } + reply_nterror(req, status); + goto out; + } - /* Create the file. */ - status = SMB_VFS_CREATE_FILE( - conn, /* conn */ - req, /* req */ - 0, /* root_dir_fid */ - smb_fname, /* fname */ - FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */ - FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ - FILE_CREATE, /* create_disposition*/ - 0, /* create_options */ - fattr, /* file_attributes */ - oplock_request, /* oplock_request */ - 0, /* allocation_size */ - 0, /* private_flags */ - NULL, /* sd */ - NULL, /* ea_list */ - &fsp, /* result */ - NULL); /* pinfo */ - - if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) { - TALLOC_FREE(fname); - TALLOC_FREE(smb_fname); - continue; - } + tmpfd = mkstemp(smb_fname->base_name); + if (tmpfd == -1) { + reply_nterror(req, map_nt_error_from_unix(errno)); + goto out; + } - if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { - /* We have re-scheduled this call. */ - goto out; - } - reply_openerror(req, status); - goto out; - } + SMB_VFS_STAT(conn, smb_fname); - break; - } + /* We should fail if file does not exist. */ + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + smb_fname, /* fname */ + FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ + FILE_OPEN, /* create_disposition*/ + 0, /* create_options */ + fattr, /* file_attributes */ + oplock_request, /* oplock_request */ + 0, /* allocation_size */ + 0, /* private_flags */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp, /* result */ + NULL); /* pinfo */ - if (i == 10) { - /* Collision after 10 times... */ - reply_nterror(req, status); + /* close fd from mkstemp() */ + close(tmpfd); + + if (!NT_STATUS_IS_OK(status)) { + if (open_was_deferred(req->sconn, req->mid)) { + /* We have re-scheduled this call. */ + goto out; + } + reply_openerror(req, status); goto out; } @@ -2379,8 +2527,6 @@ void reply_ctemp(struct smb_request *req) fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode)); out: TALLOC_FREE(smb_fname); - TALLOC_FREE(fname); - TALLOC_FREE(wire_name); END_PROFILE(SMBctemp); return; } @@ -2553,9 +2699,9 @@ static NTSTATUS do_unlink(connection_struct *conn, } /* The set is across all open files on this dev/inode pair. */ - if (!set_delete_on_close(fsp, true, + if (!set_delete_on_close(fsp, True, conn->session_info->security_token, - &conn->session_info->utok)) { + conn->session_info->unix_token)) { close_file(req, fsp, NORMAL_CLOSE); return NT_STATUS_ACCESS_DENIED; } @@ -2813,7 +2959,7 @@ void reply_unlink(struct smb_request *req) status = unlink_internals(conn, req, dirtype, smb_fname, path_contains_wcard); if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -2847,7 +2993,7 @@ static void fail_readraw(void) Fake (read/write) sendfile. Returns -1 on read or write fail. ****************************************************************************/ -ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread) +ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread) { size_t bufsize; size_t tosend = nread; @@ -3010,7 +3156,7 @@ static void reply_readbraw_error(struct smbd_server_connection *sconn) static void send_file_readbraw(connection_struct *conn, struct smb_request *req, files_struct *fsp, - SMB_OFF_T startpos, + off_t startpos, size_t nread, ssize_t mincount) { @@ -3093,9 +3239,9 @@ static void send_file_readbraw(connection_struct *conn, normal_readbraw: - outbuf = TALLOC_ARRAY(NULL, char, nread+4); + outbuf = talloc_array(NULL, char, nread+4); if (!outbuf) { - DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n", + DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n", (unsigned)(nread+4))); reply_readbraw_error(sconn); return; @@ -3141,14 +3287,15 @@ void reply_readbraw(struct smb_request *req) struct smbd_server_connection *sconn = req->sconn; ssize_t maxcount,mincount; size_t nread = 0; - SMB_OFF_T startpos; + off_t startpos; files_struct *fsp; struct lock_struct lock; - SMB_OFF_T size = 0; + off_t size = 0; START_PROFILE(SMBreadbraw); - if (srv_is_signing_active(sconn) || req->encrypted) { + if (srv_is_signing_active(sconn) || + is_encrypted_packet(sconn, req->inbuf)) { exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - " "raw reads/writes are disallowed."); } @@ -3213,27 +3360,8 @@ void reply_readbraw(struct smb_request *req) /* * This is a large offset (64 bit) read. */ -#ifdef LARGE_SMB_OFF_T - startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32); - -#else /* !LARGE_SMB_OFF_T */ - - /* - * Ensure we haven't been sent a >32 bit offset. - */ - - if(IVAL(req->vwv+8, 0) != 0) { - DEBUG(0,("reply_readbraw: large offset " - "(%x << 32) used and we don't support " - "64 bit offsets.\n", - (unsigned int)IVAL(req->vwv+8, 0) )); - reply_readbraw_error(sconn); - END_PROFILE(SMBreadbraw); - return; - } - -#endif /* LARGE_SMB_OFF_T */ + startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32); if(startpos < 0) { DEBUG(0,("reply_readbraw: negative 64 bit " @@ -3276,9 +3404,9 @@ void reply_readbraw(struct smb_request *req) nread = 0; #endif - DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu " + DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu " "min=%lu nread=%lu\n", - fsp->fnum, (double)startpos, + fsp_fnum_dbg(fsp), (double)startpos, (unsigned long)maxcount, (unsigned long)mincount, (unsigned long)nread ) ); @@ -3305,7 +3433,7 @@ void reply_lockread(struct smb_request *req) connection_struct *conn = req->conn; ssize_t nread = -1; char *data; - SMB_OFF_T startpos; + off_t startpos; size_t numtoread; NTSTATUS status; files_struct *fsp; @@ -3397,8 +3525,8 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", SCVAL(p,0,0); /* pad byte. */ SSVAL(p,1,nread); - DEBUG(3,("lockread fnum=%d num=%d nread=%d\n", - fsp->fnum, (int)numtoread, (int)nread)); + DEBUG(3,("lockread %s num=%d nread=%d\n", + fsp_fnum_dbg(fsp), (int)numtoread, (int)nread)); END_PROFILE(SMBlockread); return; @@ -3417,7 +3545,7 @@ void reply_read(struct smb_request *req) size_t numtoread; ssize_t nread = 0; char *data; - SMB_OFF_T startpos; + off_t startpos; int outsize = 0; files_struct *fsp; struct lock_struct lock; @@ -3489,8 +3617,8 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", SCVAL(smb_buf(req->outbuf),0,1); SSVAL(smb_buf(req->outbuf),1,nread); - DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n", - fsp->fnum, (int)numtoread, (int)nread ) ); + DEBUG(3, ("read %s num=%d nread=%d\n", + fsp_fnum_dbg(fsp), (int)numtoread, (int)nread)); strict_unlock: SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); @@ -3507,10 +3635,8 @@ static int setup_readX_header(struct smb_request *req, char *outbuf, size_t smb_maxcnt) { int outsize; - char *data; outsize = srv_set_message(outbuf,12,smb_maxcnt,False); - data = smb_buf(outbuf); memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */ @@ -3518,7 +3644,7 @@ static int setup_readX_header(struct smb_request *req, char *outbuf, SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */ SSVAL(outbuf,smb_vwv5,smb_maxcnt); SSVAL(outbuf,smb_vwv6, - req_wct_ofs(req) + (smb_wct - 4) /* offset from smb header to wct */ + 1 /* the wct field */ + 12 * sizeof(uint16_t) /* vwv */ + 2); /* the buflen field */ @@ -3534,13 +3660,18 @@ static int setup_readX_header(struct smb_request *req, char *outbuf, ****************************************************************************/ static void send_file_readX(connection_struct *conn, struct smb_request *req, - files_struct *fsp, SMB_OFF_T startpos, + files_struct *fsp, off_t startpos, size_t smb_maxcnt) { ssize_t nread = -1; struct lock_struct lock; int saved_errno = 0; + if(fsp_stat(fsp) == -1) { + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + init_strict_lock_struct(fsp, (uint64_t)req->smbpid, (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK, &lock); @@ -3550,6 +3681,16 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, return; } + if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) || + (startpos > fsp->fsp_name->st.st_ex_size) + || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) { + /* + * We already know that we would do a short read, so don't + * try the sendfile() path. + */ + goto nosendfile_read; + } + /* * We can only use sendfile on a non-chained packet * but we can use on a non-oplocked file. tridge proved this @@ -3557,27 +3698,13 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, */ if (!req_is_in_chain(req) && - !req->encrypted && (fsp->base_fsp == NULL) && + !is_encrypted_packet(req->sconn, req->inbuf) && + (fsp->base_fsp == NULL) && (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) { uint8 headerbuf[smb_size + 12 * 2]; DATA_BLOB header; - if(fsp_stat(fsp) == -1) { - reply_nterror(req, map_nt_error_from_unix(errno)); - goto strict_unlock; - } - - if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) || - (startpos > fsp->fsp_name->st.st_ex_size) || - (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) { - /* - * We already know that we would do a short read, so don't - * try the sendfile() path. - */ - goto nosendfile_read; - } - /* * Set up the packet header before send. We * assume here the sendfile will work (get the @@ -3618,8 +3745,8 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, strerror(errno))); exit_server_cleanly("send_file_readX: fake_sendfile failed"); } - DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_maxcnt, (int)nread ) ); + DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n", + fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread)); /* No outbuf here means successful sendfile. */ goto strict_unlock; } @@ -3642,8 +3769,8 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, goto normal_read; } - DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_maxcnt, (int)nread ) ); + DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n", + fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread)); /* Deal with possible short send. */ if (nread != smb_maxcnt + sizeof(headerbuf)) { @@ -3696,6 +3823,8 @@ normal_read: nosendfile_read: reply_outbuf(req, 12, smb_maxcnt); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt); saved_errno = errno; @@ -3709,10 +3838,8 @@ nosendfile_read: setup_readX_header(req, (char *)req->outbuf, nread); - DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_maxcnt, (int)nread ) ); - - chain_reply(req); + DEBUG(3, ("send_file_readX %s max=%d nread=%d\n", + fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread)); return; strict_unlock: @@ -3727,9 +3854,10 @@ nosendfile_read: void reply_read_and_X(struct smb_request *req) { + struct smbd_server_connection *sconn = req->sconn; connection_struct *conn = req->conn; files_struct *fsp; - SMB_OFF_T startpos; + off_t startpos; size_t smb_maxcnt; bool big_readX = False; #if 0 @@ -3765,7 +3893,15 @@ void reply_read_and_X(struct smb_request *req) return; } - if (global_client_caps & CAP_LARGE_READX) { + if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) || + (get_remote_arch() == RA_SAMBA)) { + /* + * This is Samba only behavior (up to Samba 3.6)! + * + * Windows 2008 R2 ignores the upper_size, + * so we do unless unix extentions are active + * or "smbclient" is talking to us. + */ size_t upper_size = SVAL(req->vwv+7, 0); smb_maxcnt |= (upper_size<<16); if (upper_size > 1) { @@ -3776,7 +3912,8 @@ void reply_read_and_X(struct smb_request *req) return; } /* We currently don't do this on signed or sealed data. */ - if (srv_is_signing_active(req->sconn) || req->encrypted) { + if (srv_is_signing_active(req->sconn) || + is_encrypted_packet(req->sconn, req->inbuf)) { reply_nterror(req, NT_STATUS_NOT_SUPPORTED); END_PROFILE(SMBreadX); return; @@ -3793,28 +3930,10 @@ void reply_read_and_X(struct smb_request *req) } if (req->wct == 12) { -#ifdef LARGE_SMB_OFF_T /* * This is a large offset (64 bit) read. */ - startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32); - -#else /* !LARGE_SMB_OFF_T */ - - /* - * Ensure we haven't been sent a >32 bit offset. - */ - - if(IVAL(req->vwv+10, 0) != 0) { - DEBUG(0,("reply_read_and_X - large offset (%x << 32) " - "used and we don't support 64 bit offsets.\n", - (unsigned int)IVAL(req->vwv+10, 0) )); - END_PROFILE(SMBreadX); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - -#endif /* LARGE_SMB_OFF_T */ + startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32); } @@ -3870,9 +3989,9 @@ void error_to_writebrawerr(struct smb_request *req) static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout, size_t *len) { - uint8_t msgtype = SMBkeepalive; + uint8_t msgtype = NBSSkeepalive; - while (msgtype == SMBkeepalive) { + while (msgtype == NBSSkeepalive) { NTSTATUS status; status = read_smb_length_return_keepalive(fd, inbuf, timeout, @@ -3909,8 +4028,8 @@ void reply_writebraw(struct smb_request *req) ssize_t total_written=0; size_t numtowrite=0; size_t tcount; - SMB_OFF_T startpos; - char *data=NULL; + off_t startpos; + const char *data=NULL; bool write_through; files_struct *fsp; struct lock_struct lock; @@ -3923,7 +4042,7 @@ void reply_writebraw(struct smb_request *req) * type of SMBwritec, not SMBwriteBraw, as this tells the client * we're finished. */ - SCVAL(req->inbuf,smb_com,SMBwritec); + SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec); if (srv_is_signing_active(req->sconn)) { END_PROFILE(SMBwritebraw); @@ -3969,8 +4088,8 @@ void reply_writebraw(struct smb_request *req) on whether we are using the core+ or lanman1.0 protocol */ if(get_Protocol() <= PROTOCOL_COREPLUS) { - numtowrite = SVAL(smb_buf(req->inbuf),-2); - data = smb_buf(req->inbuf); + numtowrite = SVAL(smb_buf_const(req->inbuf),-2); + data = smb_buf_const(req->inbuf); } else { numtowrite = SVAL(req->vwv+10, 0); data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0); @@ -4001,9 +4120,9 @@ void reply_writebraw(struct smb_request *req) nwritten = write_file(req,fsp,data,startpos,numtowrite); } - DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d " + DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d " "wrote=%d sync=%d\n", - fsp->fnum, (double)startpos, (int)numtowrite, + fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through)); if (nwritten < (ssize_t)numtowrite) { @@ -4015,7 +4134,7 @@ void reply_writebraw(struct smb_request *req) total_written = nwritten; /* Allocate a buffer of 64k + length. */ - buf = TALLOC_ARRAY(NULL, char, 65540); + buf = talloc_array(NULL, char, 65540); if (!buf) { reply_nterror(req, NT_STATUS_NO_MEMORY); error_to_writebrawerr(req); @@ -4108,9 +4227,9 @@ void reply_writebraw(struct smb_request *req) goto strict_unlock; } - DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d " + DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d " "wrote=%d\n", - fsp->fnum, (double)startpos, (int)numtowrite, + fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite, (int)total_written)); if (!fsp->print_file) { @@ -4126,7 +4245,7 @@ void reply_writebraw(struct smb_request *req) #if RABBIT_PELLET_FIX /* * Fix for "rabbit pellet" mode, trigger an early TCP ack by - * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. + * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this. * JRA. */ if (!send_keepalive(req->sconn->sock)) { @@ -4159,7 +4278,7 @@ void reply_writeunlock(struct smb_request *req) connection_struct *conn = req->conn; ssize_t nwritten = -1; size_t numtowrite; - SMB_OFF_T startpos; + off_t startpos; const char *data; NTSTATUS status = NT_STATUS_OK; files_struct *fsp; @@ -4249,8 +4368,8 @@ void reply_writeunlock(struct smb_request *req) SSVAL(req->outbuf,smb_vwv0,nwritten); - DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n", - fsp->fnum, (int)numtowrite, (int)nwritten)); + DEBUG(3, ("writeunlock %s num=%d wrote=%d\n", + fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten)); strict_unlock: if (numtowrite && !fsp->print_file) { @@ -4273,7 +4392,7 @@ void reply_write(struct smb_request *req) connection_struct *conn = req->conn; size_t numtowrite; ssize_t nwritten = -1; - SMB_OFF_T startpos; + off_t startpos; const char *data; files_struct *fsp; struct lock_struct lock; @@ -4334,12 +4453,12 @@ void reply_write(struct smb_request *req) /* * This is actually an allocate call, and set EOF. JRA. */ - nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos); + nwritten = vfs_allocate_file_space(fsp, (off_t)startpos); if (nwritten < 0) { reply_nterror(req, NT_STATUS_DISK_FULL); goto strict_unlock; } - nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos); + nwritten = vfs_set_filelen(fsp, (off_t)startpos); if (nwritten < 0) { reply_nterror(req, NT_STATUS_DISK_FULL); goto strict_unlock; @@ -4376,7 +4495,7 @@ void reply_write(struct smb_request *req) SSVAL(req->outbuf,smb_err,ERRdiskfull); } - DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten)); + DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten)); strict_unlock: if (!fsp->print_file) { @@ -4402,8 +4521,11 @@ bool is_valid_writeX_buffer(struct smbd_server_connection *sconn, connection_struct *conn = NULL; unsigned int doff = 0; size_t len = smb_len_large(inbuf); + struct smbXsrv_tcon *tcon; + NTSTATUS status; + NTTIME now = 0; - if (is_encrypted_packet(inbuf)) { + if (is_encrypted_packet(sconn, inbuf)) { /* Can't do this on encrypted * connections. */ return false; @@ -4420,11 +4542,14 @@ bool is_valid_writeX_buffer(struct smbd_server_connection *sconn, return false; } - conn = conn_find(sconn, SVAL(inbuf, smb_tid)); - if (conn == NULL) { + status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid), + now, &tcon); + if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("is_valid_writeX_buffer: bad tid\n")); return false; } + conn = tcon->compat; + if (IS_IPC(conn)) { DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n")); return false; @@ -4482,13 +4607,13 @@ void reply_write_and_X(struct smb_request *req) connection_struct *conn = req->conn; files_struct *fsp; struct lock_struct lock; - SMB_OFF_T startpos; + off_t startpos; size_t numtowrite; bool write_through; ssize_t nwritten; unsigned int smb_doff; unsigned int smblen; - char *data; + const char *data; NTSTATUS status; int saved_errno = 0; @@ -4496,8 +4621,7 @@ void reply_write_and_X(struct smb_request *req) if ((req->wct != 12) && (req->wct != 14)) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBwriteX); - return; + goto out; } numtowrite = SVAL(req->vwv+10, 0); @@ -4514,20 +4638,17 @@ void reply_write_and_X(struct smb_request *req) /* Can't do a recvfile write on IPC$ */ if (IS_IPC(conn)) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBwriteX); - return; + goto out; } if (numtowrite != req->unread_bytes) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBwriteX); - return; + goto out; } } else { if (smb_doff > smblen || smb_doff + numtowrite < numtowrite || smb_doff + numtowrite > smblen) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBwriteX); - return; + goto out; } } @@ -4535,12 +4656,10 @@ void reply_write_and_X(struct smb_request *req) if (IS_IPC(conn)) { if (req->unread_bytes) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBwriteX); - return; + goto out; } reply_pipe_write_and_X(req); - END_PROFILE(SMBwriteX); - return; + goto out; } fsp = file_fsp(req, SVAL(req->vwv+2, 0)); @@ -4548,41 +4667,22 @@ void reply_write_and_X(struct smb_request *req) write_through = BITSETW(req->vwv+7,0); if (!check_fsp(conn, req, fsp)) { - END_PROFILE(SMBwriteX); - return; + goto out; } if (!CHECK_WRITE(fsp)) { reply_nterror(req, NT_STATUS_ACCESS_DENIED); - END_PROFILE(SMBwriteX); - return; + goto out; } data = smb_base(req->inbuf) + smb_doff; if(req->wct == 14) { -#ifdef LARGE_SMB_OFF_T /* * This is a large offset (64 bit) write. */ - startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32); - -#else /* !LARGE_SMB_OFF_T */ - - /* - * Ensure we haven't been sent a >32 bit offset. - */ - - if(IVAL(req->vwv+12, 0) != 0) { - DEBUG(0,("reply_write_and_X - large offset (%x << 32) " - "used and we don't support 64 bit offsets.\n", - (unsigned int)IVAL(req->vwv+12, 0) )); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - END_PROFILE(SMBwriteX); - return; - } + startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32); -#endif /* LARGE_SMB_OFF_T */ } /* X/Open SMB protocol says that, unlike SMBwrite @@ -4639,11 +4739,13 @@ void reply_write_and_X(struct smb_request *req) } reply_outbuf(req, 6, 0); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ SSVAL(req->outbuf,smb_vwv2,nwritten); SSVAL(req->outbuf,smb_vwv4,nwritten>>16); - DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n", - fsp->fnum, (int)numtowrite, (int)nwritten)); + DEBUG(3,("writeX %s num=%d wrote=%d\n", + fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten)); status = sync_file(conn, fsp, write_through); if (!NT_STATUS_IS_OK(status)) { @@ -4654,10 +4756,18 @@ void reply_write_and_X(struct smb_request *req) } END_PROFILE(SMBwriteX); - chain_reply(req); return; out: + if (req->unread_bytes) { + /* writeX failed. drain socket. */ + if (drain_socket(req->sconn->sock, req->unread_bytes) != + req->unread_bytes) { + smb_panic("failed to drain pending bytes"); + } + req->unread_bytes = 0; + } + END_PROFILE(SMBwriteX); return; } @@ -4669,8 +4779,8 @@ out: void reply_lseek(struct smb_request *req) { connection_struct *conn = req->conn; - SMB_OFF_T startpos; - SMB_OFF_T res= -1; + off_t startpos; + off_t res= -1; int mode,umode; files_struct *fsp; @@ -4692,7 +4802,7 @@ void reply_lseek(struct smb_request *req) mode = SVAL(req->vwv+1, 0) & 3; /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */ - startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0); + startpos = (off_t)IVALS(req->vwv+2, 0); switch (mode) { case 0: @@ -4715,7 +4825,7 @@ void reply_lseek(struct smb_request *req) if (umode == SEEK_END) { if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) { if(errno == EINVAL) { - SMB_OFF_T current_pos = startpos; + off_t current_pos = startpos; if(fsp_stat(fsp) == -1) { reply_nterror(req, @@ -4742,8 +4852,8 @@ void reply_lseek(struct smb_request *req) reply_outbuf(req, 2, 0); SIVAL(req->outbuf,smb_vwv0,res); - DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n", - fsp->fnum, (double)startpos, (double)res, mode)); + DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n", + fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode)); END_PROFILE(SMBlseek); return; @@ -4812,9 +4922,12 @@ void reply_exit(struct smb_request *req) return; } -/**************************************************************************** - Reply to a close - has to deal with closing a directory opened by NT SMB's. -****************************************************************************/ +struct reply_close_state { + files_struct *fsp; + struct smb_request *smbreq; +}; + +static void do_smb1_close(struct tevent_req *req); void reply_close(struct smb_request *req) { @@ -4841,21 +4954,13 @@ void reply_close(struct smb_request *req) return; } - if(fsp->is_directory) { - /* - * Special case - close NT SMB directory handle. - */ - DEBUG(3,("close directory fnum=%d\n", fsp->fnum)); - status = close_file(req, fsp, NORMAL_CLOSE); - } else { - time_t t; - /* - * Close ordinary file. - */ + DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n", + fsp->is_directory ? "directory" : "file", + fsp->fh->fd, fsp_fnum_dbg(fsp), + conn->num_files_open)); - DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n", - fsp->fh->fd, fsp->fnum, - conn->num_files_open)); + if (!fsp->is_directory) { + time_t t; /* * Take care of any time sent in the close. @@ -4863,16 +4968,49 @@ void reply_close(struct smb_request *req) t = srv_make_unix_date3(req->vwv+1); set_close_write_time(fsp, convert_time_t_to_timespec(t)); + } + + if (fsp->num_aio_requests != 0) { + + struct reply_close_state *state; + + DEBUG(10, ("closing with aio %u requests pending\n", + fsp->num_aio_requests)); /* - * close_file() returns the unix errno if an error - * was detected on close - normally this is due to - * a disk full error. If not then it was probably an I/O error. + * We depend on the aio_extra destructor to take care of this + * close request once fsp->num_aio_request drops to 0. */ - status = close_file(req, fsp, NORMAL_CLOSE); - } + fsp->deferred_close = tevent_wait_send( + fsp, fsp->conn->sconn->ev_ctx); + if (fsp->deferred_close == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + state = talloc(fsp, struct reply_close_state); + if (state == NULL) { + TALLOC_FREE(fsp->deferred_close); + status = NT_STATUS_NO_MEMORY; + goto done; + } + state->fsp = fsp; + state->smbreq = talloc_move(fsp, &req); + tevent_req_set_callback(fsp->deferred_close, do_smb1_close, + state); + END_PROFILE(SMBclose); + return; + } + /* + * close_file() returns the unix errno if an error was detected on + * close - normally this is due to a disk full error. If not then it + * was probably an I/O error. + */ + + status = close_file(req, fsp, NORMAL_CLOSE); +done: if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBclose); @@ -4884,6 +5022,49 @@ void reply_close(struct smb_request *req) return; } +static void do_smb1_close(struct tevent_req *req) +{ + struct reply_close_state *state = tevent_req_callback_data( + req, struct reply_close_state); + struct smb_request *smbreq; + NTSTATUS status; + int ret; + + ret = tevent_wait_recv(req); + TALLOC_FREE(req); + if (ret != 0) { + DEBUG(10, ("tevent_wait_recv returned %s\n", + strerror(ret))); + /* + * Continue anyway, this should never happen + */ + } + + /* + * fsp->smb2_close_request right now is a talloc grandchild of + * fsp. When we close_file(fsp), it would go with it. No chance to + * reply... + */ + smbreq = talloc_move(talloc_tos(), &state->smbreq); + + status = close_file(smbreq, state->fsp, NORMAL_CLOSE); + if (NT_STATUS_IS_OK(status)) { + reply_outbuf(smbreq, 0, 0); + } else { + reply_nterror(smbreq, status); + } + if (!srv_send_smb(smbreq->sconn, + (char *)smbreq->outbuf, + true, + smbreq->seqnum+1, + IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted, + NULL)) { + exit_server_cleanly("handle_aio_read_complete: srv_send_smb " + "failed."); + } + TALLOC_FREE(smbreq); +} + /**************************************************************************** Reply to a writeclose (Core+ protocol). ****************************************************************************/ @@ -4894,7 +5075,7 @@ void reply_writeclose(struct smb_request *req) size_t numtowrite; ssize_t nwritten = -1; NTSTATUS close_status = NT_STATUS_OK; - SMB_OFF_T startpos; + off_t startpos; const char *data; struct timespec mtime; files_struct *fsp; @@ -4952,8 +5133,8 @@ void reply_writeclose(struct smb_request *req) close_status = close_file(req, fsp, NORMAL_CLOSE); } - DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n", - fsp->fnum, (int)numtowrite, (int)nwritten, + DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n", + fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten, conn->num_files_open)); if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { @@ -5012,8 +5193,8 @@ void reply_lock(struct smb_request *req) count = (uint64_t)IVAL(req->vwv+1, 0); offset = (uint64_t)IVAL(req->vwv+3, 0); - DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n", - fsp->fh->fd, fsp->fnum, (double)offset, (double)count)); + DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n", + fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count)); br_lck = do_lock(req->sconn->msg_ctx, fsp, @@ -5083,8 +5264,8 @@ void reply_unlock(struct smb_request *req) return; } - DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n", - fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) ); + DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n", + fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) ); reply_outbuf(req, 0, 0); @@ -5102,21 +5283,41 @@ void reply_unlock(struct smb_request *req) void reply_tdis(struct smb_request *req) { + NTSTATUS status; connection_struct *conn = req->conn; + struct smbXsrv_tcon *tcon; + START_PROFILE(SMBtdis); if (!conn) { DEBUG(4,("Invalid connection in tdis\n")); - reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED); + reply_force_doserror(req, ERRSRV, ERRinvnid); END_PROFILE(SMBtdis); return; } - conn->used = False; - - close_cnum(conn,req->vuid); + tcon = conn->tcon; req->conn = NULL; + /* + * TODO: cancel all outstanding requests on the tcon + */ + status = smbXsrv_tcon_disconnect(tcon, req->vuid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("reply_tdis: " + "smbXsrv_tcon_disconnect() failed: %s\n", + nt_errstr(status))); + /* + * If we hit this case, there is something completely + * wrong, so we better disconnect the transport connection. + */ + END_PROFILE(SMBtdis); + exit_server(__location__ ": smbXsrv_tcon_disconnect failed"); + return; + } + + TALLOC_FREE(tcon); + reply_outbuf(req, 0, 0); END_PROFILE(SMBtdis); return; @@ -5232,8 +5433,8 @@ void reply_printopen(struct smb_request *req) reply_outbuf(req, 1, 0); SSVAL(req->outbuf,smb_vwv0,fsp->fnum); - DEBUG(3,("openprint fd=%d fnum=%d\n", - fsp->fh->fd, fsp->fnum)); + DEBUG(3,("openprint fd=%d %s\n", + fsp->fh->fd, fsp_fnum_dbg(fsp))); END_PROFILE(SMBsplopen); return; @@ -5270,8 +5471,8 @@ void reply_printclose(struct smb_request *req) return; } - DEBUG(3,("printclose fd=%d fnum=%d\n", - fsp->fh->fd,fsp->fnum)); + DEBUG(3,("printclose fd=%d %s\n", + fsp->fh->fd, fsp_fnum_dbg(fsp))); status = close_file(req, fsp, NORMAL_CLOSE); @@ -5331,7 +5532,7 @@ void reply_printqueue(struct smb_request *req) TALLOC_CTX *mem_ctx = talloc_tos(); NTSTATUS status; WERROR werr; - const char *sharename = lp_servicename(SNUM(conn)); + const char *sharename = lp_servicename(mem_ctx, SNUM(conn)); struct rpc_pipe_client *cli = NULL; struct dcerpc_binding_handle *b = NULL; struct policy_handle handle; @@ -5347,7 +5548,7 @@ void reply_printqueue(struct smb_request *req) status = rpc_pipe_open_interface(conn, &ndr_table_spoolss.syntax_id, conn->session_info, - &conn->sconn->client_id, + conn->sconn->remote_address, conn->sconn->msg_ctx, &cli); if (!NT_STATUS_IS_OK(status)) { @@ -5503,13 +5704,13 @@ void reply_printwrite(struct smb_request *req) data = (const char *)req->buf + 3; - if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) { + if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) { reply_nterror(req, map_nt_error_from_unix(errno)); END_PROFILE(SMBsplwr); return; } - DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) ); + DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite)); END_PROFILE(SMBsplwr); return; @@ -5647,7 +5848,7 @@ void reply_rmdir(struct smb_request *req) &info); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -5664,7 +5865,7 @@ void reply_rmdir(struct smb_request *req) if (!set_delete_on_close(fsp, true, conn->session_info->security_token, - &conn->session_info->utok)) { + conn->session_info->unix_token)) { close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, NT_STATUS_ACCESS_DENIED); goto out; @@ -5826,9 +6027,9 @@ static void rename_open_files(connection_struct *conn, files_struct *fsp; bool did_rename = False; NTSTATUS status; - uint32_t new_name_hash; + uint32_t new_name_hash = 0; - for(fsp = file_find_di_first(conn->sconn, lck->id); fsp; + for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp; fsp = file_find_di_next(fsp)) { /* fsp_name is a relative path under the fsp. To change this for other sharepaths we need to manipulate relative paths. */ @@ -5840,8 +6041,8 @@ static void rename_open_files(connection_struct *conn, if (fsp->name_hash != orig_name_hash) { continue; } - DEBUG(10, ("rename_open_files: renaming file fnum %d " - "(file_id %s) from %s -> %s\n", fsp->fnum, + DEBUG(10, ("rename_open_files: renaming file %s " + "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp), smb_fname_str_dbg(smb_fname_dst))); @@ -5854,7 +6055,7 @@ static void rename_open_files(connection_struct *conn, if (!did_rename) { DEBUG(10, ("rename_open_files: no open files on file_id %s " - "for %s\n", file_id_string_tos(&lck->id), + "for %s\n", file_id_string_tos(&lck->data->id), smb_fname_str_dbg(smb_fname_dst))); } @@ -6180,8 +6381,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, status = NT_STATUS_ACCESS_DENIED; } - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, - NULL); + lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); /* * We have the file open ourselves, so not being able to get the @@ -6197,8 +6397,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name), smb_fname_str_dbg(smb_fname_dst))); - if (!fsp->is_directory && - !lp_posix_pathnames() && + if (!lp_posix_pathnames() && (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn)))) { /* We must set the archive bit on the newly @@ -6713,7 +6912,7 @@ void reply_mv(struct smb_request *req) attrs, False, src_has_wcard, dest_has_wcard, DELETE_ACCESS); if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -6746,7 +6945,7 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, bool target_is_directory) { struct smb_filename *smb_fname_dst_tmp = NULL; - SMB_OFF_T ret=-1; + off_t ret=-1; files_struct *fsp1,*fsp2; uint32 dosattrs; uint32 new_create_disposition; @@ -6891,7 +7090,7 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, goto out; } - if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) { + if (ret != (off_t)smb_fname_src->st.st_ex_size) { status = NT_STATUS_DISK_FULL; goto out; } @@ -7618,8 +7817,8 @@ NTSTATUS smbd_do_locking(struct smb_request *req, return status; } - DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n", - fsp->fnum, (unsigned int)type, num_locks, num_ulocks)); + DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n", + fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks)); return NT_STATUS_OK; } @@ -7687,8 +7886,8 @@ void reply_lockingX(struct smb_request *req) bool result; DEBUG(5,("reply_lockingX: oplock break reply (%u) from client " - "for fnum = %d\n", (unsigned int)oplocklevel, - fsp->fnum )); + "for %s\n", (unsigned int)oplocklevel, + fsp_fnum_dbg(fsp))); /* * Make sure we have granted an exclusive or batch oplock on @@ -7704,9 +7903,9 @@ void reply_lockingX(struct smb_request *req) message here - just ignore it. JRA. */ DEBUG(5,("reply_lockingX: Error : oplock break from " - "client for fnum = %d (oplock=%d) and no " + "client for %s (oplock=%d) and no " "oplock granted on this file (%s).\n", - fsp->fnum, fsp->oplock_type, + fsp_fnum_dbg(fsp), fsp->oplock_type, fsp_str_dbg(fsp))); /* if this is a pure oplock break request then don't @@ -7841,12 +8040,13 @@ void reply_lockingX(struct smb_request *req) } reply_outbuf(req, 2, 0); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ - DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n", - fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks)); + DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n", + fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks)); END_PROFILE(SMBlockingX); - chain_reply(req); } #undef DBGC_CLASS @@ -7931,15 +8131,20 @@ void reply_setattrE(struct smb_request *req) goto out; } + if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) { + reply_nterror(req, NT_STATUS_ACCESS_DENIED); + goto out; + } + status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u " + DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u " " createtime=%u\n", - fsp->fnum, + fsp_fnum_dbg(fsp), (unsigned int)ft.atime.tv_sec, (unsigned int)ft.mtime.tv_sec, (unsigned int)ft.create_time.tv_sec @@ -8042,7 +8247,7 @@ void reply_getattrE(struct smb_request *req) } SSVAL(req->outbuf,smb_vwv10, mode); - DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum)); + DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp))); END_PROFILE(SMBgetattrE); return; |