size_t clistr_push_fn(struct cli_state *cli, void *dest, const char *src, int dest_len, int flags) { size_t buf_used = PTR_DIFF(dest, cli->outbuf); if (dest_len == -1) { if (((ptrdiff_t)dest < (ptrdiff_t)cli->outbuf) || (buf_used > cli->bufsize)) { DEBUG(0, ("Pushing string of 'unlimited' length into non-SMB buffer!\n")); return push_string_base(cli->outbuf, (uint16_t)(cli_ucs2(cli) ? FLAGS2_UNICODE_STRINGS : 0), dest, src, -1, flags); } return push_string_base(cli->outbuf, (uint16_t)(cli_ucs2(cli) ? FLAGS2_UNICODE_STRINGS : 0), dest, src, cli->bufsize - buf_used, flags); } /* 'normal' push into size-specified buffer */ return push_string_base(cli->outbuf, (uint16_t)(cli_ucs2(cli) ? FLAGS2_UNICODE_STRINGS : 0), dest, src, dest_len, flags); }
NTSTATUS cli_dfs_get_referral(TALLOC_CTX *ctx, struct cli_state *cli, const char *path, struct client_dfs_referral **refs, size_t *num_refs, size_t *consumed) { unsigned int data_len = 0; unsigned int param_len = 0; uint16_t setup[1]; uint16_t recv_flags2; uint8_t *param = NULL; uint8_t *rdata = NULL; char *p; char *endp; smb_ucs2_t *path_ucs; char *consumed_path = NULL; uint16_t consumed_ucs; uint16 num_referrals; struct client_dfs_referral *referrals = NULL; NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); *num_refs = 0; *refs = NULL; SSVAL(setup, 0, TRANSACT2_GET_DFS_REFERRAL); param = talloc_array(talloc_tos(), uint8_t, 2); if (!param) { status = NT_STATUS_NO_MEMORY; goto out; } SSVAL(param, 0, 0x03); /* max referral level */ param = trans2_bytes_push_str(param, cli_ucs2(cli), path, strlen(path)+1, NULL); if (!param) { status = NT_STATUS_NO_MEMORY; goto out; } param_len = talloc_get_size(param); path_ucs = (smb_ucs2_t *)¶m[2]; status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0xffff, 0, 0, setup, 1, 0, param, param_len, 2, NULL, 0, CLI_BUFFER_SIZE, &recv_flags2, NULL, 0, NULL, /* rsetup */ NULL, 0, NULL, &rdata, 4, &data_len); if (!NT_STATUS_IS_OK(status)) { goto out; } endp = (char *)rdata + data_len; consumed_ucs = SVAL(rdata, 0); num_referrals = SVAL(rdata, 2); /* consumed_ucs is the number of bytes * of the UCS2 path consumed not counting any * terminating null. We need to convert * back to unix charset and count again * to get the number of bytes consumed from * the incoming path. */ errno = 0; if (pull_string_talloc(talloc_tos(), NULL, 0, &consumed_path, path_ucs, consumed_ucs, STR_UNICODE) == 0) { if (errno != 0) { status = map_nt_error_from_unix(errno); } else { status = NT_STATUS_INVALID_NETWORK_RESPONSE; } goto out; } if (consumed_path == NULL) { status = map_nt_error_from_unix(errno); goto out; } *consumed = strlen(consumed_path); if (num_referrals != 0) { uint16 ref_version; uint16 ref_size; int i; uint16 node_offset; referrals = talloc_array(ctx, struct client_dfs_referral, num_referrals); if (!referrals) { status = NT_STATUS_NO_MEMORY; goto out; } /* start at the referrals array */ p = (char *)rdata+8; for (i=0; i<num_referrals && p < endp; i++) { if (p + 18 > endp) { goto out; } ref_version = SVAL(p, 0); ref_size = SVAL(p, 2); node_offset = SVAL(p, 16); if (ref_version != 3) { p += ref_size; continue; } referrals[i].proximity = SVAL(p, 8); referrals[i].ttl = SVAL(p, 10); if (p + node_offset > endp) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto out; } clistr_pull_talloc(referrals, (const char *)rdata, recv_flags2, &referrals[i].dfspath, p+node_offset, PTR_DIFF(endp, p+node_offset), STR_TERMINATE|STR_UNICODE); if (!referrals[i].dfspath) { status = map_nt_error_from_unix(errno); goto out; } p += ref_size; } if (i < num_referrals) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto out; } }
struct tevent_req *cli_trans_send( TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, uint8_t cmd, const char *pipe_name, uint16_t fid, uint16_t function, int flags, uint16_t *setup, uint8_t num_setup, uint8_t max_setup, uint8_t *param, uint32_t num_param, uint32_t max_param, uint8_t *data, uint32_t num_data, uint32_t max_data) { struct tevent_req *req, *subreq; struct cli_trans_state *state; int iov_count; uint8_t wct; req = tevent_req_create(mem_ctx, &state, struct cli_trans_state); if (req == NULL) { return NULL; } if ((cmd == SMBtrans) || (cmd == SMBtrans2)) { if ((num_param > 0xffff) || (max_param > 0xffff) || (num_data > 0xffff) || (max_data > 0xffff)) { DEBUG(3, ("Attempt to send invalid trans2 request " "(setup %u, params %u/%u, data %u/%u)\n", (unsigned)num_setup, (unsigned)num_param, (unsigned)max_param, (unsigned)num_data, (unsigned)max_data)); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } } /* * The largest wct will be for nttrans (19+num_setup). Make sure we * don't overflow state->vwv in cli_trans_format. */ if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } state->cli = cli; state->ev = ev; state->cmd = cmd; state->flags = flags; state->num_rsetup = 0; state->rsetup = NULL; ZERO_STRUCT(state->rparam); ZERO_STRUCT(state->rdata); if ((pipe_name != NULL) && (!convert_string_talloc(state, CH_UNIX, cli_ucs2(cli) ? CH_UTF16LE : CH_DOS, pipe_name, strlen(pipe_name) + 1, &state->pipe_name_conv, &state->pipe_name_conv_len, true))) { tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return tevent_req_post(req, ev); } state->fid = fid; /* trans2 */ state->function = function; /* nttrans */ state->setup = setup; state->num_setup = num_setup; state->max_setup = max_setup; state->param = param; state->num_param = num_param; state->param_sent = 0; state->rparam.max = max_param; state->data = data; state->num_data = num_data; state->data_sent = 0; state->rdata.max = max_data; cli_trans_format(state, &wct, &iov_count); subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv, iov_count, state->iov); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } state->mid = cli_smb_req_mid(subreq); if (!cli_smb_req_send(subreq)) { tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return tevent_req_post(req, state->ev); } cli_state_seqnum_persistent(cli, state->mid); tevent_req_set_callback(subreq, cli_trans_done, req); return req; }
/**************************************************************************** check for existance of a nttrans call ****************************************************************************/ static bool scan_nttrans(struct cli_state *cli, int op, int level, int fnum, int dnum, const char *fname) { uint32_t data_len = 0; uint32_t param_len = 0; uint32_t rparam_len, rdata_len; uint8_t *param = NULL; uint8_t data[DATA_SIZE]; NTSTATUS status; const char *newfname; const char *dname; memset(data, 0, sizeof(data)); data_len = 4; /* try with a info level only */ TALLOC_FREE(param); param = talloc_array(talloc_tos(), uint8_t, 2); if (param == NULL) return True; SSVAL(param, 0, level); param_len = talloc_get_size(param); status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len, &rparam_len, &rdata_len); if (NT_STATUS_IS_OK(status)) return True; /* try with a file descriptor */ TALLOC_FREE(param); param = talloc_array(talloc_tos(), uint8_t, 6); if (param == NULL) return True; SSVAL(param, 0, fnum); SSVAL(param, 2, level); SSVAL(param, 4, 0); param_len = talloc_get_size(param); status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len, &rparam_len, &rdata_len); if (NT_STATUS_IS_OK(status)) return True; /* try with a notify style */ TALLOC_FREE(param); param = talloc_array(talloc_tos(), uint8_t, 6); if (param == NULL) return True; SSVAL(param, 0, dnum); SSVAL(param, 2, dnum); SSVAL(param, 4, level); param_len = talloc_get_size(param); status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len, &rparam_len, &rdata_len); if (NT_STATUS_IS_OK(status)) return True; /* try with a file name */ TALLOC_FREE(param); param = talloc_array(talloc_tos(), uint8_t, 6); if (param == NULL) return True; SSVAL(param, 0, level); SSVAL(param, 2, 0); SSVAL(param, 4, 0); param = trans2_bytes_push_str(param, cli_ucs2(cli), fname, strlen(fname)+1, NULL); if (param == NULL) return True; param_len = talloc_get_size(param); status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len, &rparam_len, &rdata_len); if (NT_STATUS_IS_OK(status)) return True; /* try with a new file name */ newfname = "\\newfile.dat"; TALLOC_FREE(param); param = talloc_array(talloc_tos(), uint8_t, 6); if (param == NULL) return True; SSVAL(param, 0, level); SSVAL(param, 2, 0); SSVAL(param, 4, 0); param = trans2_bytes_push_str(param, cli_ucs2(cli), newfname, strlen(newfname)+1, NULL); if (param == NULL) return True; param_len = talloc_get_size(param); status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len, &rparam_len, &rdata_len); cli_unlink(cli, newfname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); cli_rmdir(cli, newfname); if (NT_STATUS_IS_OK(status)) return True; /* try dfs style */ dname = "\\testdir"; cli_mkdir(cli, dname); TALLOC_FREE(param); param = talloc_array(talloc_tos(), uint8_t, 2); if (param == NULL) return True; SSVAL(param, 0, level); param = trans2_bytes_push_str(param, cli_ucs2(cli), dname, strlen(dname)+1, NULL); if (param == NULL) return True; param_len = talloc_get_size(param); status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len, &rparam_len, &rdata_len); cli_rmdir(cli, dname); if (NT_STATUS_IS_OK(status)) return True; return False; }