r15556: Better fix for leading // or \\ from "David R. Linn"
[Samba/nascimento.git] / source3 / smbd / ipc.c
blob7f9505606ccdb99bbc0e854682eeedaccd7485ab
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 SMB Version handling
7 Copyright (C) John H Terpstra 1995-1998
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 2 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
30 extern int max_send;
32 #define NERR_notsupported 50
34 extern int smb_read_error;
36 /*******************************************************************
37 copies parameters and data, as needed, into the smb buffer
39 *both* the data and params sections should be aligned. this
40 is fudged in the rpc pipes by
41 at present, only the data section is. this may be a possible
42 cause of some of the ipc problems being experienced. lkcl26dec97
44 ******************************************************************/
46 static void copy_trans_params_and_data(char *outbuf, int align,
47 char *rparam, int param_offset, int param_len,
48 char *rdata, int data_offset, int data_len)
50 char *copy_into = smb_buf(outbuf)+1;
52 if(param_len < 0)
53 param_len = 0;
55 if(data_len < 0)
56 data_len = 0;
58 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
59 param_offset, param_offset + param_len,
60 data_offset , data_offset + data_len));
62 if (param_len)
63 memcpy(copy_into, &rparam[param_offset], param_len);
65 copy_into += param_len + align;
67 if (data_len )
68 memcpy(copy_into, &rdata[data_offset], data_len);
71 /****************************************************************************
72 Send a trans reply.
73 ****************************************************************************/
75 void send_trans_reply(char *outbuf,
76 char *rparam, int rparam_len,
77 char *rdata, int rdata_len,
78 BOOL buffer_too_large)
80 int this_ldata,this_lparam;
81 int tot_data_sent = 0;
82 int tot_param_sent = 0;
83 int align;
85 int ldata = rdata ? rdata_len : 0;
86 int lparam = rparam ? rparam_len : 0;
88 if (buffer_too_large)
89 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
91 this_lparam = MIN(lparam,max_send - 500); /* hack */
92 this_ldata = MIN(ldata,max_send - (500+this_lparam));
94 align = ((this_lparam)%4);
96 if (buffer_too_large) {
97 ERROR_BOTH(STATUS_BUFFER_OVERFLOW,ERRDOS,ERRmoredata);
100 set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
102 copy_trans_params_and_data(outbuf, align,
103 rparam, tot_param_sent, this_lparam,
104 rdata, tot_data_sent, this_ldata);
106 SSVAL(outbuf,smb_vwv0,lparam);
107 SSVAL(outbuf,smb_vwv1,ldata);
108 SSVAL(outbuf,smb_vwv3,this_lparam);
109 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
110 SSVAL(outbuf,smb_vwv5,0);
111 SSVAL(outbuf,smb_vwv6,this_ldata);
112 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
113 SSVAL(outbuf,smb_vwv8,0);
114 SSVAL(outbuf,smb_vwv9,0);
116 show_msg(outbuf);
117 if (!send_smb(smbd_server_fd(),outbuf))
118 exit_server("send_trans_reply: send_smb failed.");
120 tot_data_sent = this_ldata;
121 tot_param_sent = this_lparam;
123 while (tot_data_sent < ldata || tot_param_sent < lparam)
125 this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
126 this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
128 if(this_lparam < 0)
129 this_lparam = 0;
131 if(this_ldata < 0)
132 this_ldata = 0;
134 align = (this_lparam%4);
136 set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
138 copy_trans_params_and_data(outbuf, align,
139 rparam, tot_param_sent, this_lparam,
140 rdata, tot_data_sent, this_ldata);
142 SSVAL(outbuf,smb_vwv3,this_lparam);
143 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
144 SSVAL(outbuf,smb_vwv5,tot_param_sent);
145 SSVAL(outbuf,smb_vwv6,this_ldata);
146 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
147 SSVAL(outbuf,smb_vwv8,tot_data_sent);
148 SSVAL(outbuf,smb_vwv9,0);
150 show_msg(outbuf);
151 if (!send_smb(smbd_server_fd(),outbuf))
152 exit_server("send_trans_reply: send_smb failed.");
154 tot_data_sent += this_ldata;
155 tot_param_sent += this_lparam;
159 /****************************************************************************
160 Start the first part of an RPC reply which began with an SMBtrans request.
161 ****************************************************************************/
163 static BOOL api_rpc_trans_reply(char *outbuf, smb_np_struct *p)
165 BOOL is_data_outstanding;
166 char *rdata = (char *)SMB_MALLOC(p->max_trans_reply);
167 int data_len;
169 if(rdata == NULL) {
170 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
171 return False;
174 if((data_len = read_from_pipe( p, rdata, p->max_trans_reply,
175 &is_data_outstanding)) < 0) {
176 SAFE_FREE(rdata);
177 return False;
180 send_trans_reply(outbuf, NULL, 0, rdata, data_len, is_data_outstanding);
182 SAFE_FREE(rdata);
183 return True;
186 /****************************************************************************
187 WaitNamedPipeHandleState
188 ****************************************************************************/
190 static BOOL api_WNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len)
192 uint16 priority;
194 if (!param || param_len < 2)
195 return False;
197 priority = SVAL(param,0);
198 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
200 if (wait_rpc_pipe_hnd_state(p, priority)) {
201 /* now send the reply */
202 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
203 return True;
205 return False;
209 /****************************************************************************
210 SetNamedPipeHandleState
211 ****************************************************************************/
213 static BOOL api_SNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len)
215 uint16 id;
217 if (!param || param_len < 2)
218 return False;
220 id = SVAL(param,0);
221 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
223 if (set_rpc_pipe_hnd_state(p, id)) {
224 /* now send the reply */
225 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
226 return True;
228 return False;
232 /****************************************************************************
233 When no reply is generated, indicate unsupported.
234 ****************************************************************************/
236 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
238 char rparam[4];
240 /* unsupported */
241 SSVAL(rparam,0,NERR_notsupported);
242 SSVAL(rparam,2,0); /* converter word */
244 DEBUG(3,("Unsupported API fd command\n"));
246 /* now send the reply */
247 send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
249 return -1;
252 /****************************************************************************
253 Handle remote api calls delivered to a named pipe already opened.
254 ****************************************************************************/
256 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
257 uint16 *setup,char *data,char *params,
258 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
260 BOOL reply = False;
261 smb_np_struct *p = NULL;
262 int pnum;
263 int subcommand;
265 DEBUG(5,("api_fd_reply\n"));
267 /* First find out the name of this file. */
268 if (suwcnt != 2) {
269 DEBUG(0,("Unexpected named pipe transaction.\n"));
270 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
273 /* Get the file handle and hence the file name. */
275 * NB. The setup array has already been transformed
276 * via SVAL and so is in gost byte order.
278 pnum = ((int)setup[1]) & 0xFFFF;
279 subcommand = ((int)setup[0]) & 0xFFFF;
281 if(!(p = get_rpc_pipe(pnum))) {
282 if (subcommand == TRANSACT_WAITNAMEDPIPEHANDLESTATE) {
283 /* Win9x does this call with a unicode pipe name, not a pnum. */
284 /* Just return success for now... */
285 DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n"));
286 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
287 return -1;
290 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
291 return ERROR_NT(NT_STATUS_INVALID_HANDLE);
294 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", subcommand, p->name, pnum));
296 /* record maximum data length that can be transmitted in an SMBtrans */
297 p->max_trans_reply = mdrcnt;
299 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
301 switch (subcommand) {
302 case TRANSACT_DCERPCCMD:
303 /* dce/rpc command */
304 reply = write_to_pipe(p, data, tdscnt);
305 if (reply)
306 reply = api_rpc_trans_reply(outbuf, p);
307 break;
308 case TRANSACT_WAITNAMEDPIPEHANDLESTATE:
309 /* Wait Named Pipe Handle state */
310 reply = api_WNPHS(outbuf, p, params, tpscnt);
311 break;
312 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
313 /* Set Named Pipe Handle state */
314 reply = api_SNPHS(outbuf, p, params, tpscnt);
315 break;
316 default:
317 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
320 if (!reply)
321 return api_no_reply(outbuf, mdrcnt);
323 return -1;
326 /****************************************************************************
327 handle named pipe commands
328 ****************************************************************************/
329 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
330 uint16 *setup,char *data,char *params,
331 int suwcnt,int tdscnt,int tpscnt,
332 int msrcnt,int mdrcnt,int mprcnt)
334 DEBUG(3,("named pipe command on <%s> name\n", name));
336 if (strequal(name,"LANMAN"))
337 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
339 if (strequal(name,"WKSSVC") ||
340 strequal(name,"SRVSVC") ||
341 strequal(name,"WINREG") ||
342 strequal(name,"SAMR") ||
343 strequal(name,"LSARPC"))
345 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
346 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
349 if (strlen(name) < 1)
350 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
352 if (setup)
353 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
355 return 0;
358 static NTSTATUS handle_trans(connection_struct *conn,
359 struct trans_state *state,
360 char *outbuf, int *outsize)
362 char *local_machine_name;
363 int name_offset = 0;
365 DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
366 state->name,state->total_data,state->total_param,
367 state->setup_count));
370 * WinCE wierdness....
373 local_machine_name = talloc_asprintf(state, "\\%s\\",
374 get_local_machine_name());
376 if (local_machine_name == NULL) {
377 return NT_STATUS_NO_MEMORY;
380 if (strnequal(state->name, local_machine_name,
381 strlen(local_machine_name))) {
382 name_offset = strlen(local_machine_name)-1;
385 if (!strnequal(&state->name[name_offset], "\\PIPE",
386 strlen("\\PIPE"))) {
387 return NT_STATUS_NOT_SUPPORTED;
390 name_offset += strlen("\\PIPE");
392 /* Win9x weirdness. When talking to a unicode server Win9x
393 only sends \PIPE instead of \PIPE\ */
395 if (state->name[name_offset] == '\\')
396 name_offset++;
398 DEBUG(5,("calling named_pipe\n"));
399 *outsize = named_pipe(conn, state->vuid, outbuf,
400 state->name+name_offset,
401 state->setup,state->data,
402 state->param,
403 state->setup_count,state->total_data,
404 state->total_param,
405 state->max_setup_return,
406 state->max_data_return,
407 state->max_param_return);
409 if (*outsize == 0) {
410 return NT_STATUS_NOT_SUPPORTED;
413 if (state->close_on_completion)
414 close_cnum(conn,state->vuid);
416 return NT_STATUS_OK;
419 /****************************************************************************
420 Reply to a SMBtrans.
421 ****************************************************************************/
423 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf,
424 int size, int bufsize)
426 int outsize = 0;
427 unsigned int dsoff = SVAL(inbuf, smb_dsoff);
428 unsigned int dscnt = SVAL(inbuf, smb_dscnt);
429 unsigned int psoff = SVAL(inbuf, smb_psoff);
430 unsigned int pscnt = SVAL(inbuf, smb_pscnt);
431 struct trans_state *state;
432 NTSTATUS result;
434 START_PROFILE(SMBtrans);
436 result = allow_new_trans(conn->pending_trans, SVAL(inbuf, smb_mid));
437 if (!NT_STATUS_IS_OK(result)) {
438 DEBUG(2, ("Got invalid trans request: %s\n",
439 nt_errstr(result)));
440 END_PROFILE(SMBtrans);
441 return ERROR_NT(result);
444 if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
445 DEBUG(0, ("talloc failed\n"));
446 END_PROFILE(SMBtrans);
447 return ERROR_NT(NT_STATUS_NO_MEMORY);
450 state->cmd = SMBtrans;
452 state->mid = SVAL(inbuf, smb_mid);
453 state->vuid = SVAL(inbuf, smb_uid);
454 state->setup_count = CVAL(inbuf, smb_suwcnt);
455 state->total_param = SVAL(inbuf, smb_tpscnt);
456 state->param = NULL;
457 state->total_data = SVAL(inbuf, smb_tdscnt);
458 state->data = NULL;
459 state->max_param_return = SVAL(inbuf, smb_mprcnt);
460 state->max_data_return = SVAL(inbuf, smb_mdrcnt);
461 state->max_setup_return = CVAL(inbuf, smb_msrcnt);
462 state->close_on_completion = BITSETW(inbuf+smb_vwv5,0);
463 state->one_way = BITSETW(inbuf+smb_vwv5,1);
465 memset(state->name, '\0',sizeof(state->name));
466 srvstr_pull_buf(inbuf, state->name, smb_buf(inbuf),
467 sizeof(state->name), STR_TERMINATE);
469 if ((dscnt > state->total_data) || (pscnt > state->total_param))
470 goto bad_param;
472 if (state->total_data) {
473 /* Can't use talloc here, the core routines do realloc on the
474 * params and data. */
475 state->data = SMB_MALLOC(state->total_data);
476 if (state->data == NULL) {
477 DEBUG(0,("reply_trans: data malloc fail for %u "
478 "bytes !\n", state->total_data));
479 TALLOC_FREE(state);
480 END_PROFILE(SMBtrans);
481 return(ERROR_DOS(ERRDOS,ERRnomem));
483 if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
484 goto bad_param;
485 if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
486 (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
487 goto bad_param;
489 memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
492 if (state->total_param) {
493 /* Can't use talloc here, the core routines do realloc on the
494 * params and data. */
495 state->param = SMB_MALLOC(state->total_param);
496 if (state->param == NULL) {
497 DEBUG(0,("reply_trans: param malloc fail for %u "
498 "bytes !\n", state->total_param));
499 SAFE_FREE(state->data);
500 TALLOC_FREE(state);
501 END_PROFILE(SMBtrans);
502 return(ERROR_DOS(ERRDOS,ERRnomem));
504 if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
505 goto bad_param;
506 if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
507 (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
508 goto bad_param;
510 memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
513 state->received_data = dscnt;
514 state->received_param = pscnt;
516 if (state->setup_count) {
517 unsigned int i;
518 if((state->setup = TALLOC_ARRAY(
519 state, uint16, state->setup_count)) == NULL) {
520 DEBUG(0,("reply_trans: setup malloc fail for %u "
521 "bytes !\n", (unsigned int)
522 (state->setup_count * sizeof(uint16))));
523 TALLOC_FREE(state);
524 END_PROFILE(SMBtrans);
525 return(ERROR_DOS(ERRDOS,ERRnomem));
527 if (inbuf+smb_vwv14+(state->setup_count*SIZEOFWORD) >
528 inbuf + size)
529 goto bad_param;
530 if ((smb_vwv14+(state->setup_count*SIZEOFWORD) < smb_vwv14) ||
531 (smb_vwv14+(state->setup_count*SIZEOFWORD) <
532 (state->setup_count*SIZEOFWORD)))
533 goto bad_param;
535 for (i=0;i<state->setup_count;i++)
536 state->setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
539 state->received_param = pscnt;
541 if ((state->received_param == state->total_param) &&
542 (state->received_data == state->total_data)) {
544 result = handle_trans(conn, state, outbuf, &outsize);
546 SAFE_FREE(state->data);
547 SAFE_FREE(state->param);
548 TALLOC_FREE(state);
550 if (!NT_STATUS_IS_OK(result)) {
551 END_PROFILE(SMBtrans);
552 return ERROR_NT(result);
555 if (outsize == 0) {
556 END_PROFILE(SMBtrans);
557 return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
560 END_PROFILE(SMBtrans);
561 return outsize;
564 DLIST_ADD(conn->pending_trans, state);
566 /* We need to send an interim response then receive the rest
567 of the parameter/data bytes */
568 outsize = set_message(outbuf,0,0,True);
569 show_msg(outbuf);
570 END_PROFILE(SMBtrans);
571 return outsize;
573 bad_param:
575 DEBUG(0,("reply_trans: invalid trans parameters\n"));
576 SAFE_FREE(state->data);
577 SAFE_FREE(state->param);
578 TALLOC_FREE(state);
579 END_PROFILE(SMBtrans);
580 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
583 /****************************************************************************
584 Reply to a secondary SMBtrans.
585 ****************************************************************************/
587 int reply_transs(connection_struct *conn, char *inbuf,char *outbuf,
588 int size, int bufsize)
590 int outsize = 0;
591 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
592 struct trans_state *state;
593 NTSTATUS result;
595 START_PROFILE(SMBtranss);
597 show_msg(inbuf);
599 for (state = conn->pending_trans; state != NULL;
600 state = state->next) {
601 if (state->mid == SVAL(inbuf,smb_mid)) {
602 break;
606 if ((state == NULL) || (state->cmd != SMBtrans)) {
607 END_PROFILE(SMBtranss);
608 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
611 /* Revise total_params and total_data in case they have changed
612 * downwards */
614 if (SVAL(inbuf, smb_vwv0) < state->total_param)
615 state->total_param = SVAL(inbuf,smb_vwv0);
616 if (SVAL(inbuf, smb_vwv1) < state->total_data)
617 state->total_data = SVAL(inbuf,smb_vwv1);
619 pcnt = SVAL(inbuf, smb_spscnt);
620 poff = SVAL(inbuf, smb_spsoff);
621 pdisp = SVAL(inbuf, smb_spsdisp);
623 dcnt = SVAL(inbuf, smb_sdscnt);
624 doff = SVAL(inbuf, smb_sdsoff);
625 ddisp = SVAL(inbuf, smb_sdsdisp);
627 state->received_param += pcnt;
628 state->received_data += dcnt;
630 if ((state->received_data > state->total_data) ||
631 (state->received_param > state->total_param))
632 goto bad_param;
634 if (pcnt) {
635 if (pdisp+pcnt > state->total_param)
636 goto bad_param;
637 if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
638 goto bad_param;
639 if (pdisp > state->total_param)
640 goto bad_param;
641 if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
642 (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
643 goto bad_param;
644 if (state->param + pdisp < state->param)
645 goto bad_param;
647 memcpy(state->param+pdisp,smb_base(inbuf)+poff,
648 pcnt);
651 if (dcnt) {
652 if (ddisp+dcnt > state->total_data)
653 goto bad_param;
654 if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
655 goto bad_param;
656 if (ddisp > state->total_data)
657 goto bad_param;
658 if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
659 (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
660 goto bad_param;
661 if (state->data + ddisp < state->data)
662 goto bad_param;
664 memcpy(state->data+ddisp, smb_base(inbuf)+doff,
665 dcnt);
668 if ((state->received_param < state->total_param) ||
669 (state->received_data < state->total_data)) {
670 END_PROFILE(SMBtranss);
671 return -1;
674 /* construct_reply_common has done us the favor to pre-fill the
675 * command field with SMBtranss which is wrong :-)
677 SCVAL(outbuf,smb_com,SMBtrans);
679 result = handle_trans(conn, state, outbuf, &outsize);
681 DLIST_REMOVE(conn->pending_trans, state);
682 SAFE_FREE(state->data);
683 SAFE_FREE(state->param);
684 TALLOC_FREE(state);
686 if ((outsize == 0) || !NT_STATUS_IS_OK(result)) {
687 END_PROFILE(SMBtranss);
688 return(ERROR_DOS(ERRSRV,ERRnosupport));
691 END_PROFILE(SMBtranss);
692 return(outsize);
694 bad_param:
696 DEBUG(0,("reply_transs: invalid trans parameters\n"));
697 DLIST_REMOVE(conn->pending_trans, state);
698 SAFE_FREE(state->data);
699 SAFE_FREE(state->param);
700 TALLOC_FREE(state);
701 END_PROFILE(SMBtranss);
702 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);