Ignore:
Timestamp:
Nov 27, 2012, 4:43:17 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: updated trunk to 3.6.0

Location:
trunk/server
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/server

  • trunk/server/source3/smbd/smb2_create.c

    r480 r745  
    44
    55   Copyright (C) Stefan Metzmacher 2009
     6   Copyright (C) Jeremy Allison 2010
    67
    78   This program is free software; you can redistribute it and/or modify
     
    2021
    2122#include "includes.h"
     23#include "printing.h"
     24#include "smbd/smbd.h"
    2225#include "smbd/globals.h"
    2326#include "../libcli/smb/smb_common.h"
     27#include "../librpc/gen_ndr/ndr_security.h"
     28#include "../lib/util/tevent_ntstatus.h"
     29
     30int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
     31{
     32        switch(in_oplock_level) {
     33        case SMB2_OPLOCK_LEVEL_NONE:
     34                return NO_OPLOCK;
     35        case SMB2_OPLOCK_LEVEL_II:
     36                return LEVEL_II_OPLOCK;
     37        case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
     38                return EXCLUSIVE_OPLOCK;
     39        case SMB2_OPLOCK_LEVEL_BATCH:
     40                return BATCH_OPLOCK;
     41        case SMB2_OPLOCK_LEVEL_LEASE:
     42                DEBUG(2,("map_smb2_oplock_levels_to_samba: "
     43                        "LEASE_OPLOCK_REQUESTED\n"));
     44                return NO_OPLOCK;
     45        default:
     46                DEBUG(2,("map_smb2_oplock_levels_to_samba: "
     47                        "unknown level %u\n",
     48                        (unsigned int)in_oplock_level));
     49                return NO_OPLOCK;
     50        }
     51}
     52
     53static uint8_t map_samba_oplock_levels_to_smb2(int oplock_type)
     54{
     55        if (BATCH_OPLOCK_TYPE(oplock_type)) {
     56                return SMB2_OPLOCK_LEVEL_BATCH;
     57        } else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type)) {
     58                return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
     59        } else if (oplock_type == LEVEL_II_OPLOCK) {
     60                /*
     61                 * Don't use LEVEL_II_OPLOCK_TYPE here as
     62                 * this also includes FAKE_LEVEL_II_OPLOCKs
     63                 * which are internal only.
     64                 */
     65                return SMB2_OPLOCK_LEVEL_II;
     66        } else {
     67                return SMB2_OPLOCK_LEVEL_NONE;
     68        }
     69}
    2470
    2571static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
     
    4692                        uint64_t *out_end_of_file,
    4793                        uint32_t *out_file_attributes,
     94                        uint64_t *out_file_id_persistent,
    4895                        uint64_t *out_file_id_volatile,
    4996                        struct smb2_create_blobs *out_context_blobs);
    5097
    51 static void smbd_smb2_request_create_done(struct tevent_req *subreq);
    52 NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *req)
     98static void smbd_smb2_request_create_done(struct tevent_req *tsubreq);
     99NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
    53100{
    54101        const uint8_t *inbody;
    55         int i = req->current_idx;
     102        int i = smb2req->current_idx;
    56103        size_t expected_body_size = 0x39;
    57104        size_t body_size;
     
    79126        NTSTATUS status;
    80127        bool ok;
    81         struct tevent_req *subreq;
    82 
    83         if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
    84                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
    85         }
    86 
    87         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
     128        struct tevent_req *tsubreq;
     129
     130        if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
     131                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
     132        }
     133
     134        inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
    88135
    89136        body_size = SVAL(inbody, 0x00);
    90137        if (body_size != expected_body_size) {
    91                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
     138                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
    92139        }
    93140
     
    118165                name_offset = 0;
    119166        } else if (in_name_offset < dyn_offset) {
    120                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
     167                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
    121168        } else {
    122169                name_offset = in_name_offset - dyn_offset;
    123170        }
    124171
    125         if (name_offset > req->in.vector[i+2].iov_len) {
    126                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
    127         }
    128 
    129         name_available_length = req->in.vector[i+2].iov_len - name_offset;
     172        if (name_offset > smb2req->in.vector[i+2].iov_len) {
     173                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
     174        }
     175
     176        name_available_length = smb2req->in.vector[i+2].iov_len - name_offset;
    130177
    131178        if (in_name_length > name_available_length) {
    132                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
    133         }
    134 
    135         in_name_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base +
     179                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
     180        }
     181
     182        in_name_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base +
    136183                              name_offset;
    137184        in_name_buffer.length = in_name_length;
     
    141188                context_offset = 0;
    142189        } else if (in_context_offset < dyn_offset) {
    143                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
     190                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
    144191        } else {
    145192                context_offset = in_context_offset - dyn_offset;
    146193        }
    147194
    148         if (context_offset > req->in.vector[i+2].iov_len) {
    149                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
    150         }
    151 
    152         context_available_length = req->in.vector[i+2].iov_len - context_offset;
     195        if (context_offset > smb2req->in.vector[i+2].iov_len) {
     196                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
     197        }
     198
     199        context_available_length = smb2req->in.vector[i+2].iov_len - context_offset;
    153200
    154201        if (in_context_length > context_available_length) {
    155                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
    156         }
    157 
    158         in_context_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base +
     202                return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
     203        }
     204
     205        in_context_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base +
    159206                                  context_offset;
    160207        in_context_buffer.length = in_context_length;
     
    164211         */
    165212
    166         ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
     213        ok = convert_string_talloc(smb2req, CH_UTF16, CH_UNIX,
    167214                                   in_name_buffer.data,
    168215                                   in_name_buffer.length,
     
    170217                                   &in_name_string_size, false);
    171218        if (!ok) {
    172                 return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
     219                return smbd_smb2_request_error(smb2req, NT_STATUS_ILLEGAL_CHARACTER);
    173220        }
    174221
    175222        ZERO_STRUCT(in_context_blobs);
    176         status = smb2_create_blob_parse(req, in_context_buffer, &in_context_blobs);
     223        status = smb2_create_blob_parse(smb2req, in_context_buffer, &in_context_blobs);
    177224        if (!NT_STATUS_IS_OK(status)) {
    178                 return smbd_smb2_request_error(req, status);
    179         }
    180 
    181         subreq = smbd_smb2_create_send(req,
    182                                        req->sconn->smb2.event_ctx,
    183                                        req,
     225                return smbd_smb2_request_error(smb2req, status);
     226        }
     227
     228        tsubreq = smbd_smb2_create_send(smb2req,
     229                                       smb2req->sconn->smb2.event_ctx,
     230                                       smb2req,
    184231                                       in_oplock_level,
    185232                                       in_impersonation_level,
     
    191238                                       in_name_string,
    192239                                       in_context_blobs);
    193         if (subreq == NULL) {
    194                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
    195         }
    196         tevent_req_set_callback(subreq, smbd_smb2_request_create_done, req);
    197 
    198         return smbd_smb2_request_pending_queue(req, subreq);
    199 }
    200 
    201 static void smbd_smb2_request_create_done(struct tevent_req *subreq)
    202 {
    203         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
     240        if (tsubreq == NULL) {
     241                smb2req->subreq = NULL;
     242                return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
     243        }
     244        tevent_req_set_callback(tsubreq, smbd_smb2_request_create_done, smb2req);
     245
     246        return smbd_smb2_request_pending_queue(smb2req, tsubreq);
     247}
     248
     249static uint64_t get_mid_from_smb2req(struct smbd_smb2_request *smb2req)
     250{
     251        uint8_t *reqhdr = (uint8_t *)smb2req->out.vector[smb2req->current_idx].iov_base;
     252        return BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
     253}
     254
     255static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
     256{
     257        struct smbd_smb2_request *smb2req = tevent_req_callback_data(tsubreq,
    204258                                        struct smbd_smb2_request);
    205         int i = req->current_idx;
     259        int i = smb2req->current_idx;
    206260        uint8_t *outhdr;
    207261        DATA_BLOB outbody;
     
    216270        uint64_t out_end_of_file = 0;
    217271        uint32_t out_file_attributes = 0;
     272        uint64_t out_file_id_persistent = 0;
    218273        uint64_t out_file_id_volatile = 0;
    219274        struct smb2_create_blobs out_context_blobs;
     
    223278        NTSTATUS error; /* transport error */
    224279
    225         status = smbd_smb2_create_recv(subreq,
    226                                        req,
     280        if (smb2req->cancelled) {
     281                uint64_t mid = get_mid_from_smb2req(smb2req);
     282                DEBUG(10,("smbd_smb2_request_create_done: cancelled mid %llu\n",
     283                        (unsigned long long)mid ));
     284                error = smbd_smb2_request_error(smb2req, NT_STATUS_CANCELLED);
     285                if (!NT_STATUS_IS_OK(error)) {
     286                        smbd_server_connection_terminate(smb2req->sconn,
     287                                nt_errstr(error));
     288                        return;
     289                }
     290                return;
     291        }
     292
     293        status = smbd_smb2_create_recv(tsubreq,
     294                                       smb2req,
    227295                                       &out_oplock_level,
    228296                                       &out_create_action,
     
    234302                                       &out_end_of_file,
    235303                                       &out_file_attributes,
     304                                       &out_file_id_persistent,
    236305                                       &out_file_id_volatile,
    237306                                       &out_context_blobs);
    238         TALLOC_FREE(subreq);
    239307        if (!NT_STATUS_IS_OK(status)) {
    240                 error = smbd_smb2_request_error(req, status);
     308                error = smbd_smb2_request_error(smb2req, status);
    241309                if (!NT_STATUS_IS_OK(error)) {
    242                         smbd_server_connection_terminate(req->sconn,
     310                        smbd_server_connection_terminate(smb2req->sconn,
    243311                                                         nt_errstr(error));
    244312                        return;
     
    247315        }
    248316
    249         status = smb2_create_blob_push(req, &out_context_buffer, out_context_blobs);
     317        status = smb2_create_blob_push(smb2req, &out_context_buffer, out_context_blobs);
    250318        if (!NT_STATUS_IS_OK(status)) {
    251                 error = smbd_smb2_request_error(req, status);
     319                error = smbd_smb2_request_error(smb2req, status);
    252320                if (!NT_STATUS_IS_OK(error)) {
    253                         smbd_server_connection_terminate(req->sconn,
     321                        smbd_server_connection_terminate(smb2req->sconn,
    254322                                                         nt_errstr(error));
    255323                        return;
     
    262330        }
    263331
    264         outhdr = (uint8_t *)req->out.vector[i].iov_base;
    265 
    266         outbody = data_blob_talloc(req->out.vector, NULL, 0x58);
     332        outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
     333
     334        outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x58);
    267335        if (outbody.data == NULL) {
    268                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     336                error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
    269337                if (!NT_STATUS_IS_OK(error)) {
    270                         smbd_server_connection_terminate(req->sconn,
     338                        smbd_server_connection_terminate(smb2req->sconn,
    271339                                                         nt_errstr(error));
    272340                        return;
     
    296364              out_file_attributes);             /* file attributes */
    297365        SIVAL(outbody.data, 0x3C, 0);           /* reserved */
    298         SBVAL(outbody.data, 0x40, 0);           /* file id (persistent) */
     366        SBVAL(outbody.data, 0x40,
     367              out_file_id_persistent);          /* file id (persistent) */
    299368        SBVAL(outbody.data, 0x48,
    300369              out_file_id_volatile);            /* file id (volatile) */
     
    306375        outdyn = out_context_buffer;
    307376
    308         error = smbd_smb2_request_done(req, outbody, &outdyn);
     377        error = smbd_smb2_request_done(smb2req, outbody, &outdyn);
    309378        if (!NT_STATUS_IS_OK(error)) {
    310                 smbd_server_connection_terminate(req->sconn,
     379                smbd_server_connection_terminate(smb2req->sconn,
    311380                                                 nt_errstr(error));
    312381                return;
     
    316385struct smbd_smb2_create_state {
    317386        struct smbd_smb2_request *smb2req;
     387        struct smb_request *smb1req;
     388        struct timed_event *te;
     389        struct tevent_immediate *im;
     390        struct timeval request_time;
     391        struct file_id id;
     392        DATA_BLOB private_data;
    318393        uint8_t out_oplock_level;
    319394        uint32_t out_create_action;
     
    325400        uint64_t out_end_of_file;
    326401        uint32_t out_file_attributes;
     402        uint64_t out_file_id_persistent;
    327403        uint64_t out_file_id_volatile;
    328404        struct smb2_create_blobs out_context_blobs;
     
    342418                        struct smb2_create_blobs in_context_blobs)
    343419{
    344         struct tevent_req *req;
    345         struct smbd_smb2_create_state *state;
     420        struct tevent_req *req = NULL;
     421        struct smbd_smb2_create_state *state = NULL;
    346422        NTSTATUS status;
    347         struct smb_request *smbreq;
    348         files_struct *result;
     423        struct smb_request *smb1req = NULL;
     424        files_struct *result = NULL;
    349425        int info;
    350426        struct timespec write_time_ts;
    351427        struct smb2_create_blobs out_context_blobs;
     428        int requested_oplock_level;
    352429
    353430        ZERO_STRUCT(out_context_blobs);
    354431
    355         req = tevent_req_create(mem_ctx, &state,
     432        if(lp_fake_oplocks(SNUM(smb2req->tcon->compat_conn))) {
     433                requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
     434        } else {
     435                requested_oplock_level = in_oplock_level;
     436        }
     437
     438
     439        if (!smb2req->async) {
     440                /* New create call. */
     441                req = tevent_req_create(mem_ctx, &state,
    356442                                struct smbd_smb2_create_state);
    357         if (req == NULL) {
    358                 return NULL;
    359         }
    360         state->smb2req = smb2req;
    361 
    362         DEBUG(10,("smbd_smb2_create: name[%s]\n",
    363                   in_name));
    364 
    365         smbreq = smbd_smb2_fake_smb_request(smb2req);
    366         if (tevent_req_nomem(smbreq, req)) {
    367                 return tevent_req_post(req, ev);
    368         }
    369 
    370         if (IS_IPC(smbreq->conn)) {
     443                if (req == NULL) {
     444                        return NULL;
     445                }
     446                state->smb2req = smb2req;
     447                smb2req->subreq = req; /* So we can find this when going async. */
     448
     449                smb1req = smbd_smb2_fake_smb_request(smb2req);
     450                if (tevent_req_nomem(smb1req, req)) {
     451                        return tevent_req_post(req, ev);
     452                }
     453                state->smb1req = smb1req;
     454                DEBUG(10,("smbd_smb2_create: name[%s]\n",
     455                        in_name));
     456        } else {
     457                /* Re-entrant create call. */
     458                req = smb2req->subreq;
     459                state = tevent_req_data(req,
     460                                struct smbd_smb2_create_state);
     461                smb1req = state->smb1req;
     462                DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
     463                        in_name ));
     464        }
     465
     466        if (IS_IPC(smb1req->conn)) {
    371467                const char *pipe_name = in_name;
    372468
     
    381477                }
    382478
    383                 status = open_np_file(smbreq, pipe_name, &result);
     479                status = open_np_file(smb1req, pipe_name, &result);
    384480                if (!NT_STATUS_IS_OK(status)) {
    385481                        tevent_req_nterror(req, status);
     
    387483                }
    388484                info = FILE_WAS_OPENED;
    389         } else if (CAN_PRINT(smbreq->conn)) {
    390                 status = file_new(smbreq, smbreq->conn, &result);
     485        } else if (CAN_PRINT(smb1req->conn)) {
     486                status = file_new(smb1req, smb1req->conn, &result);
    391487                if(!NT_STATUS_IS_OK(status)) {
    392488                        tevent_req_nterror(req, status);
     
    394490                }
    395491
    396                 status = print_fsp_open(smbreq,
    397                                         smbreq->conn,
    398                                         in_name,
    399                                         smbreq->vuid,
    400                                         result);
     492                status = print_spool_open(result, in_name,
     493                                          smb1req->vuid);
    401494                if (!NT_STATUS_IS_OK(status)) {
    402                         file_free(smbreq, result);
     495                        file_free(smb1req, result);
    403496                        tevent_req_nterror(req, status);
    404497                        return tevent_req_post(req, ev);
     
    488581
    489582                        ndr_err = ndr_pull_struct_blob(&secd->data,
    490                                 sec_desc, NULL, sec_desc,
     583                                sec_desc, sec_desc,
    491584                                (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
    492585                        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     
    582675                in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
    583676
    584                 /* convert '\\' into '/' */
    585                 status = check_path_syntax(fname);
    586                 if (!NT_STATUS_IS_OK(status)) {
    587                         tevent_req_nterror(req, status);
    588                         return tevent_req_post(req, ev);
     677                /*
     678                 * For a DFS path the function parse_dfs_path()
     679                 * will do the path processing.
     680                 */
     681
     682                if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) {
     683                        /* convert '\\' into '/' */
     684                        status = check_path_syntax(fname);
     685                        if (!NT_STATUS_IS_OK(status)) {
     686                                tevent_req_nterror(req, status);
     687                                return tevent_req_post(req, ev);
     688                        }
    589689                }
    590690
    591691                status = filename_convert(req,
    592                                           smbreq->conn,
    593                                           smbreq->flags2 & FLAGS2_DFS_PATHNAMES,
     692                                          smb1req->conn,
     693                                          smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
    594694                                          fname,
    595695                                          0,
     
    601701                }
    602702
    603                 status = SMB_VFS_CREATE_FILE(smbreq->conn,
    604                                              smbreq,
     703                in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
     704
     705                status = SMB_VFS_CREATE_FILE(smb1req->conn,
     706                                             smb1req,
    605707                                             0, /* root_dir_fid */
    606708                                             smb_fname,
     
    610712                                             in_create_options,
    611713                                             in_file_attributes,
    612                                              0, /* oplock_request */
     714                                             map_smb2_oplock_levels_to_samba(requested_oplock_level),
    613715                                             allocation_size,
     716                                             0, /* private_flags */
    614717                                             sec_desc,
    615718                                             ea_list,
     
    617720                                             &info);
    618721                if (!NT_STATUS_IS_OK(status)) {
     722                        if (open_was_deferred(smb1req->mid)) {
     723                                return req;
     724                        }
    619725                        tevent_req_nterror(req, status);
    620726                        return tevent_req_post(req, ev);
     
    631737                                DATA_BLOB blob = data_blob_const(p, sizeof(p));
    632738
    633                                 status = smbd_check_open_rights(smbreq->conn,
     739                                status = smbd_calculate_access_mask(smb1req->conn,
    634740                                                        result->fsp_name,
     741                                                        /*
     742                                                         * at this stage
     743                                                         * it exists
     744                                                         */
     745                                                        true,
    635746                                                        SEC_FLAG_MAXIMUM_ALLOWED,
    636747                                                        &max_access_granted);
     
    675786        }
    676787
    677         smb2req->compat_chain_fsp = smbreq->chain_fsp;
    678 
    679         state->out_oplock_level = 0;
     788        smb2req->compat_chain_fsp = smb1req->chain_fsp;
     789
     790        if(lp_fake_oplocks(SNUM(smb2req->tcon->compat_conn))) {
     791                state->out_oplock_level = in_oplock_level;
     792        } else {
     793                state->out_oplock_level = map_samba_oplock_levels_to_smb2(result->oplock_type);
     794        }
     795
    680796        if ((in_create_disposition == FILE_SUPERSEDE)
    681797            && (info == FILE_WAS_OVERWRITTEN)) {
     
    689805           write time. JRA. */
    690806        ZERO_STRUCT(write_time_ts);
    691         get_file_infos(result->file_id, NULL, &write_time_ts);
     807        get_file_infos(result->file_id, 0, NULL, &write_time_ts);
    692808        if (!null_timespec(write_time_ts)) {
    693809                update_stat_ex_mtime(&result->fsp_name->st, write_time_ts);
     
    695811
    696812        unix_timespec_to_nt_time(&state->out_creation_time,
    697                         get_create_timespec(smbreq->conn, result,
     813                        get_create_timespec(smb1req->conn, result,
    698814                                        result->fsp_name));
    699815        unix_timespec_to_nt_time(&state->out_last_access_time,
     
    702818                        result->fsp_name->st.st_ex_mtime);
    703819        unix_timespec_to_nt_time(&state->out_change_time,
    704                         get_change_timespec(smbreq->conn, result,
     820                        get_change_timespec(smb1req->conn, result,
    705821                                        result->fsp_name));
    706822        state->out_allocation_size =
     
    711827                state->out_file_attributes = FILE_ATTRIBUTE_NORMAL;
    712828        }
     829        state->out_file_id_persistent = result->fnum;
    713830        state->out_file_id_volatile = result->fnum;
    714831        state->out_context_blobs = out_context_blobs;
     
    729846                        uint64_t *out_end_of_file,
    730847                        uint32_t *out_file_attributes,
     848                        uint64_t *out_file_id_persistent,
    731849                        uint64_t *out_file_id_volatile,
    732850                        struct smb2_create_blobs *out_context_blobs)
     
    750868        *out_end_of_file        = state->out_end_of_file;
    751869        *out_file_attributes    = state->out_file_attributes;
     870        *out_file_id_persistent = state->out_file_id_persistent;
    752871        *out_file_id_volatile   = state->out_file_id_volatile;
    753872        *out_context_blobs      = state->out_context_blobs;
     
    758877        return NT_STATUS_OK;
    759878}
     879
     880/*********************************************************
     881 Code for dealing with deferred opens.
     882*********************************************************/
     883
     884bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req,
     885                        struct timeval *p_request_time,
     886                        void **pp_state)
     887{
     888        struct smbd_smb2_create_state *state = NULL;
     889        struct tevent_req *req = NULL;
     890
     891        if (!smb2req) {
     892                return false;
     893        }
     894        if (!smb2req->async) {
     895                return false;
     896        }
     897        req = smb2req->subreq;
     898        if (!req) {
     899                return false;
     900        }
     901        state = tevent_req_data(req, struct smbd_smb2_create_state);
     902        if (!state) {
     903                return false;
     904        }
     905        if (p_request_time) {
     906                *p_request_time = state->request_time;
     907        }
     908        if (pp_state) {
     909                *pp_state = (void *)state->private_data.data;
     910        }
     911        return true;
     912}
     913
     914/*********************************************************
     915 Re-process this call early - requested by message or
     916 close.
     917*********************************************************/
     918
     919static struct smbd_smb2_request *find_open_smb2req(
     920        struct smbd_server_connection *sconn, uint64_t mid)
     921{
     922        struct smbd_smb2_request *smb2req;
     923
     924        for (smb2req = sconn->smb2.requests; smb2req; smb2req = smb2req->next) {
     925                uint64_t message_id;
     926                if (smb2req->subreq == NULL) {
     927                        /* This message has been processed. */
     928                        continue;
     929                }
     930                if (!tevent_req_is_in_progress(smb2req->subreq)) {
     931                        /* This message has been processed. */
     932                        continue;
     933                }
     934                message_id = get_mid_from_smb2req(smb2req);
     935                if (message_id == mid) {
     936                        return smb2req;
     937                }
     938        }
     939        return NULL;
     940}
     941
     942bool open_was_deferred_smb2(struct smbd_server_connection *sconn, uint64_t mid)
     943{
     944        struct smbd_smb2_create_state *state = NULL;
     945        struct smbd_smb2_request *smb2req;
     946
     947        smb2req = find_open_smb2req(sconn, mid);
     948
     949        if (!smb2req) {
     950                DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n",
     951                        (unsigned long long)mid));
     952                return false;
     953        }
     954        if (!smb2req->subreq) {
     955                return false;
     956        }
     957        if (!tevent_req_is_in_progress(smb2req->subreq)) {
     958                return false;
     959        }
     960        state = tevent_req_data(smb2req->subreq,
     961                        struct smbd_smb2_create_state);
     962        if (!state) {
     963                return false;
     964        }
     965        /* It's not in progress if there's no timeout event. */
     966        if (!state->te) {
     967                return false;
     968        }
     969
     970        DEBUG(10,("open_was_deferred_smb2: mid = %llu\n",
     971                        (unsigned long long)mid));
     972
     973        return true;
     974}
     975
     976static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request *smb2req,
     977                                                        uint64_t mid)
     978{
     979        struct smbd_smb2_create_state *state = NULL;
     980
     981        if (!smb2req->subreq) {
     982                return;
     983        }
     984        if (!tevent_req_is_in_progress(smb2req->subreq)) {
     985                return;
     986        }
     987        state = tevent_req_data(smb2req->subreq,
     988                        struct smbd_smb2_create_state);
     989        if (!state) {
     990                return;
     991        }
     992
     993        DEBUG(10,("remove_deferred_open_message_smb2_internal: "
     994                "mid %llu\n",
     995                (unsigned long long)mid ));
     996
     997        /* Ensure we don't have any outstanding timer event. */
     998        TALLOC_FREE(state->te);
     999        /* Ensure we don't have any outstanding immediate event. */
     1000        TALLOC_FREE(state->im);
     1001}
     1002
     1003void remove_deferred_open_message_smb2(
     1004        struct smbd_server_connection *sconn, uint64_t mid)
     1005{
     1006        struct smbd_smb2_request *smb2req;
     1007
     1008        smb2req = find_open_smb2req(sconn, mid);
     1009
     1010        if (!smb2req) {
     1011                DEBUG(10,("remove_deferred_open_message_smb2: "
     1012                        "can't find mid %llu\n",
     1013                        (unsigned long long)mid ));
     1014                return;
     1015        }
     1016        remove_deferred_open_message_smb2_internal(smb2req, mid);
     1017}
     1018
     1019static void smbd_smb2_create_request_dispatch_immediate(struct tevent_context *ctx,
     1020                                        struct tevent_immediate *im,
     1021                                        void *private_data)
     1022{
     1023        struct smbd_smb2_request *smb2req = talloc_get_type_abort(private_data,
     1024                                        struct smbd_smb2_request);
     1025        struct smbd_server_connection *sconn = smb2req->sconn;
     1026        uint64_t mid = get_mid_from_smb2req(smb2req);
     1027        NTSTATUS status;
     1028
     1029        DEBUG(10,("smbd_smb2_create_request_dispatch_immediate: "
     1030                "re-dispatching mid %llu\n",
     1031                (unsigned long long)mid ));
     1032
     1033        status = smbd_smb2_request_dispatch(smb2req);
     1034        if (!NT_STATUS_IS_OK(status)) {
     1035                smbd_server_connection_terminate(sconn, nt_errstr(status));
     1036                return;
     1037        }
     1038}
     1039
     1040void schedule_deferred_open_message_smb2(
     1041        struct smbd_server_connection *sconn, uint64_t mid)
     1042{
     1043        struct smbd_smb2_create_state *state = NULL;
     1044        struct smbd_smb2_request *smb2req;
     1045
     1046        smb2req = find_open_smb2req(sconn, mid);
     1047
     1048        if (!smb2req) {
     1049                DEBUG(10,("schedule_deferred_open_message_smb2: "
     1050                        "can't find mid %llu\n",
     1051                        (unsigned long long)mid ));
     1052                return;
     1053        }
     1054        if (!smb2req->subreq) {
     1055                return;
     1056        }
     1057        if (!tevent_req_is_in_progress(smb2req->subreq)) {
     1058                return;
     1059        }
     1060        state = tevent_req_data(smb2req->subreq,
     1061                        struct smbd_smb2_create_state);
     1062        if (!state) {
     1063                return;
     1064        }
     1065
     1066        /* Ensure we don't have any outstanding timer event. */
     1067        TALLOC_FREE(state->te);
     1068        /* Ensure we don't have any outstanding immediate event. */
     1069        TALLOC_FREE(state->im);
     1070
     1071        /*
     1072         * This is subtle. We must null out the callback
     1073         * before resheduling, else the first call to
     1074         * tevent_req_nterror() causes the _receive()
     1075         * function to be called, this causing tevent_req_post()
     1076         * to crash.
     1077         */
     1078        tevent_req_set_callback(smb2req->subreq, NULL, NULL);
     1079
     1080        state->im = tevent_create_immediate(smb2req);
     1081        if (!state->im) {
     1082                smbd_server_connection_terminate(smb2req->sconn,
     1083                        nt_errstr(NT_STATUS_NO_MEMORY));
     1084        }
     1085
     1086        DEBUG(10,("schedule_deferred_open_message_smb2: "
     1087                "re-processing mid %llu\n",
     1088                (unsigned long long)mid ));
     1089
     1090        tevent_schedule_immediate(state->im,
     1091                        smb2req->sconn->smb2.event_ctx,
     1092                        smbd_smb2_create_request_dispatch_immediate,
     1093                        smb2req);
     1094}
     1095
     1096/*********************************************************
     1097 Re-process this call.
     1098*********************************************************/
     1099
     1100static void smb2_deferred_open_timer(struct event_context *ev,
     1101                                        struct timed_event *te,
     1102                                        struct timeval _tval,
     1103                                        void *private_data)
     1104{
     1105        NTSTATUS status;
     1106        struct smbd_smb2_create_state *state = NULL;
     1107        struct smbd_smb2_request *smb2req = talloc_get_type(private_data,
     1108                                                struct smbd_smb2_request);
     1109
     1110        DEBUG(10,("smb2_deferred_open_timer: [idx=%d], %s\n",
     1111                smb2req->current_idx,
     1112                tevent_req_default_print(smb2req->subreq, talloc_tos()) ));
     1113
     1114        state = tevent_req_data(smb2req->subreq,
     1115                        struct smbd_smb2_create_state);
     1116        if (!state) {
     1117                return;
     1118        }
     1119        /*
     1120         * Null this out, don't talloc_free. It will
     1121         * be talloc_free'd by the tevent library when
     1122         * this returns.
     1123         */
     1124        state->te = NULL;
     1125        /* Ensure we don't have any outstanding immediate event. */
     1126        TALLOC_FREE(state->im);
     1127
     1128        /*
     1129         * This is subtle. We must null out the callback
     1130         * before resheduling, else the first call to
     1131         * tevent_req_nterror() causes the _receive()
     1132         * function to be called, this causing tevent_req_post()
     1133         * to crash.
     1134         */
     1135        tevent_req_set_callback(smb2req->subreq, NULL, NULL);
     1136
     1137        status = smbd_smb2_request_dispatch(smb2req);
     1138
     1139        if (!NT_STATUS_IS_OK(status)) {
     1140                smbd_server_connection_terminate(smb2req->sconn,
     1141                                nt_errstr(status));
     1142        }
     1143}
     1144
     1145static bool smbd_smb2_create_cancel(struct tevent_req *req)
     1146{
     1147        struct smbd_smb2_request *smb2req = NULL;
     1148        struct smbd_smb2_create_state *state = tevent_req_data(req,
     1149                                struct smbd_smb2_create_state);
     1150        uint64_t mid;
     1151
     1152        if (!state) {
     1153                return false;
     1154        }
     1155
     1156        if (!state->smb2req) {
     1157                return false;
     1158        }
     1159
     1160        smb2req = state->smb2req;
     1161        mid = get_mid_from_smb2req(smb2req);
     1162
     1163        remove_deferred_open_entry(state->id, mid,
     1164                                   sconn_server_id(smb2req->sconn));
     1165        remove_deferred_open_message_smb2_internal(smb2req, mid);
     1166        smb2req->cancelled = true;
     1167
     1168        tevent_req_done(req);
     1169        return true;
     1170}
     1171
     1172bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
     1173                                struct timeval request_time,
     1174                                struct timeval timeout,
     1175                                struct file_id id,
     1176                                char *private_data,
     1177                                size_t priv_len)
     1178{
     1179        struct tevent_req *req = NULL;
     1180        struct smbd_smb2_create_state *state = NULL;
     1181        struct timeval end_time;
     1182
     1183        if (!smb2req) {
     1184                return false;
     1185        }
     1186        req = smb2req->subreq;
     1187        if (!req) {
     1188                return false;
     1189        }
     1190        state = tevent_req_data(req, struct smbd_smb2_create_state);
     1191        if (!state) {
     1192                return false;
     1193        }
     1194        state->id = id;
     1195        state->request_time = request_time;
     1196        state->private_data = data_blob_talloc(state, private_data,
     1197                                                priv_len);
     1198        if (!state->private_data.data) {
     1199                return false;
     1200        }
     1201
     1202#if 1
     1203        /* Boo - turns out this isn't what W2K8R2
     1204           does. It actually sends the STATUS_PENDING
     1205           message followed by the STATUS_SHARING_VIOLATION
     1206           message. Surely this means that all open
     1207           calls (even on directories) will potentially
     1208           fail in a chain.... ? And I've seen directory
     1209           opens as the start of a chain. JRA.
     1210
     1211           Update: 19th May 2010. Talking with Microsoft
     1212           engineers at the plugfest this is a bug in
     1213           Windows. Re-enable this code.
     1214        */
     1215        /*
     1216         * More subtlety. To match W2K8R2 don't
     1217         * send a "gone async" message if it's simply
     1218         * a STATUS_SHARING_VIOLATION (short) wait, not
     1219         * an oplock break wait. We do this by prematurely
     1220         * setting smb2req->async flag.
     1221         */
     1222        if (timeout.tv_sec < 2) {
     1223                DEBUG(10,("push_deferred_open_message_smb2: "
     1224                        "short timer wait (usec = %u). "
     1225                        "Don't send async message.\n",
     1226                        (unsigned int)timeout.tv_usec ));
     1227                smb2req->async = true;
     1228        }
     1229#endif
     1230
     1231        /* Re-schedule us to retry on timer expiry. */
     1232        end_time = timeval_sum(&request_time, &timeout);
     1233
     1234        DEBUG(10,("push_deferred_open_message_smb2: "
     1235                "timeout at %s\n",
     1236                timeval_string(talloc_tos(),
     1237                                &end_time,
     1238                                true) ));
     1239
     1240        state->te = event_add_timed(smb2req->sconn->smb2.event_ctx,
     1241                                state,
     1242                                end_time,
     1243                                smb2_deferred_open_timer,
     1244                                smb2req);
     1245        if (!state->te) {
     1246                return false;
     1247        }
     1248
     1249        /* allow this request to be canceled */
     1250        tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel);
     1251
     1252        return true;
     1253}
Note: See TracChangeset for help on using the changeset viewer.