Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Pipe SMB reply routines
4 : Copyright (C) Andrew Tridgell 1992-1998
5 : Copyright (C) Luke Kenneth Casson Leighton 1996-1998
6 : Copyright (C) Paul Ashton 1997-1998.
7 : Copyright (C) Jeremy Allison 2005.
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 : /*
23 : This file handles reply_ calls on named pipes that the server
24 : makes to handle specific protocols
25 : */
26 :
27 :
28 : #include "includes.h"
29 : #include "smbd/smbd.h"
30 : #include "smbd/globals.h"
31 : #include "libcli/security/security.h"
32 : #include "rpc_server/srv_pipe_hnd.h"
33 : #include "auth/auth_util.h"
34 : #include "librpc/rpc/dcerpc_helper.h"
35 :
36 : /****************************************************************************
37 : Reply to an open and X on a named pipe.
38 : This code is basically stolen from reply_open_and_X with some
39 : wrinkles to handle pipes.
40 : ****************************************************************************/
41 :
42 40 : void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req)
43 : {
44 40 : const char *fname = NULL;
45 40 : char *pipe_name = NULL;
46 0 : files_struct *fsp;
47 40 : TALLOC_CTX *ctx = talloc_tos();
48 0 : NTSTATUS status;
49 :
50 : /* XXXX we need to handle passed times, sattr and flags */
51 40 : srvstr_pull_req_talloc(ctx, req, &pipe_name, req->buf, STR_TERMINATE);
52 40 : if (!pipe_name) {
53 0 : reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
54 : ERRDOS, ERRbadpipe);
55 0 : return;
56 : }
57 :
58 : /* If the name doesn't start \PIPE\ then this is directed */
59 : /* at a mailslot or something we really, really don't understand, */
60 : /* not just something we really don't understand. */
61 :
62 : #define PIPE "PIPE\\"
63 : #define PIPELEN strlen(PIPE)
64 :
65 40 : fname = pipe_name;
66 96 : while (fname[0] == '\\') {
67 56 : fname++;
68 : }
69 40 : if (!strnequal(fname, PIPE, PIPELEN)) {
70 16 : reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
71 16 : return;
72 : }
73 24 : fname += PIPELEN;
74 40 : while (fname[0] == '\\') {
75 16 : fname++;
76 : }
77 :
78 24 : DEBUG(4,("Opening pipe %s => %s.\n", pipe_name, fname));
79 :
80 24 : status = open_np_file(req, fname, &fsp);
81 24 : if (!NT_STATUS_IS_OK(status)) {
82 8 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
83 8 : reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
84 : ERRDOS, ERRbadpipe);
85 8 : return;
86 : }
87 0 : reply_nterror(req, status);
88 0 : return;
89 : }
90 :
91 : /* Prepare the reply */
92 16 : reply_smb1_outbuf(req, 15, 0);
93 :
94 16 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
95 16 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
96 :
97 : /* Mark the opened file as an existing named pipe in message mode. */
98 16 : SSVAL(req->outbuf,smb_vwv9,2);
99 16 : SSVAL(req->outbuf,smb_vwv10,0xc700);
100 :
101 16 : SSVAL(req->outbuf, smb_vwv2, fsp->fnum);
102 16 : SSVAL(req->outbuf, smb_vwv3, 0); /* fmode */
103 16 : srv_put_dos_date3((char *)req->outbuf, smb_vwv4, 0); /* mtime */
104 16 : SIVAL(req->outbuf, smb_vwv6, 0); /* size */
105 16 : SSVAL(req->outbuf, smb_vwv8, 0); /* rmode */
106 16 : SSVAL(req->outbuf, smb_vwv11, 0x0001);
107 : }
108 :
109 : /****************************************************************************
110 : Reply to a write and X.
111 :
112 : This code is basically stolen from reply_write_and_X with some
113 : wrinkles to handle pipes.
114 : ****************************************************************************/
115 :
116 : struct pipe_write_andx_state {
117 : bool pipe_start_message_raw;
118 : size_t numtowrite;
119 : };
120 :
121 : static void pipe_write_andx_done(struct tevent_req *subreq);
122 :
123 8 : void reply_pipe_write_and_X(struct smb_request *req)
124 : {
125 8 : files_struct *fsp = file_fsp(req, SVAL(req->vwv+2, 0));
126 8 : int smb_doff = SVAL(req->vwv+11, 0);
127 0 : const uint8_t *data;
128 0 : struct pipe_write_andx_state *state;
129 0 : struct tevent_req *subreq;
130 :
131 8 : if (!fsp_is_np(fsp)) {
132 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
133 0 : return;
134 : }
135 :
136 8 : if (fsp->vuid != req->vuid) {
137 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
138 0 : return;
139 : }
140 :
141 8 : state = talloc(req, struct pipe_write_andx_state);
142 8 : if (state == NULL) {
143 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
144 0 : return;
145 : }
146 8 : req->async_priv = state;
147 :
148 8 : state->numtowrite = SVAL(req->vwv+10, 0);
149 8 : state->pipe_start_message_raw =
150 8 : ((SVAL(req->vwv+7, 0) & (PIPE_START_MESSAGE|PIPE_RAW_MODE))
151 8 : == (PIPE_START_MESSAGE|PIPE_RAW_MODE));
152 :
153 8 : DEBUG(6, ("reply_pipe_write_and_X: %s, name: %s len: %d\n",
154 : fsp_fnum_dbg(fsp), fsp_str_dbg(fsp), (int)state->numtowrite));
155 :
156 8 : data = (const uint8_t *)smb_base(req->inbuf) + smb_doff;
157 :
158 8 : if (state->pipe_start_message_raw) {
159 : /*
160 : * For the start of a message in named pipe byte mode,
161 : * the first two bytes are a length-of-pdu field. Ignore
162 : * them (we don't trust the client). JRA.
163 : */
164 0 : if (state->numtowrite < 2) {
165 0 : DEBUG(0,("reply_pipe_write_and_X: start of message "
166 : "set and not enough data sent.(%u)\n",
167 : (unsigned int)state->numtowrite ));
168 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
169 0 : return;
170 : }
171 :
172 0 : data += 2;
173 0 : state->numtowrite -= 2;
174 : }
175 :
176 8 : subreq = np_write_send(state, req->sconn->ev_ctx,
177 : fsp->fake_file_handle, data, state->numtowrite);
178 8 : if (subreq == NULL) {
179 0 : TALLOC_FREE(state);
180 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
181 0 : return;
182 : }
183 8 : tevent_req_set_callback(subreq, pipe_write_andx_done,
184 : talloc_move(req->conn, &req));
185 : }
186 :
187 8 : static void pipe_write_andx_done(struct tevent_req *subreq)
188 : {
189 8 : struct smb_request *req = tevent_req_callback_data(
190 : subreq, struct smb_request);
191 8 : struct pipe_write_andx_state *state = talloc_get_type_abort(
192 : req->async_priv, struct pipe_write_andx_state);
193 0 : NTSTATUS status;
194 8 : ssize_t nwritten = -1;
195 :
196 8 : status = np_write_recv(subreq, &nwritten);
197 8 : TALLOC_FREE(subreq);
198 :
199 8 : if (!NT_STATUS_IS_OK(status)) {
200 0 : reply_nterror(req, status);
201 0 : goto done;
202 : }
203 :
204 : /* Looks bogus to me now. Is this error message correct ? JRA. */
205 8 : if (nwritten != state->numtowrite) {
206 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
207 0 : goto done;
208 : }
209 :
210 8 : reply_smb1_outbuf(req, 6, 0);
211 :
212 8 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
213 8 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
214 :
215 8 : nwritten = (state->pipe_start_message_raw ? nwritten + 2 : nwritten);
216 8 : SSVAL(req->outbuf,smb_vwv2,nwritten);
217 :
218 8 : DEBUG(3,("writeX-IPC nwritten=%d\n", (int)nwritten));
219 :
220 8 : done:
221 : /*
222 : * We must free here as the ownership of req was
223 : * moved to the connection struct in reply_pipe_write_and_X().
224 : */
225 8 : smb_request_done(req);
226 8 : }
227 :
228 : /****************************************************************************
229 : Reply to a read and X.
230 : This code is basically stolen from reply_read_and_X with some
231 : wrinkles to handle pipes.
232 : ****************************************************************************/
233 :
234 : struct pipe_read_andx_state {
235 : uint8_t *outbuf;
236 : int smb_mincnt;
237 : int smb_maxcnt;
238 : };
239 :
240 : static void pipe_read_andx_done(struct tevent_req *subreq);
241 :
242 34 : void reply_pipe_read_and_X(struct smb_request *req)
243 : {
244 34 : files_struct *fsp = file_fsp(req, SVAL(req->vwv+0, 0));
245 0 : uint8_t *data;
246 0 : struct pipe_read_andx_state *state;
247 0 : struct tevent_req *subreq;
248 :
249 : /* we don't use the offset given to use for pipe reads. This
250 : is deliberate, instead we always return the next lump of
251 : data on the pipe */
252 : #if 0
253 : uint32_t smb_offs = IVAL(req->vwv+3, 0);
254 : #endif
255 :
256 34 : if (!fsp_is_np(fsp)) {
257 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
258 0 : return;
259 : }
260 :
261 34 : if (fsp->vuid != req->vuid) {
262 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
263 0 : return;
264 : }
265 :
266 34 : state = talloc(req, struct pipe_read_andx_state);
267 34 : if (state == NULL) {
268 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
269 0 : return;
270 : }
271 34 : req->async_priv = state;
272 :
273 34 : state->smb_maxcnt = SVAL(req->vwv+5, 0);
274 34 : state->smb_mincnt = SVAL(req->vwv+6, 0);
275 :
276 34 : reply_smb1_outbuf(req, 12, state->smb_maxcnt + 1 /* padding byte */);
277 34 : SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
278 34 : SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
279 34 : SCVAL(smb_buf(req->outbuf), 0, 0); /* padding byte */
280 :
281 34 : data = (uint8_t *)smb_buf(req->outbuf) + 1 /* padding byte */;
282 :
283 : /*
284 : * We have to tell the upper layers that we're async.
285 : */
286 34 : state->outbuf = req->outbuf;
287 34 : req->outbuf = NULL;
288 :
289 34 : subreq = np_read_send(state, req->sconn->ev_ctx,
290 : fsp->fake_file_handle, data,
291 34 : state->smb_maxcnt);
292 34 : if (subreq == NULL) {
293 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
294 0 : return;
295 : }
296 34 : tevent_req_set_callback(subreq, pipe_read_andx_done,
297 : talloc_move(req->conn, &req));
298 : }
299 :
300 34 : static void pipe_read_andx_done(struct tevent_req *subreq)
301 : {
302 34 : struct smb_request *req = tevent_req_callback_data(
303 : subreq, struct smb_request);
304 34 : struct pipe_read_andx_state *state = talloc_get_type_abort(
305 : req->async_priv, struct pipe_read_andx_state);
306 0 : NTSTATUS status;
307 0 : ssize_t nread;
308 0 : bool is_data_outstanding;
309 :
310 34 : status = np_read_recv(subreq, &nread, &is_data_outstanding);
311 34 : TALLOC_FREE(subreq);
312 34 : if (!NT_STATUS_IS_OK(status)) {
313 0 : NTSTATUS old = status;
314 0 : status = nt_status_np_pipe(old);
315 0 : reply_nterror(req, status);
316 0 : goto done;
317 : }
318 :
319 34 : req->outbuf = state->outbuf;
320 34 : state->outbuf = NULL;
321 :
322 34 : srv_smb1_set_message((char *)req->outbuf, 12, nread + 1 /* padding byte */,
323 : false);
324 :
325 : #if 0
326 : /*
327 : * we should return STATUS_BUFFER_OVERFLOW if there's
328 : * out standing data.
329 : *
330 : * But we can't enable it yet, as it has bad interactions
331 : * with fixup_chain_error_packet() in chain_reply().
332 : */
333 : if (is_data_outstanding) {
334 : error_packet_set((char *)req->outbuf, ERRDOS, ERRmoredata,
335 : STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__);
336 : }
337 : #endif
338 :
339 34 : SSVAL(req->outbuf,smb_vwv5,nread);
340 34 : SSVAL(req->outbuf,smb_vwv6,
341 : (smb_wct - 4) /* offset from smb header to wct */
342 : + 1 /* the wct field */
343 : + 12 * sizeof(uint16_t) /* vwv */
344 : + 2 /* the buflen field */
345 : + 1); /* padding byte */
346 :
347 34 : DEBUG(3,("readX-IPC min=%d max=%d nread=%d\n",
348 : state->smb_mincnt, state->smb_maxcnt, (int)nread));
349 :
350 34 : done:
351 : /*
352 : * We must free here as the ownership of req was
353 : * moved to the connection struct in reply_pipe_read_and_X().
354 : */
355 34 : smb_request_done(req);
356 34 : }
357 :
358 : /****************************************************************************
359 : Reply to a write on a pipe.
360 : ****************************************************************************/
361 :
362 : struct pipe_write_state {
363 : size_t numtowrite;
364 : };
365 :
366 : static void pipe_write_done(struct tevent_req *subreq);
367 :
368 0 : void reply_pipe_write(struct smb_request *req)
369 : {
370 0 : files_struct *fsp = file_fsp(req, SVAL(req->vwv+0, 0));
371 0 : const uint8_t *data;
372 0 : struct pipe_write_state *state;
373 0 : struct tevent_req *subreq;
374 :
375 0 : if (!fsp_is_np(fsp)) {
376 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
377 0 : return;
378 : }
379 :
380 0 : if (fsp->vuid != req->vuid) {
381 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
382 0 : return;
383 : }
384 :
385 0 : state = talloc(req, struct pipe_write_state);
386 0 : if (state == NULL) {
387 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
388 0 : return;
389 : }
390 0 : req->async_priv = state;
391 :
392 0 : state->numtowrite = SVAL(req->vwv+1, 0);
393 :
394 0 : data = req->buf + 3;
395 :
396 0 : DEBUG(6, ("reply_pipe_write: %s, name: %s len: %d\n", fsp_fnum_dbg(fsp),
397 : fsp_str_dbg(fsp), (int)state->numtowrite));
398 :
399 0 : subreq = np_write_send(state, req->sconn->ev_ctx,
400 : fsp->fake_file_handle, data, state->numtowrite);
401 0 : if (subreq == NULL) {
402 0 : TALLOC_FREE(state);
403 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
404 0 : return;
405 : }
406 0 : tevent_req_set_callback(subreq, pipe_write_done,
407 : talloc_move(req->conn, &req));
408 : }
409 :
410 0 : static void pipe_write_done(struct tevent_req *subreq)
411 : {
412 0 : struct smb_request *req = tevent_req_callback_data(
413 : subreq, struct smb_request);
414 0 : struct pipe_write_state *state = talloc_get_type_abort(
415 : req->async_priv, struct pipe_write_state);
416 0 : NTSTATUS status;
417 0 : ssize_t nwritten = -1;
418 :
419 0 : status = np_write_recv(subreq, &nwritten);
420 0 : TALLOC_FREE(subreq);
421 0 : if (nwritten < 0) {
422 0 : reply_nterror(req, status);
423 0 : goto send;
424 : }
425 :
426 : /* Looks bogus to me now. Needs to be removed ? JRA. */
427 0 : if ((nwritten == 0 && state->numtowrite != 0)) {
428 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
429 0 : goto send;
430 : }
431 :
432 0 : reply_smb1_outbuf(req, 1, 0);
433 :
434 0 : SSVAL(req->outbuf,smb_vwv0,nwritten);
435 :
436 0 : DEBUG(3,("write-IPC nwritten=%d\n", (int)nwritten));
437 :
438 0 : send:
439 0 : if (!smb1_srv_send(req->xconn,
440 0 : (char *)req->outbuf,
441 : true,
442 0 : req->seqnum + 1,
443 0 : IS_CONN_ENCRYPTED(req->conn) || req->encrypted)) {
444 0 : exit_server_cleanly("construct_reply: smb1_srv_send failed.");
445 : }
446 0 : TALLOC_FREE(req);
447 0 : }
|