/* send an oplock break request to a client */ NTSTATUS smbsrv_send_oplock_break(void *p, struct ntvfs_handle *ntvfs, uint8_t level) { struct smbsrv_tcon *tcon = talloc_get_type(p, struct smbsrv_tcon); struct smbsrv_request *req; req = smbsrv_init_request(tcon->smb_conn); NT_STATUS_HAVE_NO_MEMORY(req); smbsrv_setup_reply(req, 8, 0); SCVAL(req->out.hdr,HDR_COM,SMBlockingX); SSVAL(req->out.hdr,HDR_TID,tcon->tid); SSVAL(req->out.hdr,HDR_PID,0xFFFF); SSVAL(req->out.hdr,HDR_UID,0); SSVAL(req->out.hdr,HDR_MID,0xFFFF); SCVAL(req->out.hdr,HDR_FLG,0); SSVAL(req->out.hdr,HDR_FLG2,0); SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); SSVAL(req->out.vwv, VWV(1), 0); smbsrv_push_fnum(req->out.vwv, VWV(2), ntvfs); SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE); SCVAL(req->out.vwv, VWV(3)+1, level); SIVAL(req->out.vwv, VWV(4), 0); SSVAL(req->out.vwv, VWV(6), 0); SSVAL(req->out.vwv, VWV(7), 0); smbsrv_send_reply(req); return NT_STATUS_OK; }
/* send a continue request */ static void reply_trans_continue(struct smbsrv_request *req, uint8_t command, struct smb_trans2 *trans) { struct smbsrv_request *req2; struct smbsrv_trans_partial *tp; int count; /* make sure they don't flood us */ for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++; if (count > 100) { smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES); return; } tp = talloc(req, struct smbsrv_trans_partial); tp->req = req; tp->u.trans = trans; tp->command = command; DLIST_ADD(req->smb_conn->trans_partial, tp); talloc_set_destructor(tp, smbsrv_trans_partial_destructor); req2 = smbsrv_setup_secondary_request(req); /* send a 'please continue' reply */ smbsrv_setup_reply(req2, 0, 0); smbsrv_send_reply(req2); }
/* construct and send an error packet, then destroy the request auto-converts to DOS error format when appropriate */ void smbsrv_send_error(struct smbsrv_request *req, NTSTATUS status) { if (req->smb_conn->connection->event.fde == NULL) { /* the socket has been destroyed - no point trying to send an error! */ talloc_free(req); return; } smbsrv_setup_reply(req, 0, 0); /* error returns never have any data */ req_grow_data(req, 0); smbsrv_setup_error(req, status); smbsrv_send_reply(req); }
/* answer a reconstructed trans request */ static void reply_trans_send(struct ntvfs_request *ntvfs) { struct smbsrv_request *req; struct trans_op *op; struct smb_trans2 *trans; uint16_t params_left, data_left; uint8_t *params, *data; int i; SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op); trans = op->trans; /* if this function needs work to form the nttrans reply buffer, then call that now */ if (op->send_fn != NULL) { NTSTATUS status; status = op->send_fn(op); if (!NT_STATUS_IS_OK(status)) { smbsrv_send_error(req, status); return; } } params_left = trans->out.params.length; data_left = trans->out.data.length; params = trans->out.params.data; data = trans->out.data.data; smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0); if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { smbsrv_setup_error(req, req->ntvfs->async_states->status); } /* we need to divide up the reply into chunks that fit into the negotiated buffer size */ do { uint16_t this_data, this_param, max_bytes; unsigned int align1 = 1, align2 = (params_left ? 2 : 0); struct smbsrv_request *this_req; max_bytes = req_max_data(req) - (align1 + align2); this_param = params_left; if (this_param > max_bytes) { this_param = max_bytes; } max_bytes -= this_param; this_data = data_left; if (this_data > max_bytes) { this_data = max_bytes; } /* don't destroy unless this is the last chunk */ if (params_left - this_param != 0 || data_left - this_data != 0) { this_req = smbsrv_setup_secondary_request(req); } else { this_req = req; } req_grow_data(this_req, this_param + this_data + (align1 + align2)); SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length); SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length); SSVAL(this_req->out.vwv, VWV(2), 0); SSVAL(this_req->out.vwv, VWV(3), this_param); SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr)); SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data)); SSVAL(this_req->out.vwv, VWV(6), this_data); SSVAL(this_req->out.vwv, VWV(7), align1 + align2 + PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr)); SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data)); SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count); SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */ for (i=0;i<trans->out.setup_count;i++) { SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]); } memset(this_req->out.data, 0, align1); if (this_param != 0) { memcpy(this_req->out.data + align1, params, this_param); } memset(this_req->out.data+this_param+align1, 0, align2); if (this_data != 0) { memcpy(this_req->out.data+this_param+align1+align2, data, this_data); } params_left -= this_param; data_left -= this_data; params += this_param; data += this_data; smbsrv_send_reply(this_req); } while (params_left != 0 || data_left != 0); }