2 Unix SMB/Netbios implementation.
4 Inter-process communication and named pipe handling
5 Copyright (C) Andrew Tridgell 1992-1998
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
33 extern fstring local_machine
;
35 #define NERR_notsupported 50
37 extern int smb_read_error
;
39 /*******************************************************************
40 copies parameters and data, as needed, into the smb buffer
42 *both* the data and params sections should be aligned. this
43 is fudged in the rpc pipes by
44 at present, only the data section is. this may be a possible
45 cause of some of the ipc problems being experienced. lkcl26dec97
47 ******************************************************************/
49 static void copy_trans_params_and_data(char *outbuf
, int align
,
50 char *rparam
, int param_offset
, int param_len
,
51 char *rdata
, int data_offset
, int data_len
)
53 char *copy_into
= smb_buf(outbuf
)+1;
61 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
62 param_offset
, param_offset
+ param_len
,
63 data_offset
, data_offset
+ data_len
));
66 memcpy(copy_into
, &rparam
[param_offset
], param_len
);
68 copy_into
+= param_len
+ align
;
71 memcpy(copy_into
, &rdata
[data_offset
], data_len
);
74 /****************************************************************************
76 ****************************************************************************/
78 void send_trans_reply(char *outbuf
,
79 char *rparam
, int rparam_len
,
80 char *rdata
, int rdata_len
,
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_NT(STATUS_BUFFER_OVERFLOW
);
103 set_message(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("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(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("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(char *outbuf
, pipes_struct
*p
)
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
)) < 0) {
181 send_trans_reply(outbuf
, NULL
, 0, rdata
, data_len
, p
->out_data
.current_pdu_len
> data_len
);
187 /****************************************************************************
188 WaitNamedPipeHandleState
189 ****************************************************************************/
191 static BOOL
api_WNPHS(char *outbuf
, pipes_struct
*p
, char *param
, int param_len
)
195 if (!param
|| param_len
< 2)
198 priority
= SVAL(param
,0);
199 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority
));
201 if (wait_rpc_pipe_hnd_state(p
, priority
)) {
202 /* now send the reply */
203 send_trans_reply(outbuf
, NULL
, 0, NULL
, 0, False
);
210 /****************************************************************************
211 SetNamedPipeHandleState
212 ****************************************************************************/
214 static BOOL
api_SNPHS(char *outbuf
, pipes_struct
*p
, char *param
, int param_len
)
218 if (!param
|| param_len
< 2)
222 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id
));
224 if (set_rpc_pipe_hnd_state(p
, id
)) {
225 /* now send the reply */
226 send_trans_reply(outbuf
, NULL
, 0, NULL
, 0, False
);
233 /****************************************************************************
234 When no reply is generated, indicate unsupported.
235 ****************************************************************************/
237 static BOOL
api_no_reply(char *outbuf
, int max_rdata_len
)
242 SSVAL(rparam
,0,NERR_notsupported
);
243 SSVAL(rparam
,2,0); /* converter word */
245 DEBUG(3,("Unsupported API fd command\n"));
247 /* now send the reply */
248 send_trans_reply(outbuf
, rparam
, 4, NULL
, 0, False
);
253 /****************************************************************************
254 Handle remote api calls delivered to a named pipe already opened.
255 ****************************************************************************/
257 static int api_fd_reply(connection_struct
*conn
,uint16 vuid
,char *outbuf
,
258 uint16
*setup
,char *data
,char *params
,
259 int suwcnt
,int tdscnt
,int tpscnt
,int mdrcnt
,int mprcnt
)
262 pipes_struct
*p
= NULL
;
266 DEBUG(5,("api_fd_reply\n"));
268 /* First find out the name of this file. */
270 DEBUG(0,("Unexpected named pipe transaction.\n"));
274 /* Get the file handle and hence the file name. */
276 * NB. The setup array has already been transformed
277 * via SVAL and so is in gost byte order.
279 pnum
= ((int)setup
[1]) & 0xFFFF;
280 subcommand
= ((int)setup
[0]) & 0xFFFF;
282 if(!(p
= get_rpc_pipe(pnum
))) {
283 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum
));
284 return api_no_reply(outbuf
, mdrcnt
);
287 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand
, p
->name
, pnum
));
289 /* record maximum data length that can be transmitted in an SMBtrans */
290 p
->max_trans_reply
= mdrcnt
;
292 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p
, p
->max_trans_reply
));
294 switch (subcommand
) {
296 /* dce/rpc command */
297 reply
= write_to_pipe(p
, data
, tdscnt
);
299 reply
= api_rpc_trans_reply(outbuf
, p
);
302 /* Wait Named Pipe Handle state */
303 reply
= api_WNPHS(outbuf
, p
, params
, tpscnt
);
306 /* Set Named Pipe Handle state */
307 reply
= api_SNPHS(outbuf
, p
, params
, tpscnt
);
312 return api_no_reply(outbuf
, mdrcnt
);
317 /****************************************************************************
318 handle named pipe commands
319 ****************************************************************************/
320 static int named_pipe(connection_struct
*conn
,uint16 vuid
, char *outbuf
,char *name
,
321 uint16
*setup
,char *data
,char *params
,
322 int suwcnt
,int tdscnt
,int tpscnt
,
323 int msrcnt
,int mdrcnt
,int mprcnt
)
325 DEBUG(3,("named pipe command on <%s> name\n", name
));
327 if (strequal(name
,"LANMAN"))
328 return api_reply(conn
,vuid
,outbuf
,data
,params
,tdscnt
,tpscnt
,mdrcnt
,mprcnt
);
330 if (strequal(name
,"WKSSVC") ||
331 strequal(name
,"SRVSVC") ||
332 strequal(name
,"WINREG") ||
333 strequal(name
,"SAMR") ||
334 strequal(name
,"LSARPC"))
336 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
337 return api_fd_reply(conn
,vuid
,outbuf
,setup
,data
,params
,suwcnt
,tdscnt
,tpscnt
,mdrcnt
,mprcnt
);
340 if (strlen(name
) < 1)
341 return api_fd_reply(conn
,vuid
,outbuf
,setup
,data
,params
,suwcnt
,tdscnt
,tpscnt
,mdrcnt
,mprcnt
);
344 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup
[0],(int)setup
[1]));
350 /****************************************************************************
352 ****************************************************************************/
354 int reply_trans(connection_struct
*conn
, char *inbuf
,char *outbuf
, int size
, int bufsize
)
358 char *data
=NULL
,*params
=NULL
;
361 uint16 vuid
= SVAL(inbuf
,smb_uid
);
362 int tpscnt
= SVAL(inbuf
,smb_vwv0
);
363 int tdscnt
= SVAL(inbuf
,smb_vwv1
);
364 int mprcnt
= SVAL(inbuf
,smb_vwv2
);
365 int mdrcnt
= SVAL(inbuf
,smb_vwv3
);
366 int msrcnt
= CVAL(inbuf
,smb_vwv4
);
367 BOOL close_on_completion
= BITSETW(inbuf
+smb_vwv5
,0);
368 BOOL one_way
= BITSETW(inbuf
+smb_vwv5
,1);
369 int pscnt
= SVAL(inbuf
,smb_vwv9
);
370 int psoff
= SVAL(inbuf
,smb_vwv10
);
371 int dscnt
= SVAL(inbuf
,smb_vwv11
);
372 int dsoff
= SVAL(inbuf
,smb_vwv12
);
373 int suwcnt
= CVAL(inbuf
,smb_vwv13
);
374 START_PROFILE(SMBtrans
);
376 memset(name
, '\0',sizeof(name
));
377 srvstr_pull(inbuf
, name
, smb_buf(inbuf
), sizeof(name
), -1, STR_TERMINATE
);
379 if (dscnt
> tdscnt
|| pscnt
> tpscnt
) {
380 exit_server("invalid trans parameters");
384 if((data
= (char *)malloc(tdscnt
)) == NULL
) {
385 DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt
));
386 END_PROFILE(SMBtrans
);
387 return(ERROR_DOS(ERRDOS
,ERRnomem
));
389 memcpy(data
,smb_base(inbuf
)+dsoff
,dscnt
);
393 if((params
= (char *)malloc(tpscnt
)) == NULL
) {
394 DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt
));
395 END_PROFILE(SMBtrans
);
396 return(ERROR_DOS(ERRDOS
,ERRnomem
));
398 memcpy(params
,smb_base(inbuf
)+psoff
,pscnt
);
403 if((setup
= (uint16
*)malloc(suwcnt
*sizeof(uint16
))) == NULL
) {
404 DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt
* sizeof(uint16
))));
405 END_PROFILE(SMBtrans
);
406 return(ERROR_DOS(ERRDOS
,ERRnomem
));
408 for (i
=0;i
<suwcnt
;i
++)
409 setup
[i
] = SVAL(inbuf
,smb_vwv14
+i
*SIZEOFWORD
);
413 if (pscnt
< tpscnt
|| dscnt
< tdscnt
) {
414 /* We need to send an interim response then receive the rest
415 of the parameter/data bytes */
416 outsize
= set_message(outbuf
,0,0,True
);
418 if (!send_smb(smbd_server_fd(),outbuf
))
419 exit_server("reply_trans: send_smb failed.");
422 /* receive the rest of the trans packet */
423 while (pscnt
< tpscnt
|| dscnt
< tdscnt
) {
425 int pcnt
,poff
,dcnt
,doff
,pdisp
,ddisp
;
427 ret
= receive_next_smb(inbuf
,bufsize
,SMB_SECONDARY_WAIT
);
429 if ((ret
&& (CVAL(inbuf
, smb_com
) != SMBtranss
)) || !ret
) {
431 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
433 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
434 (smb_read_error
== READ_ERROR
) ? "error" : "timeout" ));
439 END_PROFILE(SMBtrans
);
440 return(ERROR_DOS(ERRSRV
,ERRerror
));
445 tpscnt
= SVAL(inbuf
,smb_vwv0
);
446 tdscnt
= SVAL(inbuf
,smb_vwv1
);
448 pcnt
= SVAL(inbuf
,smb_vwv2
);
449 poff
= SVAL(inbuf
,smb_vwv3
);
450 pdisp
= SVAL(inbuf
,smb_vwv4
);
452 dcnt
= SVAL(inbuf
,smb_vwv5
);
453 doff
= SVAL(inbuf
,smb_vwv6
);
454 ddisp
= SVAL(inbuf
,smb_vwv7
);
459 if (dscnt
> tdscnt
|| pscnt
> tpscnt
) {
460 exit_server("invalid trans parameters");
464 memcpy(params
+pdisp
,smb_base(inbuf
)+poff
,pcnt
);
466 memcpy(data
+ddisp
,smb_base(inbuf
)+doff
,dcnt
);
470 DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
471 name
,tdscnt
,tpscnt
,suwcnt
));
474 * WinCE wierdness....
477 if (name
[0] == '\\' && (StrnCaseCmp(&name
[1],local_machine
, strlen(local_machine
)) == 0) &&
478 (name
[strlen(local_machine
)+1] == '\\'))
479 name_offset
= strlen(local_machine
)+1;
481 if (strnequal(&name
[name_offset
], "\\PIPE", strlen("\\PIPE"))) {
482 name_offset
+= strlen("\\PIPE");
484 /* Win9x weirdness. When talking to a unicode server Win9x
485 only sends \PIPE instead of \PIPE\ */
487 if (name
[name_offset
] == '\\')
490 DEBUG(5,("calling named_pipe\n"));
491 outsize
= named_pipe(conn
,vuid
,outbuf
,
492 name
+name_offset
,setup
,data
,params
,
493 suwcnt
,tdscnt
,tpscnt
,msrcnt
,mdrcnt
,mprcnt
);
495 DEBUG(3,("invalid pipe name\n"));
504 if (close_on_completion
)
505 close_cnum(conn
,vuid
);
508 END_PROFILE(SMBtrans
);
513 END_PROFILE(SMBtrans
);
514 return(ERROR_DOS(ERRSRV
,ERRnosupport
));
517 END_PROFILE(SMBtrans
);