📄 trans2.c
字号:
/* make sure we got all the parameters */ if (trans->in.params.length < 12) { return NT_STATUS_FOOBAR; } search = talloc(op, union smb_search_next); NT_STATUS_HAVE_NO_MEMORY(search); search->t2fnext.in.handle = SVAL(trans->in.params.data, 0); search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2); level = SVAL(trans->in.params.data, 4); search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6); search->t2fnext.in.flags = SVAL(trans->in.params.data, 10); smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0); if (search->t2fnext.in.last_name == NULL) { return NT_STATUS_FOOBAR; } search->t2fnext.level = RAW_SEARCH_TRANS2; search->t2fnext.data_level = (enum smb_search_data_level)level; if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) { return NT_STATUS_INVALID_LEVEL; } if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) { TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, &search->t2fnext.in.num_names, &search->t2fnext.in.ea_names)); } /* setup the private state structure that the backend will give us in the callback */ state = talloc(op, struct find_state); NT_STATUS_HAVE_NO_MEMORY(state); state->op = op; state->search = search; state->data_level = search->t2fnext.data_level; state->last_entry_offset= 0; state->flags = search->t2fnext.in.flags; /* setup for just a header in the reply */ TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0)); op->op_info = state; op->send_fn = trans2_findnext_send; return ntvfs_search_next(req->ntvfs, search, state, find_callback);}/* backend for trans2 requests*/static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op){ struct smb_trans2 *trans = op->trans; NTSTATUS status; /* direct trans2 pass thru */ status = ntvfs_trans2(req->ntvfs, trans); if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) { return status; } /* must have at least one setup word */ if (trans->in.setup_count < 1) { return NT_STATUS_FOOBAR; } /* the trans2 command is in setup[0] */ switch (trans->in.setup[0]) { case TRANSACT2_FINDFIRST: return trans2_findfirst(req, op); case TRANSACT2_FINDNEXT: return trans2_findnext(req, op); case TRANSACT2_QPATHINFO: return trans2_qpathinfo(req, op); case TRANSACT2_QFILEINFO: return trans2_qfileinfo(req, op); case TRANSACT2_SETFILEINFO: return trans2_setfileinfo(req, op); case TRANSACT2_SETPATHINFO: return trans2_setpathinfo(req, op); case TRANSACT2_QFSINFO: return trans2_qfsinfo(req, op); case TRANSACT2_OPEN: return trans2_open(req, op); case TRANSACT2_MKDIR: return trans2_mkdir(req, op); } /* an unknown trans2 command */ return NT_STATUS_FOOBAR;}/* send a continue request*/static void reply_trans_continue(struct smbsrv_request *req, uint8_t command, struct smb_trans2 *trans){ 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 = talloc_reference(tp, req); tp->trans = trans; tp->command = command; DLIST_ADD(req->smb_conn->trans_partial, tp); /* send a 'please continue' reply */ smbsrv_setup_reply(req, 0, 0); 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; uint_t 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)); SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count); 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);}/* answer a reconstructed trans request*/static void reply_trans_complete(struct smbsrv_request *req, uint8_t command, struct smb_trans2 *trans){ struct trans_op *op; SMBSRV_TALLOC_IO_PTR(op, struct trans_op); SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC); op->req = req; op->trans = trans; op->command = command; op->op_info = NULL; op->send_fn = NULL; /* its a full request, give it to the backend */ if (command == SMBtrans) { SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans)); return; } else { SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op)); return; }}/* Reply to an SMBtrans or SMBtrans2 request*/static void reply_trans_generic(struct smbsrv_request *req, uint8_t command){ struct smb_trans2 *trans; int i; uint16_t param_ofs, data_ofs; uint16_t param_count, data_count; uint16_t param_total, data_total; /* parse request */ if (req->in.wct < 14) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } trans = talloc(req, struct smb_trans2); if (trans == NULL) { smbsrv_send_error(req, NT_STATUS_NO_MEMORY); return; } param_total = SVAL(req->in.vwv, VWV(0)); data_total = SVAL(req->in.vwv, VWV(1)); trans->in.max_param = SVAL(req->in.vwv, VWV(2)); trans->in.max_data = SVAL(req->in.vwv, VWV(3)); trans->in.max_setup = CVAL(req->in.vwv, VWV(4)); trans->in.flags = SVAL(req->in.vwv, VWV(5)); trans->in.timeout = IVAL(req->in.vwv, VWV(6)); param_count = SVAL(req->in.vwv, VWV(9)); param_ofs = SVAL(req->in.vwv, VWV(10)); data_count = SVAL(req->in.vwv, VWV(11)); data_ofs = SVAL(req->in.vwv, VWV(12)); trans->in.setup_count = CVAL(req->in.vwv, VWV(13)); if (req->in.wct != 14 + trans->in.setup_count) { smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror)); return; } /* parse out the setup words */ trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count); if (trans->in.setup_count && !trans->in.setup) { smbsrv_send_error(req, NT_STATUS_NO_MEMORY); return; } for (i=0;i<trans->in.setup_count;i++) { trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i)); } if (command == SMBtrans) { req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE); } if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) || !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } /* is it a partial request? if so, then send a 'send more' message */ if (param_total > param_count || data_total > data_count) { reply_trans_continue(req, command, trans); return; } reply_trans_complete(req, command, trans);}/* Reply to an SMBtranss2 request*/static void reply_transs_generic(struct smbsrv_request *req, uint8_t command){ struct smbsrv_trans_partial *tp; struct smb_trans2 *trans = NULL; uint16_t param_ofs, data_ofs; uint16_t param_count, data_count; uint16_t param_disp, data_disp; uint16_t param_total, data_total; DATA_BLOB params, data; /* parse request */ if (req->in.wct < 8) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) { if (tp->command == command && SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {/* TODO: check the VUID, PID and TID too? */ break; } } if (tp == NULL) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } trans = tp->trans; param_total = SVAL(req->in.vwv, VWV(0)); data_total = SVAL(req->in.vwv, VWV(1)); param_count = SVAL(req->in.vwv, VWV(2)); param_ofs = SVAL(req->in.vwv, VWV(3)); param_disp = SVAL(req->in.vwv, VWV(4)); data_count = SVAL(req->in.vwv, VWV(5)); data_ofs = SVAL(req->in.vwv, VWV(6)); data_disp = SVAL(req->in.vwv, VWV(7)); if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, ¶ms) || !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } /* only allow contiguous requests */ if ((param_count != 0 && param_disp != trans->in.params.length) || (data_count != 0 && data_disp != trans->in.data.length)) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } /* add to the existing request */ if (param_count != 0) { trans->in.params.data = talloc_realloc(trans, trans->in.params.data, uint8_t, param_disp + param_count); if (trans->in.params.data == NULL) { goto failed; } trans->in.params.length = param_disp + param_count; } if (data_count != 0) { trans->in.data.data = talloc_realloc(trans, trans->in.data.data, uint8_t, data_disp + data_count); if (trans->in.data.data == NULL) { goto failed; } trans->in.data.length = data_disp + data_count; } memcpy(trans->in.params.data + param_disp, params.data, params.length); memcpy(trans->in.data.data + data_disp, data.data, data.length); /* the sequence number of the reply is taken from the last secondary response */ tp->req->seq_num = req->seq_num; /* we don't reply to Transs2 requests */ talloc_free(req); if (trans->in.params.length == param_total && trans->in.data.length == data_total) { /* its now complete */ DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp); reply_trans_complete(tp->req, command, trans); } return;failed: smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY); DLIST_REMOVE(req->smb_conn->trans_partial, tp); talloc_free(req); talloc_free(tp);}/* Reply to an SMBtrans2*/void smbsrv_reply_trans2(struct smbsrv_request *req){ reply_trans_generic(req, SMBtrans2);}/* Reply to an SMBtrans*/void smbsrv_reply_trans(struct smbsrv_request *req){ reply_trans_generic(req, SMBtrans);}/* Reply to an SMBtranss request*/void smbsrv_reply_transs(struct smbsrv_request *req){ reply_transs_generic(req, SMBtrans);}/* Reply to an SMBtranss2 request*/void smbsrv_reply_transs2(struct smbsrv_request *req){ reply_transs_generic(req, SMBtrans2);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -