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 extern fstring local_machine
;
34 #define NERR_notsupported 50
36 extern int smb_read_error
;
38 /*******************************************************************
39 copies parameters and data, as needed, into the smb buffer
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
46 ******************************************************************/
48 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
)
52 char *copy_into
= smb_buf(outbuf
)+1;
60 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
61 param_offset
, param_offset
+ param_len
,
62 data_offset
, data_offset
+ data_len
));
65 memcpy(copy_into
, &rparam
[param_offset
], param_len
);
67 copy_into
+= param_len
+ align
;
70 memcpy(copy_into
, &rdata
[data_offset
], data_len
);
73 /****************************************************************************
75 ****************************************************************************/
77 void send_trans_reply(char *outbuf
,
78 char *rparam
, int rparam_len
,
79 char *rdata
, int rdata_len
,
80 BOOL buffer_too_large
)
82 int this_ldata
,this_lparam
;
83 int tot_data_sent
= 0;
84 int tot_param_sent
= 0;
87 int ldata
= rdata
? rdata_len
: 0;
88 int lparam
= rparam
? rparam_len
: 0;
91 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata
));
93 this_lparam
= MIN(lparam
,max_send
- 500); /* hack */
94 this_ldata
= MIN(ldata
,max_send
- (500+this_lparam
));
96 align
= ((this_lparam
)%4);
98 if (buffer_too_large
) {
99 ERROR_BOTH(STATUS_BUFFER_OVERFLOW
,ERRDOS
,ERRmoredata
);
102 set_message(outbuf
,10,1+align
+this_ldata
+this_lparam
,True
);
104 copy_trans_params_and_data(outbuf
, align
,
105 rparam
, tot_param_sent
, this_lparam
,
106 rdata
, tot_data_sent
, this_ldata
);
108 SSVAL(outbuf
,smb_vwv0
,lparam
);
109 SSVAL(outbuf
,smb_vwv1
,ldata
);
110 SSVAL(outbuf
,smb_vwv3
,this_lparam
);
111 SSVAL(outbuf
,smb_vwv4
,smb_offset(smb_buf(outbuf
)+1,outbuf
));
112 SSVAL(outbuf
,smb_vwv5
,0);
113 SSVAL(outbuf
,smb_vwv6
,this_ldata
);
114 SSVAL(outbuf
,smb_vwv7
,smb_offset(smb_buf(outbuf
)+1+this_lparam
+align
,outbuf
));
115 SSVAL(outbuf
,smb_vwv8
,0);
116 SSVAL(outbuf
,smb_vwv9
,0);
119 if (!send_smb(smbd_server_fd(),outbuf
))
120 exit_server("send_trans_reply: send_smb failed.");
122 tot_data_sent
= this_ldata
;
123 tot_param_sent
= this_lparam
;
125 while (tot_data_sent
< ldata
|| tot_param_sent
< lparam
)
127 this_lparam
= MIN(lparam
-tot_param_sent
, max_send
- 500); /* hack */
128 this_ldata
= MIN(ldata
-tot_data_sent
, max_send
- (500+this_lparam
));
136 align
= (this_lparam
%4);
138 set_message(outbuf
,10,1+this_ldata
+this_lparam
+align
,False
);
140 copy_trans_params_and_data(outbuf
, align
,
141 rparam
, tot_param_sent
, this_lparam
,
142 rdata
, tot_data_sent
, this_ldata
);
144 SSVAL(outbuf
,smb_vwv3
,this_lparam
);
145 SSVAL(outbuf
,smb_vwv4
,smb_offset(smb_buf(outbuf
)+1,outbuf
));
146 SSVAL(outbuf
,smb_vwv5
,tot_param_sent
);
147 SSVAL(outbuf
,smb_vwv6
,this_ldata
);
148 SSVAL(outbuf
,smb_vwv7
,smb_offset(smb_buf(outbuf
)+1+this_lparam
+align
,outbuf
));
149 SSVAL(outbuf
,smb_vwv8
,tot_data_sent
);
150 SSVAL(outbuf
,smb_vwv9
,0);
153 if (!send_smb(smbd_server_fd(),outbuf
))
154 exit_server("send_trans_reply: send_smb failed.");
156 tot_data_sent
+= this_ldata
;
157 tot_param_sent
+= this_lparam
;
161 /****************************************************************************
162 Start the first part of an RPC reply which began with an SMBtrans request.
163 ****************************************************************************/
165 static BOOL
api_rpc_trans_reply(char *outbuf
, smb_np_struct
*p
)
167 BOOL is_data_outstanding
;
168 char *rdata
= malloc(p
->max_trans_reply
);
172 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
176 if((data_len
= read_from_pipe( p
, rdata
, p
->max_trans_reply
,
177 &is_data_outstanding
)) < 0) {
182 send_trans_reply(outbuf
, NULL
, 0, rdata
, data_len
, is_data_outstanding
);
188 /****************************************************************************
189 WaitNamedPipeHandleState
190 ****************************************************************************/
192 static BOOL
api_WNPHS(char *outbuf
, smb_np_struct
*p
, char *param
, int param_len
)
196 if (!param
|| param_len
< 2)
199 priority
= SVAL(param
,0);
200 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority
));
202 if (wait_rpc_pipe_hnd_state(p
, priority
)) {
203 /* now send the reply */
204 send_trans_reply(outbuf
, NULL
, 0, NULL
, 0, False
);
211 /****************************************************************************
212 SetNamedPipeHandleState
213 ****************************************************************************/
215 static BOOL
api_SNPHS(char *outbuf
, smb_np_struct
*p
, char *param
, int param_len
)
219 if (!param
|| param_len
< 2)
223 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id
));
225 if (set_rpc_pipe_hnd_state(p
, id
)) {
226 /* now send the reply */
227 send_trans_reply(outbuf
, NULL
, 0, NULL
, 0, False
);
234 /****************************************************************************
235 When no reply is generated, indicate unsupported.
236 ****************************************************************************/
238 static BOOL
api_no_reply(char *outbuf
, int max_rdata_len
)
243 SSVAL(rparam
,0,NERR_notsupported
);
244 SSVAL(rparam
,2,0); /* converter word */
246 DEBUG(3,("Unsupported API fd command\n"));
248 /* now send the reply */
249 send_trans_reply(outbuf
, rparam
, 4, NULL
, 0, False
);
254 /****************************************************************************
255 Handle remote api calls delivered to a named pipe already opened.
256 ****************************************************************************/
258 static int api_fd_reply(connection_struct
*conn
,uint16 vuid
,char *outbuf
,
259 uint16
*setup
,char *data
,char *params
,
260 int suwcnt
,int tdscnt
,int tpscnt
,int mdrcnt
,int mprcnt
)
263 smb_np_struct
*p
= NULL
;
267 DEBUG(5,("api_fd_reply\n"));
269 /* First find out the name of this file. */
271 DEBUG(0,("Unexpected named pipe transaction.\n"));
275 /* Get the file handle and hence the file name. */
277 * NB. The setup array has already been transformed
278 * via SVAL and so is in gost byte order.
280 pnum
= ((int)setup
[1]) & 0xFFFF;
281 subcommand
= ((int)setup
[0]) & 0xFFFF;
283 if(!(p
= get_rpc_pipe(pnum
))) {
284 if (subcommand
== TRANSACT_WAITNAMEDPIPEHANDLESTATE
) {
285 /* Win9x does this call with a unicode pipe name, not a pnum. */
286 /* Just return success for now... */
287 DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n"));
288 send_trans_reply(outbuf
, NULL
, 0, NULL
, 0, False
);
292 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum
));
293 return api_no_reply(outbuf
, mdrcnt
);
296 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", subcommand
, p
->name
, pnum
));
298 /* record maximum data length that can be transmitted in an SMBtrans */
299 p
->max_trans_reply
= mdrcnt
;
301 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p
, p
->max_trans_reply
));
303 switch (subcommand
) {
304 case TRANSACT_DCERPCCMD
:
305 /* dce/rpc command */
306 reply
= write_to_pipe(p
, data
, tdscnt
);
308 reply
= api_rpc_trans_reply(outbuf
, p
);
310 case TRANSACT_WAITNAMEDPIPEHANDLESTATE
:
311 /* Wait Named Pipe Handle state */
312 reply
= api_WNPHS(outbuf
, p
, params
, tpscnt
);
314 case TRANSACT_SETNAMEDPIPEHANDLESTATE
:
315 /* Set Named Pipe Handle state */
316 reply
= api_SNPHS(outbuf
, p
, params
, tpscnt
);
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]));
359 /****************************************************************************
361 ****************************************************************************/
363 int reply_trans(connection_struct
*conn
, char *inbuf
,char *outbuf
, int size
, int bufsize
)
367 char *data
=NULL
,*params
=NULL
;
370 uint16 vuid
= SVAL(inbuf
,smb_uid
);
371 unsigned int tpscnt
= SVAL(inbuf
,smb_vwv0
);
372 unsigned int tdscnt
= SVAL(inbuf
,smb_vwv1
);
373 unsigned int mprcnt
= SVAL(inbuf
,smb_vwv2
);
374 unsigned int mdrcnt
= SVAL(inbuf
,smb_vwv3
);
375 unsigned int msrcnt
= CVAL(inbuf
,smb_vwv4
);
376 BOOL close_on_completion
= BITSETW(inbuf
+smb_vwv5
,0);
377 BOOL one_way
= BITSETW(inbuf
+smb_vwv5
,1);
378 unsigned int pscnt
= SVAL(inbuf
,smb_vwv9
);
379 unsigned int psoff
= SVAL(inbuf
,smb_vwv10
);
380 unsigned int dscnt
= SVAL(inbuf
,smb_vwv11
);
381 unsigned int dsoff
= SVAL(inbuf
,smb_vwv12
);
382 unsigned int suwcnt
= CVAL(inbuf
,smb_vwv13
);
383 START_PROFILE(SMBtrans
);
385 memset(name
, '\0',sizeof(name
));
386 srvstr_pull_buf(inbuf
, name
, smb_buf(inbuf
), sizeof(name
), STR_TERMINATE
);
388 if (dscnt
> tdscnt
|| pscnt
> tpscnt
)
392 if((data
= (char *)malloc(tdscnt
)) == NULL
) {
393 DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt
));
394 END_PROFILE(SMBtrans
);
395 return(ERROR_DOS(ERRDOS
,ERRnomem
));
397 if ((dsoff
+dscnt
< dsoff
) || (dsoff
+dscnt
< dscnt
))
399 if ((smb_base(inbuf
)+dsoff
+dscnt
> inbuf
+ size
) ||
400 (smb_base(inbuf
)+dsoff
+dscnt
< smb_base(inbuf
)))
403 memcpy(data
,smb_base(inbuf
)+dsoff
,dscnt
);
407 if((params
= (char *)malloc(tpscnt
)) == NULL
) {
408 DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt
));
410 END_PROFILE(SMBtrans
);
411 return(ERROR_DOS(ERRDOS
,ERRnomem
));
413 if ((psoff
+pscnt
< psoff
) || (psoff
+pscnt
< pscnt
))
415 if ((smb_base(inbuf
)+psoff
+pscnt
> inbuf
+ size
) ||
416 (smb_base(inbuf
)+psoff
+pscnt
< smb_base(inbuf
)))
419 memcpy(params
,smb_base(inbuf
)+psoff
,pscnt
);
424 if((setup
= (uint16
*)malloc(suwcnt
*sizeof(uint16
))) == NULL
) {
425 DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt
* sizeof(uint16
))));
428 END_PROFILE(SMBtrans
);
429 return(ERROR_DOS(ERRDOS
,ERRnomem
));
431 if (inbuf
+smb_vwv14
+(suwcnt
*SIZEOFWORD
) > inbuf
+ size
)
433 if ((smb_vwv14
+(suwcnt
*SIZEOFWORD
) < smb_vwv14
) || (smb_vwv14
+(suwcnt
*SIZEOFWORD
) < (suwcnt
*SIZEOFWORD
)))
436 for (i
=0;i
<suwcnt
;i
++)
437 setup
[i
] = SVAL(inbuf
,smb_vwv14
+i
*SIZEOFWORD
);
441 srv_signing_trans_start(SVAL(inbuf
,smb_mid
));
443 if (pscnt
< tpscnt
|| dscnt
< tdscnt
) {
444 /* We need to send an interim response then receive the rest
445 of the parameter/data bytes */
446 outsize
= set_message(outbuf
,0,0,True
);
448 srv_signing_trans_stop();
449 if (!send_smb(smbd_server_fd(),outbuf
))
450 exit_server("reply_trans: send_smb failed.");
453 /* receive the rest of the trans packet */
454 while (pscnt
< tpscnt
|| dscnt
< tdscnt
) {
456 unsigned int pcnt
,poff
,dcnt
,doff
,pdisp
,ddisp
;
458 ret
= receive_next_smb(inbuf
,bufsize
,SMB_SECONDARY_WAIT
);
461 * The sequence number for the trans reply is always
462 * based on the last secondary received.
465 srv_signing_trans_start(SVAL(inbuf
,smb_mid
));
467 if ((ret
&& (CVAL(inbuf
, smb_com
) != SMBtranss
)) || !ret
) {
469 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
471 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
472 (smb_read_error
== READ_ERROR
) ? "error" : "timeout" ));
477 END_PROFILE(SMBtrans
);
478 srv_signing_trans_stop();
479 return(ERROR_DOS(ERRSRV
,ERRerror
));
484 /* Revise total_params and total_data in case they have changed downwards */
485 if (SVAL(inbuf
,smb_vwv0
) < tpscnt
)
486 tpscnt
= SVAL(inbuf
,smb_vwv0
);
487 if (SVAL(inbuf
,smb_vwv1
) < tdscnt
)
488 tdscnt
= SVAL(inbuf
,smb_vwv1
);
490 pcnt
= SVAL(inbuf
,smb_vwv2
);
491 poff
= SVAL(inbuf
,smb_vwv3
);
492 pdisp
= SVAL(inbuf
,smb_vwv4
);
494 dcnt
= SVAL(inbuf
,smb_vwv5
);
495 doff
= SVAL(inbuf
,smb_vwv6
);
496 ddisp
= SVAL(inbuf
,smb_vwv7
);
501 if (dscnt
> tdscnt
|| pscnt
> tpscnt
)
505 if (pdisp
+pcnt
>= tpscnt
)
507 if ((pdisp
+pcnt
< pdisp
) || (pdisp
+pcnt
< pcnt
))
511 if ((smb_base(inbuf
) + poff
+ pcnt
>= inbuf
+ bufsize
) ||
512 (smb_base(inbuf
) + poff
+ pcnt
< smb_base(inbuf
)))
514 if (params
+ pdisp
< params
)
517 memcpy(params
+pdisp
,smb_base(inbuf
)+poff
,pcnt
);
521 if (ddisp
+dcnt
>= tdscnt
)
523 if ((ddisp
+dcnt
< ddisp
) || (ddisp
+dcnt
< dcnt
))
527 if ((smb_base(inbuf
) + doff
+ dcnt
>= inbuf
+ bufsize
) ||
528 (smb_base(inbuf
) + doff
+ dcnt
< smb_base(inbuf
)))
530 if (data
+ ddisp
< data
)
533 memcpy(data
+ddisp
,smb_base(inbuf
)+doff
,dcnt
);
537 DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
538 name
,tdscnt
,tpscnt
,suwcnt
));
541 * WinCE wierdness....
544 if (name
[0] == '\\' && (StrnCaseCmp(&name
[1],local_machine
, strlen(local_machine
)) == 0) &&
545 (name
[strlen(local_machine
)+1] == '\\'))
546 name_offset
= strlen(local_machine
)+1;
548 if (strnequal(&name
[name_offset
], "\\PIPE", strlen("\\PIPE"))) {
549 name_offset
+= strlen("\\PIPE");
551 /* Win9x weirdness. When talking to a unicode server Win9x
552 only sends \PIPE instead of \PIPE\ */
554 if (name
[name_offset
] == '\\')
557 DEBUG(5,("calling named_pipe\n"));
558 outsize
= named_pipe(conn
,vuid
,outbuf
,
559 name
+name_offset
,setup
,data
,params
,
560 suwcnt
,tdscnt
,tpscnt
,msrcnt
,mdrcnt
,mprcnt
);
562 DEBUG(3,("invalid pipe name\n"));
571 srv_signing_trans_stop();
573 if (close_on_completion
)
574 close_cnum(conn
,vuid
);
577 END_PROFILE(SMBtrans
);
582 END_PROFILE(SMBtrans
);
583 return(ERROR_DOS(ERRSRV
,ERRnosupport
));
586 END_PROFILE(SMBtrans
);
592 srv_signing_trans_stop();
593 DEBUG(0,("reply_trans: invalid trans parameters\n"));
597 END_PROFILE(SMBtrans
);
598 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);