2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
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
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;
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
));
63 memcpy(copy_into
, &rparam
[param_offset
], param_len
);
65 copy_into
+= param_len
+ align
;
68 memcpy(copy_into
, &rdata
[data_offset
], data_len
);
71 /****************************************************************************
73 ****************************************************************************/
75 void send_trans_reply(const char *inbuf
,
81 BOOL buffer_too_large
)
83 int this_ldata
,this_lparam
;
84 int tot_data_sent
= 0;
85 int tot_param_sent
= 0;
88 int ldata
= rdata
? rdata_len
: 0;
89 int lparam
= rparam
? rparam_len
: 0;
92 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata
));
94 this_lparam
= MIN(lparam
,max_send
- 500); /* hack */
95 this_ldata
= MIN(ldata
,max_send
- (500+this_lparam
));
97 align
= ((this_lparam
)%4);
99 if (buffer_too_large
) {
100 ERROR_BOTH(STATUS_BUFFER_OVERFLOW
,ERRDOS
,ERRmoredata
);
103 set_message(inbuf
,outbuf
,10,1+align
+this_ldata
+this_lparam
,True
);
105 copy_trans_params_and_data(outbuf
, align
,
106 rparam
, tot_param_sent
, this_lparam
,
107 rdata
, tot_data_sent
, this_ldata
);
109 SSVAL(outbuf
,smb_vwv0
,lparam
);
110 SSVAL(outbuf
,smb_vwv1
,ldata
);
111 SSVAL(outbuf
,smb_vwv3
,this_lparam
);
112 SSVAL(outbuf
,smb_vwv4
,smb_offset(smb_buf(outbuf
)+1,outbuf
));
113 SSVAL(outbuf
,smb_vwv5
,0);
114 SSVAL(outbuf
,smb_vwv6
,this_ldata
);
115 SSVAL(outbuf
,smb_vwv7
,smb_offset(smb_buf(outbuf
)+1+this_lparam
+align
,outbuf
));
116 SSVAL(outbuf
,smb_vwv8
,0);
117 SSVAL(outbuf
,smb_vwv9
,0);
120 if (!send_smb(smbd_server_fd(),outbuf
))
121 exit_server_cleanly("send_trans_reply: send_smb failed.");
123 tot_data_sent
= this_ldata
;
124 tot_param_sent
= this_lparam
;
126 while (tot_data_sent
< ldata
|| tot_param_sent
< lparam
)
128 this_lparam
= MIN(lparam
-tot_param_sent
, max_send
- 500); /* hack */
129 this_ldata
= MIN(ldata
-tot_data_sent
, max_send
- (500+this_lparam
));
137 align
= (this_lparam
%4);
139 set_message(inbuf
,outbuf
,10,1+this_ldata
+this_lparam
+align
,False
);
141 copy_trans_params_and_data(outbuf
, align
,
142 rparam
, tot_param_sent
, this_lparam
,
143 rdata
, tot_data_sent
, this_ldata
);
145 SSVAL(outbuf
,smb_vwv3
,this_lparam
);
146 SSVAL(outbuf
,smb_vwv4
,smb_offset(smb_buf(outbuf
)+1,outbuf
));
147 SSVAL(outbuf
,smb_vwv5
,tot_param_sent
);
148 SSVAL(outbuf
,smb_vwv6
,this_ldata
);
149 SSVAL(outbuf
,smb_vwv7
,smb_offset(smb_buf(outbuf
)+1+this_lparam
+align
,outbuf
));
150 SSVAL(outbuf
,smb_vwv8
,tot_data_sent
);
151 SSVAL(outbuf
,smb_vwv9
,0);
154 if (!send_smb(smbd_server_fd(),outbuf
))
155 exit_server_cleanly("send_trans_reply: send_smb failed.");
157 tot_data_sent
+= this_ldata
;
158 tot_param_sent
+= this_lparam
;
162 /****************************************************************************
163 Start the first part of an RPC reply which began with an SMBtrans request.
164 ****************************************************************************/
166 static BOOL
api_rpc_trans_reply(const char *inbuf
,
170 BOOL is_data_outstanding
;
171 char *rdata
= (char *)SMB_MALLOC(p
->max_trans_reply
);
175 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
179 if((data_len
= read_from_pipe( p
, rdata
, p
->max_trans_reply
,
180 &is_data_outstanding
)) < 0) {
185 send_trans_reply(inbuf
, outbuf
, NULL
, 0, rdata
, data_len
, is_data_outstanding
);
191 /****************************************************************************
192 WaitNamedPipeHandleState
193 ****************************************************************************/
195 static BOOL
api_WNPHS(const char *inbuf
,
203 if (!param
|| param_len
< 2)
206 priority
= SVAL(param
,0);
207 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority
));
209 if (wait_rpc_pipe_hnd_state(p
, priority
)) {
210 /* now send the reply */
211 send_trans_reply(inbuf
, outbuf
, NULL
, 0, NULL
, 0, False
);
218 /****************************************************************************
219 SetNamedPipeHandleState
220 ****************************************************************************/
222 static BOOL
api_SNPHS(const char *inbuf
,
230 if (!param
|| param_len
< 2)
234 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id
));
236 if (set_rpc_pipe_hnd_state(p
, id
)) {
237 /* now send the reply */
238 send_trans_reply(inbuf
, outbuf
, NULL
, 0, NULL
, 0, False
);
245 /****************************************************************************
246 When no reply is generated, indicate unsupported.
247 ****************************************************************************/
249 static BOOL
api_no_reply(const char *inbuf
, char *outbuf
, int max_rdata_len
)
254 SSVAL(rparam
,0,NERR_notsupported
);
255 SSVAL(rparam
,2,0); /* converter word */
257 DEBUG(3,("Unsupported API fd command\n"));
259 /* now send the reply */
260 send_trans_reply(inbuf
, outbuf
, rparam
, 4, NULL
, 0, False
);
265 /****************************************************************************
266 Handle remote api calls delivered to a named pipe already opened.
267 ****************************************************************************/
269 static int api_fd_reply(connection_struct
*conn
,
283 smb_np_struct
*p
= NULL
;
287 DEBUG(5,("api_fd_reply\n"));
289 /* First find out the name of this file. */
291 DEBUG(0,("Unexpected named pipe transaction.\n"));
292 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
295 /* Get the file handle and hence the file name. */
297 * NB. The setup array has already been transformed
298 * via SVAL and so is in gost byte order.
300 pnum
= ((int)setup
[1]) & 0xFFFF;
301 subcommand
= ((int)setup
[0]) & 0xFFFF;
303 if(!(p
= get_rpc_pipe(pnum
))) {
304 if (subcommand
== TRANSACT_WAITNAMEDPIPEHANDLESTATE
) {
305 /* Win9x does this call with a unicode pipe name, not a pnum. */
306 /* Just return success for now... */
307 DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n"));
308 send_trans_reply(inbuf
, outbuf
, NULL
, 0, NULL
, 0, False
);
312 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum
));
313 return ERROR_NT(NT_STATUS_INVALID_HANDLE
);
316 if (vuid
!= p
->vuid
) {
317 DEBUG(1, ("Got pipe request (pnum %x) using invalid VUID %d, "
318 "expected %d\n", pnum
, vuid
, p
->vuid
));
319 return ERROR_NT(NT_STATUS_INVALID_HANDLE
);
322 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", subcommand
, p
->name
, pnum
));
324 /* record maximum data length that can be transmitted in an SMBtrans */
325 p
->max_trans_reply
= mdrcnt
;
327 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p
, p
->max_trans_reply
));
329 switch (subcommand
) {
330 case TRANSACT_DCERPCCMD
:
331 /* dce/rpc command */
332 reply
= write_to_pipe(p
, data
, tdscnt
);
334 reply
= api_rpc_trans_reply(inbuf
, outbuf
, p
);
336 case TRANSACT_WAITNAMEDPIPEHANDLESTATE
:
337 /* Wait Named Pipe Handle state */
338 reply
= api_WNPHS(inbuf
, outbuf
, p
, params
, tpscnt
);
340 case TRANSACT_SETNAMEDPIPEHANDLESTATE
:
341 /* Set Named Pipe Handle state */
342 reply
= api_SNPHS(inbuf
, outbuf
, p
, params
, tpscnt
);
345 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
349 return api_no_reply(inbuf
, outbuf
, mdrcnt
);
354 /****************************************************************************
355 Handle named pipe commands.
356 ****************************************************************************/
358 static int named_pipe(connection_struct
*conn
,
373 DEBUG(3,("named pipe command on <%s> name\n", name
));
375 if (strequal(name
,"LANMAN")) {
376 return api_reply(conn
,
388 if (strequal(name
,"WKSSVC") ||
389 strequal(name
,"SRVSVC") ||
390 strequal(name
,"WINREG") ||
391 strequal(name
,"SAMR") ||
392 strequal(name
,"LSARPC")) {
393 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
394 return api_fd_reply(conn
,
408 if (strlen(name
) < 1) {
409 return api_fd_reply(conn
,
424 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup
[0],(int)setup
[1]));
429 static NTSTATUS
handle_trans(connection_struct
*conn
,
430 struct trans_state
*state
,
435 char *local_machine_name
;
438 DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
439 state
->name
,(unsigned int)state
->total_data
,(unsigned int)state
->total_param
,
440 (unsigned int)state
->setup_count
));
443 * WinCE wierdness....
446 local_machine_name
= talloc_asprintf(state
, "\\%s\\",
447 get_local_machine_name());
449 if (local_machine_name
== NULL
) {
450 return NT_STATUS_NO_MEMORY
;
453 if (strnequal(state
->name
, local_machine_name
,
454 strlen(local_machine_name
))) {
455 name_offset
= strlen(local_machine_name
)-1;
458 if (!strnequal(&state
->name
[name_offset
], "\\PIPE",
460 return NT_STATUS_NOT_SUPPORTED
;
463 name_offset
+= strlen("\\PIPE");
465 /* Win9x weirdness. When talking to a unicode server Win9x
466 only sends \PIPE instead of \PIPE\ */
468 if (state
->name
[name_offset
] == '\\')
471 DEBUG(5,("calling named_pipe\n"));
472 *outsize
= named_pipe(conn
,
476 state
->name
+name_offset
,
477 state
->setup
,state
->data
,
479 state
->setup_count
,state
->total_data
,
481 state
->max_setup_return
,
482 state
->max_data_return
,
483 state
->max_param_return
);
486 return NT_STATUS_NOT_SUPPORTED
;
489 if (state
->close_on_completion
)
490 close_cnum(conn
,state
->vuid
);
495 /****************************************************************************
497 ****************************************************************************/
499 int reply_trans(connection_struct
*conn
,
506 unsigned int dsoff
= SVAL(inbuf
, smb_dsoff
);
507 unsigned int dscnt
= SVAL(inbuf
, smb_dscnt
);
508 unsigned int psoff
= SVAL(inbuf
, smb_psoff
);
509 unsigned int pscnt
= SVAL(inbuf
, smb_pscnt
);
510 struct trans_state
*state
;
513 START_PROFILE(SMBtrans
);
515 result
= allow_new_trans(conn
->pending_trans
, SVAL(inbuf
, smb_mid
));
516 if (!NT_STATUS_IS_OK(result
)) {
517 DEBUG(2, ("Got invalid trans request: %s\n",
519 END_PROFILE(SMBtrans
);
520 return ERROR_NT(result
);
523 if ((state
= TALLOC_P(conn
->mem_ctx
, struct trans_state
)) == NULL
) {
524 DEBUG(0, ("talloc failed\n"));
525 END_PROFILE(SMBtrans
);
526 return ERROR_NT(NT_STATUS_NO_MEMORY
);
529 state
->cmd
= SMBtrans
;
531 state
->mid
= SVAL(inbuf
, smb_mid
);
532 state
->vuid
= SVAL(inbuf
, smb_uid
);
533 state
->setup_count
= CVAL(inbuf
, smb_suwcnt
);
535 state
->total_param
= SVAL(inbuf
, smb_tpscnt
);
537 state
->total_data
= SVAL(inbuf
, smb_tdscnt
);
539 state
->max_param_return
= SVAL(inbuf
, smb_mprcnt
);
540 state
->max_data_return
= SVAL(inbuf
, smb_mdrcnt
);
541 state
->max_setup_return
= CVAL(inbuf
, smb_msrcnt
);
542 state
->close_on_completion
= BITSETW(inbuf
+smb_vwv5
,0);
543 state
->one_way
= BITSETW(inbuf
+smb_vwv5
,1);
545 memset(state
->name
, '\0',sizeof(state
->name
));
546 srvstr_pull_buf(inbuf
, state
->name
, smb_buf(inbuf
),
547 sizeof(state
->name
), STR_TERMINATE
);
549 if ((dscnt
> state
->total_data
) || (pscnt
> state
->total_param
))
552 if (state
->total_data
) {
553 /* Can't use talloc here, the core routines do realloc on the
554 * params and data. Out of paranoia, 100 bytes too many. */
555 state
->data
= (char *)SMB_MALLOC(state
->total_data
+100);
556 if (state
->data
== NULL
) {
557 DEBUG(0,("reply_trans: data malloc fail for %u "
558 "bytes !\n", (unsigned int)state
->total_data
));
560 END_PROFILE(SMBtrans
);
561 return(ERROR_DOS(ERRDOS
,ERRnomem
));
563 /* null-terminate the slack space */
564 memset(&state
->data
[state
->total_data
], 0, 100);
565 if ((dsoff
+dscnt
< dsoff
) || (dsoff
+dscnt
< dscnt
))
567 if ((smb_base(inbuf
)+dsoff
+dscnt
> inbuf
+ size
) ||
568 (smb_base(inbuf
)+dsoff
+dscnt
< smb_base(inbuf
)))
571 memcpy(state
->data
,smb_base(inbuf
)+dsoff
,dscnt
);
574 if (state
->total_param
) {
575 /* Can't use talloc here, the core routines do realloc on the
576 * params and data. Out of paranoia, 100 bytes too many */
577 state
->param
= (char *)SMB_MALLOC(state
->total_param
+100);
578 if (state
->param
== NULL
) {
579 DEBUG(0,("reply_trans: param malloc fail for %u "
580 "bytes !\n", (unsigned int)state
->total_param
));
581 SAFE_FREE(state
->data
);
583 END_PROFILE(SMBtrans
);
584 return(ERROR_DOS(ERRDOS
,ERRnomem
));
586 /* null-terminate the slack space */
587 memset(&state
->param
[state
->total_param
], 0, 100);
588 if ((psoff
+pscnt
< psoff
) || (psoff
+pscnt
< pscnt
))
590 if ((smb_base(inbuf
)+psoff
+pscnt
> inbuf
+ size
) ||
591 (smb_base(inbuf
)+psoff
+pscnt
< smb_base(inbuf
)))
594 memcpy(state
->param
,smb_base(inbuf
)+psoff
,pscnt
);
597 state
->received_data
= dscnt
;
598 state
->received_param
= pscnt
;
600 if (state
->setup_count
) {
602 if((state
->setup
= TALLOC_ARRAY(
603 state
, uint16
, state
->setup_count
)) == NULL
) {
604 DEBUG(0,("reply_trans: setup malloc fail for %u "
605 "bytes !\n", (unsigned int)
606 (state
->setup_count
* sizeof(uint16
))));
608 END_PROFILE(SMBtrans
);
609 return(ERROR_DOS(ERRDOS
,ERRnomem
));
611 if (inbuf
+smb_vwv14
+(state
->setup_count
*SIZEOFWORD
) >
614 if ((smb_vwv14
+(state
->setup_count
*SIZEOFWORD
) < smb_vwv14
) ||
615 (smb_vwv14
+(state
->setup_count
*SIZEOFWORD
) <
616 (state
->setup_count
*SIZEOFWORD
)))
619 for (i
=0;i
<state
->setup_count
;i
++)
620 state
->setup
[i
] = SVAL(inbuf
,smb_vwv14
+i
*SIZEOFWORD
);
623 state
->received_param
= pscnt
;
625 if ((state
->received_param
== state
->total_param
) &&
626 (state
->received_data
== state
->total_data
)) {
628 result
= handle_trans(conn
, state
, inbuf
, outbuf
, &outsize
);
630 SAFE_FREE(state
->data
);
631 SAFE_FREE(state
->param
);
634 if (!NT_STATUS_IS_OK(result
)) {
635 END_PROFILE(SMBtrans
);
636 return ERROR_NT(result
);
640 END_PROFILE(SMBtrans
);
641 return ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
644 END_PROFILE(SMBtrans
);
648 DLIST_ADD(conn
->pending_trans
, state
);
650 /* We need to send an interim response then receive the rest
651 of the parameter/data bytes */
652 outsize
= set_message(inbuf
,outbuf
,0,0,True
);
654 END_PROFILE(SMBtrans
);
659 DEBUG(0,("reply_trans: invalid trans parameters\n"));
660 SAFE_FREE(state
->data
);
661 SAFE_FREE(state
->param
);
663 END_PROFILE(SMBtrans
);
664 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
667 /****************************************************************************
668 Reply to a secondary SMBtrans.
669 ****************************************************************************/
671 int reply_transs(connection_struct
*conn
, char *inbuf
,char *outbuf
,
672 int size
, int bufsize
)
675 unsigned int pcnt
,poff
,dcnt
,doff
,pdisp
,ddisp
;
676 struct trans_state
*state
;
679 START_PROFILE(SMBtranss
);
683 for (state
= conn
->pending_trans
; state
!= NULL
;
684 state
= state
->next
) {
685 if (state
->mid
== SVAL(inbuf
,smb_mid
)) {
690 if ((state
== NULL
) || (state
->cmd
!= SMBtrans
)) {
691 END_PROFILE(SMBtranss
);
692 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
695 /* Revise total_params and total_data in case they have changed
698 if (SVAL(inbuf
, smb_vwv0
) < state
->total_param
)
699 state
->total_param
= SVAL(inbuf
,smb_vwv0
);
700 if (SVAL(inbuf
, smb_vwv1
) < state
->total_data
)
701 state
->total_data
= SVAL(inbuf
,smb_vwv1
);
703 pcnt
= SVAL(inbuf
, smb_spscnt
);
704 poff
= SVAL(inbuf
, smb_spsoff
);
705 pdisp
= SVAL(inbuf
, smb_spsdisp
);
707 dcnt
= SVAL(inbuf
, smb_sdscnt
);
708 doff
= SVAL(inbuf
, smb_sdsoff
);
709 ddisp
= SVAL(inbuf
, smb_sdsdisp
);
711 state
->received_param
+= pcnt
;
712 state
->received_data
+= dcnt
;
714 if ((state
->received_data
> state
->total_data
) ||
715 (state
->received_param
> state
->total_param
))
719 if (pdisp
+pcnt
> state
->total_param
)
721 if ((pdisp
+pcnt
< pdisp
) || (pdisp
+pcnt
< pcnt
))
723 if (pdisp
> state
->total_param
)
725 if ((smb_base(inbuf
) + poff
+ pcnt
> inbuf
+ size
) ||
726 (smb_base(inbuf
) + poff
+ pcnt
< smb_base(inbuf
)))
728 if (state
->param
+ pdisp
< state
->param
)
731 memcpy(state
->param
+pdisp
,smb_base(inbuf
)+poff
,
736 if (ddisp
+dcnt
> state
->total_data
)
738 if ((ddisp
+dcnt
< ddisp
) || (ddisp
+dcnt
< dcnt
))
740 if (ddisp
> state
->total_data
)
742 if ((smb_base(inbuf
) + doff
+ dcnt
> inbuf
+ size
) ||
743 (smb_base(inbuf
) + doff
+ dcnt
< smb_base(inbuf
)))
745 if (state
->data
+ ddisp
< state
->data
)
748 memcpy(state
->data
+ddisp
, smb_base(inbuf
)+doff
,
752 if ((state
->received_param
< state
->total_param
) ||
753 (state
->received_data
< state
->total_data
)) {
754 END_PROFILE(SMBtranss
);
758 /* construct_reply_common has done us the favor to pre-fill the
759 * command field with SMBtranss which is wrong :-)
761 SCVAL(outbuf
,smb_com
,SMBtrans
);
763 result
= handle_trans(conn
, state
, inbuf
, outbuf
, &outsize
);
765 DLIST_REMOVE(conn
->pending_trans
, state
);
766 SAFE_FREE(state
->data
);
767 SAFE_FREE(state
->param
);
770 if ((outsize
== 0) || !NT_STATUS_IS_OK(result
)) {
771 END_PROFILE(SMBtranss
);
772 return(ERROR_DOS(ERRSRV
,ERRnosupport
));
775 END_PROFILE(SMBtranss
);
780 DEBUG(0,("reply_transs: invalid trans parameters\n"));
781 DLIST_REMOVE(conn
->pending_trans
, state
);
782 SAFE_FREE(state
->data
);
783 SAFE_FREE(state
->param
);
785 END_PROFILE(SMBtranss
);
786 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);