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(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;
85 int ldata
= rdata
? rdata_len
: 0;
86 int lparam
= rparam
? rparam_len
: 0;
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);
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
));
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);
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
);
170 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
174 if((data_len
= read_from_pipe( p
, rdata
, p
->max_trans_reply
,
175 &is_data_outstanding
)) < 0) {
180 send_trans_reply(outbuf
, NULL
, 0, rdata
, data_len
, is_data_outstanding
);
186 /****************************************************************************
187 WaitNamedPipeHandleState
188 ****************************************************************************/
190 static BOOL
api_WNPHS(char *outbuf
, smb_np_struct
*p
, char *param
, int param_len
)
194 if (!param
|| param_len
< 2)
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
);
209 /****************************************************************************
210 SetNamedPipeHandleState
211 ****************************************************************************/
213 static BOOL
api_SNPHS(char *outbuf
, smb_np_struct
*p
, char *param
, int param_len
)
217 if (!param
|| param_len
< 2)
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
);
232 /****************************************************************************
233 When no reply is generated, indicate unsupported.
234 ****************************************************************************/
236 static BOOL
api_no_reply(char *outbuf
, int max_rdata_len
)
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
);
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
)
261 smb_np_struct
*p
= NULL
;
265 DEBUG(5,("api_fd_reply\n"));
267 /* First find out the name of this file. */
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
);
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
);
306 reply
= api_rpc_trans_reply(outbuf
, p
);
308 case TRANSACT_WAITNAMEDPIPEHANDLESTATE
:
309 /* Wait Named Pipe Handle state */
310 reply
= api_WNPHS(outbuf
, p
, params
, tpscnt
);
312 case TRANSACT_SETNAMEDPIPEHANDLESTATE
:
313 /* Set Named Pipe Handle state */
314 reply
= api_SNPHS(outbuf
, p
, params
, tpscnt
);
317 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
321 return api_no_reply(outbuf
, mdrcnt
);
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
);
353 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup
[0],(int)setup
[1]));
358 static NTSTATUS
handle_trans(connection_struct
*conn
,
359 struct trans_state
*state
,
360 char *outbuf
, int *outsize
)
362 char *local_machine_name
;
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",
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
] == '\\')
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
,
403 state
->setup_count
,state
->total_data
,
405 state
->max_setup_return
,
406 state
->max_data_return
,
407 state
->max_param_return
);
410 return NT_STATUS_NOT_SUPPORTED
;
413 if (state
->close_on_completion
)
414 close_cnum(conn
,state
->vuid
);
419 /****************************************************************************
421 ****************************************************************************/
423 int reply_trans(connection_struct
*conn
, char *inbuf
,char *outbuf
,
424 int size
, int bufsize
)
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
;
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",
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
);
457 state
->total_data
= SVAL(inbuf
, smb_tdscnt
);
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
))
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
));
480 END_PROFILE(SMBtrans
);
481 return(ERROR_DOS(ERRDOS
,ERRnomem
));
483 if ((dsoff
+dscnt
< dsoff
) || (dsoff
+dscnt
< dscnt
))
485 if ((smb_base(inbuf
)+dsoff
+dscnt
> inbuf
+ size
) ||
486 (smb_base(inbuf
)+dsoff
+dscnt
< smb_base(inbuf
)))
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
);
501 END_PROFILE(SMBtrans
);
502 return(ERROR_DOS(ERRDOS
,ERRnomem
));
504 if ((psoff
+pscnt
< psoff
) || (psoff
+pscnt
< pscnt
))
506 if ((smb_base(inbuf
)+psoff
+pscnt
> inbuf
+ size
) ||
507 (smb_base(inbuf
)+psoff
+pscnt
< smb_base(inbuf
)))
510 memcpy(state
->param
,smb_base(inbuf
)+psoff
,pscnt
);
513 state
->received_data
= dscnt
;
514 state
->received_param
= pscnt
;
516 if (state
->setup_count
) {
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
))));
524 END_PROFILE(SMBtrans
);
525 return(ERROR_DOS(ERRDOS
,ERRnomem
));
527 if (inbuf
+smb_vwv14
+(state
->setup_count
*SIZEOFWORD
) >
530 if ((smb_vwv14
+(state
->setup_count
*SIZEOFWORD
) < smb_vwv14
) ||
531 (smb_vwv14
+(state
->setup_count
*SIZEOFWORD
) <
532 (state
->setup_count
*SIZEOFWORD
)))
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
);
550 if (!NT_STATUS_IS_OK(result
)) {
551 END_PROFILE(SMBtrans
);
552 return ERROR_NT(result
);
556 END_PROFILE(SMBtrans
);
557 return ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
560 END_PROFILE(SMBtrans
);
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
);
570 END_PROFILE(SMBtrans
);
575 DEBUG(0,("reply_trans: invalid trans parameters\n"));
576 SAFE_FREE(state
->data
);
577 SAFE_FREE(state
->param
);
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
)
591 unsigned int pcnt
,poff
,dcnt
,doff
,pdisp
,ddisp
;
592 struct trans_state
*state
;
595 START_PROFILE(SMBtranss
);
599 for (state
= conn
->pending_trans
; state
!= NULL
;
600 state
= state
->next
) {
601 if (state
->mid
== SVAL(inbuf
,smb_mid
)) {
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
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
))
635 if (pdisp
+pcnt
> state
->total_param
)
637 if ((pdisp
+pcnt
< pdisp
) || (pdisp
+pcnt
< pcnt
))
639 if (pdisp
> state
->total_param
)
641 if ((smb_base(inbuf
) + poff
+ pcnt
> inbuf
+ size
) ||
642 (smb_base(inbuf
) + poff
+ pcnt
< smb_base(inbuf
)))
644 if (state
->param
+ pdisp
< state
->param
)
647 memcpy(state
->param
+pdisp
,smb_base(inbuf
)+poff
,
652 if (ddisp
+dcnt
> state
->total_data
)
654 if ((ddisp
+dcnt
< ddisp
) || (ddisp
+dcnt
< dcnt
))
656 if (ddisp
> state
->total_data
)
658 if ((smb_base(inbuf
) + doff
+ dcnt
> inbuf
+ size
) ||
659 (smb_base(inbuf
) + doff
+ dcnt
< smb_base(inbuf
)))
661 if (state
->data
+ ddisp
< state
->data
)
664 memcpy(state
->data
+ddisp
, smb_base(inbuf
)+doff
,
668 if ((state
->received_param
< state
->total_param
) ||
669 (state
->received_data
< state
->total_data
)) {
670 END_PROFILE(SMBtranss
);
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
);
686 if ((outsize
== 0) || !NT_STATUS_IS_OK(result
)) {
687 END_PROFILE(SMBtranss
);
688 return(ERROR_DOS(ERRSRV
,ERRnosupport
));
691 END_PROFILE(SMBtranss
);
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
);
701 END_PROFILE(SMBtranss
);
702 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);