Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Inter-process communication and named pipe handling
4 : Copyright (C) Andrew Tridgell 1992-1998
5 :
6 : SMB Version handling
7 : Copyright (C) John H Terpstra 1995-1998
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 the named pipe and mailslot calls
24 : in the SMBtrans protocol
25 : */
26 :
27 : #include "includes.h"
28 : #include "smbd/smbd.h"
29 : #include "smbd/globals.h"
30 : #include "smbprofile.h"
31 : #include "rpc_server/srv_pipe_hnd.h"
32 : #include "source3/lib/substitute.h"
33 :
34 : #define NERR_notsupported 50
35 :
36 : static void api_no_reply(connection_struct *conn, struct smb_request *req);
37 :
38 : /*******************************************************************
39 : copies parameters and data, as needed, into the smb buffer
40 :
41 : *both* the data and params sections should be aligned. this
42 : is fudged in the rpc pipes by
43 : at present, only the data section is. this may be a possible
44 : cause of some of the ipc problems being experienced. lkcl26dec97
45 :
46 : ******************************************************************/
47 :
48 4 : static void copy_trans_params_and_data(char *outbuf, int align,
49 : char *rparam, int param_offset, int param_len,
50 : char *rdata, int data_offset, int data_len)
51 : {
52 4 : char *copy_into = smb_buf(outbuf);
53 :
54 4 : if(param_len < 0)
55 0 : param_len = 0;
56 :
57 4 : if(data_len < 0)
58 0 : data_len = 0;
59 :
60 4 : DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d] (align %d)\n",
61 : param_offset, param_offset + param_len,
62 : data_offset , data_offset + data_len,
63 : align));
64 :
65 4 : *copy_into = '\0';
66 :
67 4 : copy_into += 1;
68 :
69 4 : if (param_len)
70 4 : memcpy(copy_into, &rparam[param_offset], param_len);
71 :
72 4 : copy_into += param_len;
73 4 : if (align) {
74 0 : memset(copy_into, '\0', align);
75 : }
76 :
77 4 : copy_into += align;
78 :
79 4 : if (data_len )
80 4 : memcpy(copy_into, &rdata[data_offset], data_len);
81 4 : }
82 :
83 : /****************************************************************************
84 : Send a trans reply.
85 : ****************************************************************************/
86 :
87 4 : void send_trans_reply(connection_struct *conn,
88 : struct smb_request *req,
89 : char *rparam, int rparam_len,
90 : char *rdata, int rdata_len,
91 : bool buffer_too_large)
92 : {
93 : int this_ldata,this_lparam;
94 4 : int tot_data_sent = 0;
95 4 : int tot_param_sent = 0;
96 : int align;
97 :
98 4 : int ldata = rdata ? rdata_len : 0;
99 4 : int lparam = rparam ? rparam_len : 0;
100 4 : struct smbXsrv_connection *xconn = req->xconn;
101 4 : int max_send = xconn->smb1.sessions.max_send;
102 : /* HACK: make sure we send at least 128 byte in one go */
103 4 : int hdr_overhead = SMB_BUFFER_SIZE_MIN - 128;
104 :
105 4 : if (buffer_too_large)
106 0 : DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
107 :
108 4 : this_lparam = MIN(lparam,max_send - hdr_overhead);
109 4 : this_ldata = MIN(ldata,max_send - (hdr_overhead+this_lparam));
110 :
111 4 : align = ((this_lparam)%4);
112 :
113 4 : reply_smb1_outbuf(req, 10, 1+align+this_ldata+this_lparam);
114 :
115 : /*
116 : * We might have SMBtranss in req which was transferred to the outbuf,
117 : * fix that.
118 : */
119 4 : SCVAL(req->outbuf, smb_com, SMBtrans);
120 :
121 4 : copy_trans_params_and_data((char *)req->outbuf, align,
122 : rparam, tot_param_sent, this_lparam,
123 : rdata, tot_data_sent, this_ldata);
124 :
125 4 : SSVAL(req->outbuf,smb_vwv0,lparam);
126 4 : SSVAL(req->outbuf,smb_vwv1,ldata);
127 4 : SSVAL(req->outbuf,smb_vwv3,this_lparam);
128 4 : SSVAL(req->outbuf,smb_vwv4,
129 : smb_offset(smb_buf(req->outbuf)+1, req->outbuf));
130 4 : SSVAL(req->outbuf,smb_vwv5,0);
131 4 : SSVAL(req->outbuf,smb_vwv6,this_ldata);
132 4 : SSVAL(req->outbuf,smb_vwv7,
133 : smb_offset(smb_buf(req->outbuf)+1+this_lparam+align,
134 : req->outbuf));
135 4 : SSVAL(req->outbuf,smb_vwv8,0);
136 4 : SSVAL(req->outbuf,smb_vwv9,0);
137 :
138 4 : if (buffer_too_large) {
139 0 : error_packet_set((char *)req->outbuf, ERRDOS, ERRmoredata,
140 0 : STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__);
141 : }
142 :
143 4 : show_msg((char *)req->outbuf);
144 8 : if (!smb1_srv_send(xconn, (char *)req->outbuf,
145 4 : true, req->seqnum+1,
146 4 : IS_CONN_ENCRYPTED(conn), &req->pcd)) {
147 0 : exit_server_cleanly("send_trans_reply: smb1_srv_send failed.");
148 : }
149 :
150 4 : TALLOC_FREE(req->outbuf);
151 :
152 4 : tot_data_sent = this_ldata;
153 4 : tot_param_sent = this_lparam;
154 :
155 6 : while (tot_data_sent < ldata || tot_param_sent < lparam)
156 : {
157 0 : this_lparam = MIN(lparam-tot_param_sent,
158 : max_send - hdr_overhead);
159 0 : this_ldata = MIN(ldata -tot_data_sent,
160 : max_send - (hdr_overhead+this_lparam));
161 :
162 0 : if(this_lparam < 0)
163 0 : this_lparam = 0;
164 :
165 0 : if(this_ldata < 0)
166 0 : this_ldata = 0;
167 :
168 0 : align = (this_lparam%4);
169 :
170 0 : reply_smb1_outbuf(req, 10, 1+align+this_ldata+this_lparam);
171 :
172 : /*
173 : * We might have SMBtranss in req which was transferred to the
174 : * outbuf, fix that.
175 : */
176 0 : SCVAL(req->outbuf, smb_com, SMBtrans);
177 :
178 0 : copy_trans_params_and_data((char *)req->outbuf, align,
179 : rparam, tot_param_sent, this_lparam,
180 : rdata, tot_data_sent, this_ldata);
181 :
182 0 : SSVAL(req->outbuf,smb_vwv0,lparam);
183 0 : SSVAL(req->outbuf,smb_vwv1,ldata);
184 :
185 0 : SSVAL(req->outbuf,smb_vwv3,this_lparam);
186 0 : SSVAL(req->outbuf,smb_vwv4,
187 : smb_offset(smb_buf(req->outbuf)+1,req->outbuf));
188 0 : SSVAL(req->outbuf,smb_vwv5,tot_param_sent);
189 0 : SSVAL(req->outbuf,smb_vwv6,this_ldata);
190 0 : SSVAL(req->outbuf,smb_vwv7,
191 : smb_offset(smb_buf(req->outbuf)+1+this_lparam+align,
192 : req->outbuf));
193 0 : SSVAL(req->outbuf,smb_vwv8,tot_data_sent);
194 0 : SSVAL(req->outbuf,smb_vwv9,0);
195 :
196 0 : if (buffer_too_large) {
197 0 : error_packet_set((char *)req->outbuf,
198 : ERRDOS, ERRmoredata,
199 0 : STATUS_BUFFER_OVERFLOW,
200 : __LINE__, __FILE__);
201 : }
202 :
203 0 : show_msg((char *)req->outbuf);
204 0 : if (!smb1_srv_send(xconn, (char *)req->outbuf,
205 0 : true, req->seqnum+1,
206 0 : IS_CONN_ENCRYPTED(conn), &req->pcd))
207 0 : exit_server_cleanly("send_trans_reply: smb1_srv_send "
208 : "failed.");
209 :
210 0 : tot_data_sent += this_ldata;
211 0 : tot_param_sent += this_lparam;
212 0 : TALLOC_FREE(req->outbuf);
213 : }
214 4 : }
215 :
216 : /****************************************************************************
217 : Start the first part of an RPC reply which began with an SMBtrans request.
218 : ****************************************************************************/
219 :
220 : struct dcerpc_cmd_state {
221 : struct fake_file_handle *handle;
222 : uint8_t *data;
223 : size_t num_data;
224 : size_t max_read;
225 : };
226 :
227 : static void api_dcerpc_cmd_write_done(struct tevent_req *subreq);
228 : static void api_dcerpc_cmd_read_done(struct tevent_req *subreq);
229 :
230 0 : static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
231 : files_struct *fsp, uint8_t *data, size_t length,
232 : size_t max_read)
233 : {
234 : struct tevent_req *subreq;
235 : struct dcerpc_cmd_state *state;
236 : bool busy;
237 :
238 0 : if (!fsp_is_np(fsp)) {
239 0 : api_no_reply(conn, req);
240 0 : return;
241 : }
242 :
243 : /*
244 : * Trans requests are only allowed
245 : * if no other Trans or Read is active
246 : */
247 0 : busy = np_read_in_progress(fsp->fake_file_handle);
248 0 : if (busy) {
249 0 : reply_nterror(req, NT_STATUS_PIPE_BUSY);
250 0 : return;
251 : }
252 :
253 0 : state = talloc(req, struct dcerpc_cmd_state);
254 0 : if (state == NULL) {
255 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
256 0 : return;
257 : }
258 0 : req->async_priv = state;
259 :
260 0 : state->handle = fsp->fake_file_handle;
261 :
262 : /*
263 : * This memdup severely sucks. But doing it properly essentially means
264 : * to rewrite lanman.c, something which I don't really want to do now.
265 : */
266 0 : state->data = (uint8_t *)talloc_memdup(state, data, length);
267 0 : if (state->data == NULL) {
268 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
269 0 : return;
270 : }
271 0 : state->num_data = length;
272 0 : state->max_read = max_read;
273 :
274 0 : subreq = np_write_send(state, req->sconn->ev_ctx, state->handle,
275 0 : state->data, length);
276 0 : if (subreq == NULL) {
277 0 : TALLOC_FREE(state);
278 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
279 0 : return;
280 : }
281 0 : tevent_req_set_callback(subreq, api_dcerpc_cmd_write_done,
282 : talloc_move(conn, &req));
283 : }
284 :
285 0 : static void api_dcerpc_cmd_write_done(struct tevent_req *subreq)
286 : {
287 0 : struct smb_request *req = tevent_req_callback_data(
288 : subreq, struct smb_request);
289 0 : struct dcerpc_cmd_state *state = talloc_get_type_abort(
290 : req->async_priv, struct dcerpc_cmd_state);
291 : NTSTATUS status;
292 0 : ssize_t nwritten = -1;
293 :
294 0 : status = np_write_recv(subreq, &nwritten);
295 0 : TALLOC_FREE(subreq);
296 0 : if (!NT_STATUS_IS_OK(status)) {
297 0 : NTSTATUS old = status;
298 0 : status = nt_status_np_pipe(old);
299 :
300 0 : DEBUG(10, ("Could not write to pipe: %s%s%s\n",
301 : nt_errstr(old),
302 : NT_STATUS_EQUAL(old, status)?"":" => ",
303 : NT_STATUS_EQUAL(old, status)?"":nt_errstr(status)));
304 0 : reply_nterror(req, status);
305 0 : goto send;
306 : }
307 0 : if (nwritten != state->num_data) {
308 0 : status = NT_STATUS_PIPE_NOT_AVAILABLE;
309 0 : DEBUG(10, ("Could not write to pipe: (%d/%d) => %s\n",
310 : (int)state->num_data,
311 : (int)nwritten, nt_errstr(status)));
312 0 : reply_nterror(req, status);
313 0 : goto send;
314 : }
315 :
316 0 : state->data = talloc_realloc(state, state->data, uint8_t,
317 : state->max_read);
318 0 : if (state->data == NULL) {
319 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
320 0 : goto send;
321 : }
322 :
323 0 : subreq = np_read_send(state, req->sconn->ev_ctx,
324 : state->handle, state->data, state->max_read);
325 0 : if (subreq == NULL) {
326 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
327 0 : goto send;
328 : }
329 0 : tevent_req_set_callback(subreq, api_dcerpc_cmd_read_done, req);
330 0 : return;
331 :
332 0 : send:
333 0 : if (!smb1_srv_send(
334 0 : req->xconn, (char *)req->outbuf,
335 0 : true, req->seqnum+1,
336 0 : IS_CONN_ENCRYPTED(req->conn) || req->encrypted,
337 : &req->pcd)) {
338 0 : exit_server_cleanly("api_dcerpc_cmd_write_done: "
339 : "smb1_srv_send failed.");
340 : }
341 0 : TALLOC_FREE(req);
342 : }
343 :
344 0 : static void api_dcerpc_cmd_read_done(struct tevent_req *subreq)
345 : {
346 0 : struct smb_request *req = tevent_req_callback_data(
347 : subreq, struct smb_request);
348 0 : struct dcerpc_cmd_state *state = talloc_get_type_abort(
349 : req->async_priv, struct dcerpc_cmd_state);
350 : NTSTATUS status;
351 : ssize_t nread;
352 : bool is_data_outstanding;
353 :
354 0 : status = np_read_recv(subreq, &nread, &is_data_outstanding);
355 0 : TALLOC_FREE(subreq);
356 :
357 0 : if (!NT_STATUS_IS_OK(status)) {
358 0 : NTSTATUS old = status;
359 0 : status = nt_status_np_pipe(old);
360 :
361 0 : DEBUG(10, ("Could not read from to pipe: %s%s%s\n",
362 : nt_errstr(old),
363 : NT_STATUS_EQUAL(old, status)?"":" => ",
364 : NT_STATUS_EQUAL(old, status)?"":nt_errstr(status)));
365 0 : reply_nterror(req, status);
366 :
367 0 : if (!smb1_srv_send(req->xconn, (char *)req->outbuf,
368 0 : true, req->seqnum+1,
369 0 : IS_CONN_ENCRYPTED(req->conn)
370 0 : ||req->encrypted, &req->pcd)) {
371 0 : exit_server_cleanly("api_dcerpc_cmd_read_done: "
372 : "smb1_srv_send failed.");
373 : }
374 0 : TALLOC_FREE(req);
375 0 : return;
376 : }
377 :
378 0 : send_trans_reply(req->conn, req, NULL, 0, (char *)state->data, nread,
379 : is_data_outstanding);
380 0 : TALLOC_FREE(req);
381 : }
382 :
383 : /****************************************************************************
384 : WaitNamedPipeHandleState
385 : ****************************************************************************/
386 :
387 0 : static void api_WNPHS(connection_struct *conn, struct smb_request *req,
388 : struct files_struct *fsp, char *param, int param_len)
389 : {
390 0 : if (!param || param_len < 2) {
391 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
392 0 : return;
393 : }
394 :
395 0 : DEBUG(4,("WaitNamedPipeHandleState priority %x\n",
396 : (int)SVAL(param,0)));
397 :
398 0 : send_trans_reply(conn, req, NULL, 0, NULL, 0, False);
399 : }
400 :
401 :
402 : /****************************************************************************
403 : SetNamedPipeHandleState
404 : ****************************************************************************/
405 :
406 0 : static void api_SNPHS(connection_struct *conn, struct smb_request *req,
407 : struct files_struct *fsp, char *param, int param_len)
408 : {
409 0 : if (!param || param_len < 2) {
410 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
411 0 : return;
412 : }
413 :
414 0 : DEBUG(4,("SetNamedPipeHandleState to code %x\n", (int)SVAL(param,0)));
415 :
416 0 : send_trans_reply(conn, req, NULL, 0, NULL, 0, False);
417 : }
418 :
419 :
420 : /****************************************************************************
421 : When no reply is generated, indicate unsupported.
422 : ****************************************************************************/
423 :
424 0 : static void api_no_reply(connection_struct *conn, struct smb_request *req)
425 : {
426 : char rparam[4];
427 :
428 : /* unsupported */
429 0 : SSVAL(rparam,0,NERR_notsupported);
430 0 : SSVAL(rparam,2,0); /* converter word */
431 :
432 0 : DEBUG(3,("Unsupported API fd command\n"));
433 :
434 : /* now send the reply */
435 0 : send_trans_reply(conn, req, rparam, 4, NULL, 0, False);
436 :
437 0 : return;
438 : }
439 :
440 : /****************************************************************************
441 : Handle remote api calls delivered to a named pipe already opened.
442 : ****************************************************************************/
443 :
444 0 : static void api_fd_reply(connection_struct *conn, uint64_t vuid,
445 : struct smb_request *req,
446 : uint16_t *setup, uint8_t *data, char *params,
447 : int suwcnt, int tdscnt, int tpscnt,
448 : int mdrcnt, int mprcnt)
449 : {
450 : struct files_struct *fsp;
451 : int pnum;
452 : int subcommand;
453 :
454 0 : DEBUG(5,("api_fd_reply\n"));
455 :
456 : /* First find out the name of this file. */
457 0 : if (suwcnt != 2) {
458 0 : DEBUG(0,("Unexpected named pipe transaction.\n"));
459 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
460 0 : return;
461 : }
462 :
463 : /* Get the file handle and hence the file name. */
464 : /*
465 : * NB. The setup array has already been transformed
466 : * via SVAL and so is in host byte order.
467 : */
468 0 : pnum = ((int)setup[1]) & 0xFFFF;
469 0 : subcommand = ((int)setup[0]) & 0xFFFF;
470 :
471 0 : fsp = file_fsp(req, pnum);
472 :
473 0 : if (!fsp_is_np(fsp)) {
474 0 : if (subcommand == TRANSACT_WAITNAMEDPIPEHANDLESTATE) {
475 : /* Win9x does this call with a unicode pipe name, not a pnum. */
476 : /* Just return success for now... */
477 0 : DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n"));
478 0 : send_trans_reply(conn, req, NULL, 0, NULL, 0, False);
479 0 : return;
480 : }
481 :
482 0 : DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
483 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
484 0 : return;
485 : }
486 :
487 0 : if (vuid != fsp->vuid) {
488 0 : DEBUG(1, ("Got pipe request (pnum %x) using invalid VUID %llu, "
489 : "expected %llu\n", pnum, (unsigned long long)vuid,
490 : (unsigned long long)fsp->vuid));
491 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
492 0 : return;
493 : }
494 :
495 0 : DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n",
496 : subcommand, fsp_str_dbg(fsp), pnum));
497 :
498 0 : DEBUG(10, ("api_fd_reply: p:%p max_trans_reply: %d\n", fsp, mdrcnt));
499 :
500 0 : switch (subcommand) {
501 0 : case TRANSACT_DCERPCCMD: {
502 : /* dce/rpc command */
503 0 : api_dcerpc_cmd(conn, req, fsp, (uint8_t *)data, tdscnt,
504 : mdrcnt);
505 0 : break;
506 : }
507 0 : case TRANSACT_WAITNAMEDPIPEHANDLESTATE:
508 : /* Wait Named Pipe Handle state */
509 0 : api_WNPHS(conn, req, fsp, params, tpscnt);
510 0 : break;
511 0 : case TRANSACT_SETNAMEDPIPEHANDLESTATE:
512 : /* Set Named Pipe Handle state */
513 0 : api_SNPHS(conn, req, fsp, params, tpscnt);
514 0 : break;
515 0 : default:
516 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
517 0 : return;
518 : }
519 : }
520 :
521 : /****************************************************************************
522 : Handle named pipe commands.
523 : ****************************************************************************/
524 :
525 4 : static void named_pipe(connection_struct *conn, uint64_t vuid,
526 : struct smb_request *req,
527 : const char *name, uint16_t *setup,
528 : char *data, char *params,
529 : int suwcnt, int tdscnt,int tpscnt,
530 : int msrcnt, int mdrcnt, int mprcnt)
531 : {
532 4 : DEBUG(3,("named pipe command on <%s> name\n", name));
533 :
534 4 : if (strequal(name,"LANMAN")) {
535 4 : api_reply(conn, vuid, req,
536 : data, params,
537 : tdscnt, tpscnt,
538 : mdrcnt, mprcnt);
539 4 : return;
540 : }
541 :
542 0 : if (strequal(name,"WKSSVC") ||
543 0 : strequal(name,"SRVSVC") ||
544 0 : strequal(name,"WINREG") ||
545 0 : strequal(name,"SAMR") ||
546 0 : strequal(name,"LSARPC")) {
547 :
548 0 : DEBUG(4,("named pipe command from Win95 (wow!)\n"));
549 :
550 0 : api_fd_reply(conn, vuid, req,
551 : setup, (uint8_t *)data, params,
552 : suwcnt, tdscnt, tpscnt,
553 : mdrcnt, mprcnt);
554 0 : return;
555 : }
556 :
557 0 : if (strlen(name) < 1) {
558 0 : api_fd_reply(conn, vuid, req,
559 : setup, (uint8_t *)data,
560 : params, suwcnt, tdscnt,
561 : tpscnt, mdrcnt, mprcnt);
562 0 : return;
563 : }
564 :
565 0 : if (setup)
566 0 : DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n",
567 : (int)setup[0],(int)setup[1]));
568 :
569 0 : reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
570 0 : return;
571 : }
572 :
573 4 : static void handle_trans(connection_struct *conn, struct smb_request *req,
574 : struct trans_state *state)
575 : {
576 : char *local_machine_name;
577 4 : int name_offset = 0;
578 :
579 4 : DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
580 : state->name,(unsigned int)state->total_data,(unsigned int)state->total_param,
581 : (unsigned int)state->setup_count));
582 :
583 : /*
584 : * WinCE wierdness....
585 : */
586 :
587 4 : local_machine_name = talloc_asprintf(state, "\\%s\\",
588 : get_local_machine_name());
589 :
590 4 : if (local_machine_name == NULL) {
591 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
592 0 : return;
593 : }
594 :
595 4 : if (strnequal(state->name, local_machine_name,
596 : strlen(local_machine_name))) {
597 0 : name_offset = strlen(local_machine_name)-1;
598 : }
599 :
600 4 : if (!strnequal(&state->name[name_offset], "\\PIPE",
601 : strlen("\\PIPE"))) {
602 0 : reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
603 0 : return;
604 : }
605 :
606 4 : name_offset += strlen("\\PIPE");
607 :
608 : /* Win9x weirdness. When talking to a unicode server Win9x
609 : only sends \PIPE instead of \PIPE\ */
610 :
611 4 : if (state->name[name_offset] == '\\')
612 4 : name_offset++;
613 :
614 4 : DEBUG(5,("calling named_pipe\n"));
615 18 : named_pipe(conn, state->vuid, req,
616 6 : state->name+name_offset,
617 : state->setup,state->data,
618 : state->param,
619 6 : state->setup_count,state->total_data,
620 4 : state->total_param,
621 4 : state->max_setup_return,
622 4 : state->max_data_return,
623 4 : state->max_param_return);
624 :
625 4 : if (state->close_on_completion) {
626 : struct smbXsrv_tcon *tcon;
627 : NTSTATUS status;
628 :
629 0 : tcon = conn->tcon;
630 0 : req->conn = NULL;
631 0 : conn = NULL;
632 :
633 : /*
634 : * TODO: cancel all outstanding requests on the tcon
635 : */
636 0 : status = smbXsrv_tcon_disconnect(tcon, state->vuid);
637 0 : if (!NT_STATUS_IS_OK(status)) {
638 0 : DEBUG(0, ("handle_trans: "
639 : "smbXsrv_tcon_disconnect() failed: %s\n",
640 : nt_errstr(status)));
641 : /*
642 : * If we hit this case, there is something completely
643 : * wrong, so we better disconnect the transport connection.
644 : */
645 0 : exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
646 : return;
647 : }
648 :
649 0 : TALLOC_FREE(tcon);
650 : }
651 :
652 4 : return;
653 : }
654 :
655 : /****************************************************************************
656 : Reply to a SMBtrans.
657 : ****************************************************************************/
658 :
659 4 : void reply_trans(struct smb_request *req)
660 : {
661 4 : connection_struct *conn = req->conn;
662 : unsigned int dsoff;
663 : unsigned int dscnt;
664 : unsigned int psoff;
665 : unsigned int pscnt;
666 : struct trans_state *state;
667 : NTSTATUS result;
668 :
669 4 : START_PROFILE(SMBtrans);
670 :
671 4 : if (req->wct < 14) {
672 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
673 0 : END_PROFILE(SMBtrans);
674 0 : return;
675 : }
676 :
677 4 : dsoff = SVAL(req->vwv+12, 0);
678 4 : dscnt = SVAL(req->vwv+11, 0);
679 4 : psoff = SVAL(req->vwv+10, 0);
680 4 : pscnt = SVAL(req->vwv+9, 0);
681 :
682 4 : result = allow_new_trans(conn->pending_trans, req->mid);
683 4 : if (!NT_STATUS_IS_OK(result)) {
684 0 : DEBUG(2, ("Got invalid trans request: %s\n",
685 : nt_errstr(result)));
686 0 : reply_nterror(req, result);
687 0 : END_PROFILE(SMBtrans);
688 0 : return;
689 : }
690 :
691 4 : if ((state = talloc_zero(conn, struct trans_state)) == NULL) {
692 0 : DEBUG(0, ("talloc failed\n"));
693 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
694 0 : END_PROFILE(SMBtrans);
695 0 : return;
696 : }
697 :
698 4 : state->cmd = SMBtrans;
699 :
700 4 : state->mid = req->mid;
701 4 : state->vuid = req->vuid;
702 4 : state->setup_count = CVAL(req->vwv+13, 0);
703 4 : state->setup = NULL;
704 4 : state->total_param = SVAL(req->vwv+0, 0);
705 4 : state->param = NULL;
706 4 : state->total_data = SVAL(req->vwv+1, 0);
707 4 : state->data = NULL;
708 4 : state->max_param_return = SVAL(req->vwv+2, 0);
709 4 : state->max_data_return = SVAL(req->vwv+3, 0);
710 4 : state->max_setup_return = CVAL(req->vwv+4, 0);
711 4 : state->close_on_completion = BITSETW(req->vwv+5, 0);
712 4 : state->one_way = BITSETW(req->vwv+5, 1);
713 :
714 4 : srvstr_pull_req_talloc(state, req, &state->name, req->buf,
715 : STR_TERMINATE);
716 :
717 6 : if ((dscnt > state->total_data) || (pscnt > state->total_param) ||
718 4 : !state->name)
719 0 : goto bad_param;
720 :
721 4 : if (state->total_data) {
722 :
723 0 : if (smb_buffer_oob(state->total_data, 0, dscnt)
724 0 : || smb_buffer_oob(smb_len(req->inbuf), dsoff, dscnt)) {
725 0 : goto bad_param;
726 : }
727 :
728 : /* Can't use talloc here, the core routines do realloc on the
729 : * params and data. Out of paranoia, 100 bytes too many. */
730 0 : state->data = (char *)SMB_MALLOC(state->total_data+100);
731 0 : if (state->data == NULL) {
732 0 : DEBUG(0,("reply_trans: data malloc fail for %u "
733 : "bytes !\n", (unsigned int)state->total_data));
734 0 : TALLOC_FREE(state);
735 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
736 0 : END_PROFILE(SMBtrans);
737 0 : return;
738 : }
739 : /* null-terminate the slack space */
740 0 : memset(&state->data[state->total_data], 0, 100);
741 :
742 0 : memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
743 : }
744 :
745 4 : if (state->total_param) {
746 :
747 4 : if (smb_buffer_oob(state->total_param, 0, pscnt)
748 4 : || smb_buffer_oob(smb_len(req->inbuf), psoff, pscnt)) {
749 0 : goto bad_param;
750 : }
751 :
752 : /* Can't use talloc here, the core routines do realloc on the
753 : * params and data. Out of paranoia, 100 bytes too many */
754 4 : state->param = (char *)SMB_MALLOC(state->total_param+100);
755 4 : if (state->param == NULL) {
756 0 : DEBUG(0,("reply_trans: param malloc fail for %u "
757 : "bytes !\n", (unsigned int)state->total_param));
758 0 : SAFE_FREE(state->data);
759 0 : TALLOC_FREE(state);
760 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
761 0 : END_PROFILE(SMBtrans);
762 0 : return;
763 : }
764 : /* null-terminate the slack space */
765 4 : memset(&state->param[state->total_param], 0, 100);
766 :
767 4 : memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
768 : }
769 :
770 4 : state->received_data = dscnt;
771 4 : state->received_param = pscnt;
772 :
773 4 : if (state->setup_count) {
774 : unsigned int i;
775 :
776 : /*
777 : * No overflow possible here, state->setup_count is an
778 : * unsigned int, being filled by a single byte from
779 : * CVAL(req->vwv+13, 0) above. The cast in the comparison
780 : * below is not necessary, it's here to clarify things. The
781 : * validity of req->vwv and req->wct has been checked in
782 : * init_smb1_request already.
783 : */
784 0 : if (state->setup_count + 14 > (unsigned int)req->wct) {
785 0 : goto bad_param;
786 : }
787 :
788 0 : if((state->setup = talloc_array(
789 : state, uint16_t, state->setup_count)) == NULL) {
790 0 : DEBUG(0,("reply_trans: setup malloc fail for %u "
791 : "bytes !\n", (unsigned int)
792 : (state->setup_count * sizeof(uint16_t))));
793 0 : SAFE_FREE(state->data);
794 0 : SAFE_FREE(state->param);
795 0 : TALLOC_FREE(state);
796 0 : reply_nterror(req, NT_STATUS_NO_MEMORY);
797 0 : END_PROFILE(SMBtrans);
798 0 : return;
799 : }
800 :
801 0 : for (i=0;i<state->setup_count;i++) {
802 0 : state->setup[i] = SVAL(req->vwv + 14 + i, 0);
803 : }
804 : }
805 :
806 4 : state->received_param = pscnt;
807 :
808 6 : if ((state->received_param != state->total_param) ||
809 4 : (state->received_data != state->total_data)) {
810 0 : DLIST_ADD(conn->pending_trans, state);
811 :
812 : /* We need to send an interim response then receive the rest
813 : of the parameter/data bytes */
814 0 : reply_smb1_outbuf(req, 0, 0);
815 0 : show_msg((char *)req->outbuf);
816 0 : END_PROFILE(SMBtrans);
817 0 : return;
818 : }
819 :
820 4 : talloc_steal(talloc_tos(), state);
821 :
822 4 : handle_trans(conn, req, state);
823 :
824 4 : SAFE_FREE(state->data);
825 4 : SAFE_FREE(state->param);
826 4 : TALLOC_FREE(state);
827 :
828 4 : END_PROFILE(SMBtrans);
829 4 : return;
830 :
831 0 : bad_param:
832 :
833 0 : DEBUG(0,("reply_trans: invalid trans parameters\n"));
834 0 : SAFE_FREE(state->data);
835 0 : SAFE_FREE(state->param);
836 0 : TALLOC_FREE(state);
837 0 : END_PROFILE(SMBtrans);
838 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
839 0 : return;
840 : }
841 :
842 : /****************************************************************************
843 : Reply to a secondary SMBtrans.
844 : ****************************************************************************/
845 :
846 0 : void reply_transs(struct smb_request *req)
847 : {
848 0 : connection_struct *conn = req->conn;
849 : unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
850 : struct trans_state *state;
851 :
852 0 : START_PROFILE(SMBtranss);
853 :
854 0 : show_msg((const char *)req->inbuf);
855 :
856 0 : if (req->wct < 8) {
857 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
858 0 : END_PROFILE(SMBtranss);
859 0 : return;
860 : }
861 :
862 0 : for (state = conn->pending_trans; state != NULL;
863 0 : state = state->next) {
864 0 : if (state->mid == req->mid) {
865 0 : break;
866 : }
867 : }
868 :
869 0 : if ((state == NULL) || (state->cmd != SMBtrans)) {
870 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
871 0 : END_PROFILE(SMBtranss);
872 0 : return;
873 : }
874 :
875 : /* Revise total_params and total_data in case they have changed
876 : * downwards */
877 :
878 0 : if (SVAL(req->vwv+0, 0) < state->total_param)
879 0 : state->total_param = SVAL(req->vwv+0, 0);
880 0 : if (SVAL(req->vwv+1, 0) < state->total_data)
881 0 : state->total_data = SVAL(req->vwv+1, 0);
882 :
883 0 : pcnt = SVAL(req->vwv+2, 0);
884 0 : poff = SVAL(req->vwv+3, 0);
885 0 : pdisp = SVAL(req->vwv+4, 0);
886 :
887 0 : dcnt = SVAL(req->vwv+5, 0);
888 0 : doff = SVAL(req->vwv+6, 0);
889 0 : ddisp = SVAL(req->vwv+7, 0);
890 :
891 0 : state->received_param += pcnt;
892 0 : state->received_data += dcnt;
893 :
894 0 : if ((state->received_data > state->total_data) ||
895 0 : (state->received_param > state->total_param))
896 0 : goto bad_param;
897 :
898 0 : if (pcnt) {
899 0 : if (smb_buffer_oob(state->total_param, pdisp, pcnt)
900 0 : || smb_buffer_oob(smb_len(req->inbuf), poff, pcnt)) {
901 0 : goto bad_param;
902 : }
903 0 : memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
904 : }
905 :
906 0 : if (dcnt) {
907 0 : if (smb_buffer_oob(state->total_data, ddisp, dcnt)
908 0 : || smb_buffer_oob(smb_len(req->inbuf), doff, dcnt)) {
909 0 : goto bad_param;
910 : }
911 0 : memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
912 : }
913 :
914 0 : if ((state->received_param < state->total_param) ||
915 0 : (state->received_data < state->total_data)) {
916 0 : END_PROFILE(SMBtranss);
917 0 : return;
918 : }
919 :
920 0 : talloc_steal(talloc_tos(), state);
921 :
922 0 : handle_trans(conn, req, state);
923 :
924 0 : DLIST_REMOVE(conn->pending_trans, state);
925 0 : SAFE_FREE(state->data);
926 0 : SAFE_FREE(state->param);
927 0 : TALLOC_FREE(state);
928 :
929 0 : END_PROFILE(SMBtranss);
930 0 : return;
931 :
932 0 : bad_param:
933 :
934 0 : DEBUG(0,("reply_transs: invalid trans parameters\n"));
935 0 : DLIST_REMOVE(conn->pending_trans, state);
936 0 : SAFE_FREE(state->data);
937 0 : SAFE_FREE(state->param);
938 0 : TALLOC_FREE(state);
939 0 : reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
940 0 : END_PROFILE(SMBtranss);
941 0 : return;
942 : }
|