Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * Copyright (C) Stefan Metzmacher 2009
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include <tevent.h>
22 : #include "system/filesys.h"
23 : #include "system/network.h"
24 : #include "../lib/tsocket/tsocket.h"
25 : #include "../libcli/util/tstream.h"
26 : #include "../lib/util/tevent_ntstatus.h"
27 :
28 : struct tstream_read_pdu_blob_state {
29 : /* this structs are owned by the caller */
30 : struct {
31 : struct tevent_context *ev;
32 : struct tstream_context *stream;
33 : tstream_read_pdu_blob_full_fn_t *full_fn;
34 : void *full_private;
35 : } caller;
36 :
37 : DATA_BLOB pdu_blob;
38 : struct iovec tmp_vector;
39 : };
40 :
41 : static void tstream_read_pdu_blob_done(struct tevent_req *subreq);
42 :
43 2220816 : struct tevent_req *tstream_read_pdu_blob_send(TALLOC_CTX *mem_ctx,
44 : struct tevent_context *ev,
45 : struct tstream_context *stream,
46 : size_t initial_read_size,
47 : tstream_read_pdu_blob_full_fn_t *full_fn,
48 : void *full_private)
49 : {
50 6433 : struct tevent_req *req;
51 6433 : struct tstream_read_pdu_blob_state *state;
52 6433 : struct tevent_req *subreq;
53 6433 : uint8_t *buf;
54 :
55 2220816 : req = tevent_req_create(mem_ctx, &state,
56 : struct tstream_read_pdu_blob_state);
57 2220816 : if (!req) {
58 0 : return NULL;
59 : }
60 :
61 2220816 : state->caller.ev = ev;
62 2220816 : state->caller.stream = stream;
63 2220816 : state->caller.full_fn = full_fn;
64 2220816 : state->caller.full_private = full_private;
65 :
66 2220816 : if (initial_read_size == 0) {
67 0 : tevent_req_error(req, EINVAL);
68 0 : return tevent_req_post(req, ev);
69 : }
70 :
71 2220816 : buf = talloc_array(state, uint8_t, initial_read_size);
72 2220816 : if (tevent_req_nomem(buf, req)) {
73 0 : return tevent_req_post(req, ev);
74 : }
75 2220816 : state->pdu_blob.data = buf;
76 2220816 : state->pdu_blob.length = initial_read_size;
77 :
78 2220816 : state->tmp_vector.iov_base = (char *) buf;
79 2220816 : state->tmp_vector.iov_len = initial_read_size;
80 :
81 2220816 : subreq = tstream_readv_send(state, ev, stream, &state->tmp_vector, 1);
82 2220816 : if (tevent_req_nomem(subreq, req)) {
83 0 : return tevent_req_post(req, ev);
84 : }
85 2220816 : tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
86 :
87 2220816 : return req;
88 : }
89 :
90 4335974 : static void tstream_read_pdu_blob_done(struct tevent_req *subreq)
91 : {
92 10501 : struct tevent_req *req =
93 4335974 : tevent_req_callback_data(subreq,
94 : struct tevent_req);
95 10501 : struct tstream_read_pdu_blob_state *state =
96 4335974 : tevent_req_data(req,
97 : struct tstream_read_pdu_blob_state);
98 10501 : ssize_t ret;
99 10501 : int sys_errno;
100 4335974 : size_t old_buf_size = state->pdu_blob.length;
101 4335974 : size_t new_buf_size = 0;
102 4335974 : size_t pdu_size = 0;
103 10501 : NTSTATUS status;
104 10501 : uint8_t *buf;
105 :
106 4335974 : ret = tstream_readv_recv(subreq, &sys_errno);
107 4335974 : TALLOC_FREE(subreq);
108 4335974 : if (ret == -1) {
109 105482 : status = map_nt_error_from_unix_common(sys_errno);
110 105482 : tevent_req_nterror(req, status);
111 2223104 : return;
112 : }
113 :
114 4230492 : status = state->caller.full_fn(state->caller.stream,
115 : state->caller.full_private,
116 : state->pdu_blob, &pdu_size);
117 4230492 : if (NT_STATUS_IS_OK(status)) {
118 2115251 : tevent_req_done(req);
119 2115251 : return;
120 2115241 : } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
121 : /* more to get */
122 2115235 : if (pdu_size > 0) {
123 2111167 : new_buf_size = pdu_size;
124 : } else {
125 : /* we don't know the size yet, so get one more byte */
126 0 : new_buf_size = old_buf_size + 1;
127 : }
128 6 : } else if (!NT_STATUS_IS_OK(status)) {
129 6 : tevent_req_nterror(req, status);
130 6 : return;
131 : }
132 :
133 2115235 : if (new_buf_size <= old_buf_size) {
134 0 : tevent_req_nterror(req, NT_STATUS_INVALID_BUFFER_SIZE);
135 0 : return;
136 : }
137 :
138 2115235 : buf = talloc_realloc(state, state->pdu_blob.data, uint8_t, new_buf_size);
139 2115235 : if (tevent_req_nomem(buf, req)) {
140 0 : return;
141 : }
142 2115235 : state->pdu_blob.data = buf;
143 2115235 : state->pdu_blob.length = new_buf_size;
144 :
145 2115235 : state->tmp_vector.iov_base = (char *) (buf + old_buf_size);
146 2115235 : state->tmp_vector.iov_len = new_buf_size - old_buf_size;
147 :
148 2115235 : subreq = tstream_readv_send(state,
149 : state->caller.ev,
150 : state->caller.stream,
151 : &state->tmp_vector,
152 : 1);
153 2115235 : if (tevent_req_nomem(subreq, req)) {
154 0 : return;
155 : }
156 2115235 : tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
157 : }
158 :
159 2220739 : NTSTATUS tstream_read_pdu_blob_recv(struct tevent_req *req,
160 : TALLOC_CTX *mem_ctx,
161 : DATA_BLOB *pdu_blob)
162 : {
163 2220739 : struct tstream_read_pdu_blob_state *state = tevent_req_data(req,
164 : struct tstream_read_pdu_blob_state);
165 6433 : NTSTATUS status;
166 :
167 2220739 : if (tevent_req_is_nterror(req, &status)) {
168 105488 : tevent_req_received(req);
169 105488 : return status;
170 : }
171 :
172 2115251 : *pdu_blob = state->pdu_blob;
173 2115251 : talloc_steal(mem_ctx, pdu_blob->data);
174 :
175 2115251 : tevent_req_received(req);
176 2115251 : return NT_STATUS_OK;
177 : }
178 :
179 171832 : NTSTATUS tstream_full_request_u32(struct tstream_context *stream,
180 : void *private_data,
181 : DATA_BLOB blob, size_t *size)
182 : {
183 171832 : if (blob.length < 4) {
184 0 : return STATUS_MORE_ENTRIES;
185 : }
186 171832 : *size = 4 + RIVAL(blob.data, 0);
187 171832 : if (*size > blob.length) {
188 85916 : return STATUS_MORE_ENTRIES;
189 : }
190 85916 : return NT_STATUS_OK;
191 : }
192 :
193 444 : NTSTATUS tstream_full_request_u16(struct tstream_context *stream,
194 : void *private_data,
195 : DATA_BLOB blob, size_t *size)
196 : {
197 444 : if (blob.length < 2) {
198 0 : return STATUS_MORE_ENTRIES;
199 : }
200 444 : *size = 2 + RSVAL(blob.data, 0);
201 444 : if (*size > blob.length) {
202 222 : return STATUS_MORE_ENTRIES;
203 : }
204 222 : return NT_STATUS_OK;
205 : }
|