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