/* pull a string from a blob in a trans2 request */ size_t smbsrv_blob_pull_string(struct smbsrv_request *req, const DATA_BLOB *blob, uint16_t offset, const char **str, int flags) { *str = NULL; /* we use STR_NO_RANGE_CHECK because the params are allocated separately in a DATA_BLOB, so we need to do our own range checking */ if (offset >= blob->length) { return 0; } return req_pull_string(req, str, blob->data + offset, blob->length - offset, STR_NO_RANGE_CHECK | flags); }
/** pull a ASCII4 string buffer from a request packet, returning a talloced string an ASCII4 buffer is a null terminated string that has a prefix of the character 0x4. It tends to be used in older parts of the protocol. on failure *dest is set to the zero length string. This seems to match win2000 behaviour */ size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, unsigned int flags) { ssize_t ret; if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) { /* win2000 treats this as the empty string! */ (*dest) = talloc_strdup(bufinfo->mem_ctx, ""); return 0; } /* this consumes the 0x4 byte. We don't check whether the byte is actually 0x4 or not. This matches win2000 server behaviour */ src++; ret = req_pull_string(bufinfo, dest, src, -1, flags); if (ret == -1) { (*dest) = talloc_strdup(bufinfo->mem_ctx, ""); return 1; } return ret + 1; }
/* 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); }
/* parse NTTRANS_CREATE request */ static NTSTATUS nttrans_create(struct smbsrv_request *req, struct nttrans_op *op) { struct smb_nttrans *trans = op->trans; union smb_open *io; uint16_t fname_len; uint32_t sd_length, ea_length; NTSTATUS status; uint8_t *params; enum ndr_err_code ndr_err; if (trans->in.params.length < 54) { return NT_STATUS_INVALID_PARAMETER; } /* parse the request */ io = talloc(op, union smb_open); NT_STATUS_HAVE_NO_MEMORY(io); io->ntcreatex.level = RAW_OPEN_NTTRANS_CREATE; params = trans->in.params.data; io->ntcreatex.in.flags = IVAL(params, 0); io->ntcreatex.in.root_fid.ntvfs = smbsrv_pull_fnum(req, params, 4); io->ntcreatex.in.access_mask = IVAL(params, 8); io->ntcreatex.in.alloc_size = BVAL(params, 12); io->ntcreatex.in.file_attr = IVAL(params, 20); io->ntcreatex.in.share_access = IVAL(params, 24); io->ntcreatex.in.open_disposition = IVAL(params, 28); io->ntcreatex.in.create_options = IVAL(params, 32); sd_length = IVAL(params, 36); ea_length = IVAL(params, 40); fname_len = IVAL(params, 44); io->ntcreatex.in.impersonation = IVAL(params, 48); io->ntcreatex.in.security_flags = CVAL(params, 52); io->ntcreatex.in.sec_desc = NULL; io->ntcreatex.in.ea_list = NULL; io->ntcreatex.in.query_maximal_access = false; io->ntcreatex.in.query_on_disk_id = false; io->ntcreatex.in.private_flags = 0; req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, params + 53, MIN(fname_len+1, trans->in.params.length - 53), STR_NO_RANGE_CHECK | STR_TERMINATE); if (!io->ntcreatex.in.fname) { return NT_STATUS_INVALID_PARAMETER; } if (sd_length > trans->in.data.length || ea_length > trans->in.data.length || (sd_length+ea_length) > trans->in.data.length) { return NT_STATUS_INVALID_PARAMETER; } /* this call has an optional security descriptor */ if (sd_length != 0) { DATA_BLOB blob; blob.data = trans->in.data.data; blob.length = sd_length; io->ntcreatex.in.sec_desc = talloc(io, struct security_descriptor); if (io->ntcreatex.in.sec_desc == NULL) { return NT_STATUS_NO_MEMORY; } ndr_err = ndr_pull_struct_blob(&blob, io, io->ntcreatex.in.sec_desc, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return ndr_map_error2ntstatus(ndr_err); } }