3 Unix SMB/Netbios implementation.
5 Inter-process communication and named pipe handling
6 Copyright (C) Andrew Tridgell 1992-1998
9 Copyright (C) John H Terpstra 1995-1998
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 This file handles the named pipe and mailslot calls
27 in the SMBtrans protocol
32 extern int DEBUGLEVEL;
35 extern fstring local_machine;
37 #define NERR_notsupported 50
39 extern int smb_read_error;
41 /*******************************************************************
42 copies parameters and data, as needed, into the smb buffer
44 *both* the data and params sections should be aligned. this
45 is fudged in the rpc pipes by
46 at present, only the data section is. this may be a possible
47 cause of some of the ipc problems being experienced. lkcl26dec97
49 ******************************************************************/
51 static void copy_trans_params_and_data(char *outbuf, int align,
52 char *rparam, int param_offset, int param_len,
53 char *rdata, int data_offset, int data_len)
55 char *copy_into = smb_buf(outbuf)+1;
63 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
64 param_offset, param_offset + param_len,
65 data_offset , data_offset + data_len));
68 memcpy(copy_into, &rparam[param_offset], param_len);
70 copy_into += param_len + align;
73 memcpy(copy_into, &rdata[data_offset], data_len);
76 /****************************************************************************
78 ****************************************************************************/
80 void send_trans_reply(char *outbuf,
81 char *rparam, int rparam_len,
82 char *rdata, int rdata_len,
83 BOOL buffer_too_large)
85 int this_ldata,this_lparam;
86 int tot_data_sent = 0;
87 int tot_param_sent = 0;
90 int ldata = rdata ? rdata_len : 0;
91 int lparam = rparam ? rparam_len : 0;
94 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
96 this_lparam = MIN(lparam,max_send - 500); /* hack */
97 this_ldata = MIN(ldata,max_send - (500+this_lparam));
99 align = ((this_lparam)%4);
101 set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
103 if (buffer_too_large)
105 /* issue a buffer size warning. on a DCE/RPC pipe, expect an SMBreadX... */
106 SIVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
107 SIVAL(outbuf, smb_rcls, 0x80000000 | NT_STATUS_ACCESS_VIOLATION);
110 copy_trans_params_and_data(outbuf, align,
111 rparam, tot_param_sent, this_lparam,
112 rdata, tot_data_sent, this_ldata);
114 SSVAL(outbuf,smb_vwv0,lparam);
115 SSVAL(outbuf,smb_vwv1,ldata);
116 SSVAL(outbuf,smb_vwv3,this_lparam);
117 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
118 SSVAL(outbuf,smb_vwv5,0);
119 SSVAL(outbuf,smb_vwv6,this_ldata);
120 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
121 SSVAL(outbuf,smb_vwv8,0);
122 SSVAL(outbuf,smb_vwv9,0);
125 send_smb(smbd_server_fd(),outbuf);
127 tot_data_sent = this_ldata;
128 tot_param_sent = this_lparam;
130 while (tot_data_sent < ldata || tot_param_sent < lparam)
132 this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
133 this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
141 align = (this_lparam%4);
143 set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
145 copy_trans_params_and_data(outbuf, align,
146 rparam, tot_param_sent, this_lparam,
147 rdata, tot_data_sent, this_ldata);
149 SSVAL(outbuf,smb_vwv3,this_lparam);
150 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
151 SSVAL(outbuf,smb_vwv5,tot_param_sent);
152 SSVAL(outbuf,smb_vwv6,this_ldata);
153 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
154 SSVAL(outbuf,smb_vwv8,tot_data_sent);
155 SSVAL(outbuf,smb_vwv9,0);
158 send_smb(smbd_server_fd(),outbuf);
160 tot_data_sent += this_ldata;
161 tot_param_sent += this_lparam;
165 /****************************************************************************
166 Start the first part of an RPC reply which began with an SMBtrans request.
167 ****************************************************************************/
169 static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p)
171 char *rdata = 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)) < 0) {
184 send_trans_reply(outbuf, NULL, 0, rdata, data_len, p->out_data.current_pdu_len > data_len);
190 /****************************************************************************
191 WaitNamedPipeHandleState
192 ****************************************************************************/
194 static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
198 if (!param || param_len < 2)
201 priority = SVAL(param,0);
202 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
204 if (wait_rpc_pipe_hnd_state(p, priority)) {
205 /* now send the reply */
206 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
213 /****************************************************************************
214 SetNamedPipeHandleState
215 ****************************************************************************/
217 static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
221 if (!param || param_len < 2)
225 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
227 if (set_rpc_pipe_hnd_state(p, id)) {
228 /* now send the reply */
229 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
236 /****************************************************************************
237 When no reply is generated, indicate unsupported.
238 ****************************************************************************/
240 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
245 SSVAL(rparam,0,NERR_notsupported);
246 SSVAL(rparam,2,0); /* converter word */
248 DEBUG(3,("Unsupported API fd command\n"));
250 /* now send the reply */
251 send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
256 /****************************************************************************
257 Handle remote api calls delivered to a named pipe already opened.
258 ****************************************************************************/
260 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
261 uint16 *setup,char *data,char *params,
262 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
265 pipes_struct *p = NULL;
269 DEBUG(5,("api_fd_reply\n"));
271 /* First find out the name of this file. */
273 DEBUG(0,("Unexpected named pipe transaction.\n"));
277 /* Get the file handle and hence the file name. */
279 * NB. The setup array has already been transformed
280 * via SVAL and so is in gost byte order.
282 pnum = ((int)setup[1]) & 0xFFFF;
283 subcommand = ((int)setup[0]) & 0xFFFF;
285 if(!(p = get_rpc_pipe(pnum))) {
286 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
287 return api_no_reply(outbuf, mdrcnt);
290 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand, p->name, pnum));
292 /* record maximum data length that can be transmitted in an SMBtrans */
293 p->max_trans_reply = mdrcnt;
295 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
297 switch (subcommand) {
299 /* dce/rpc command */
300 reply = write_to_pipe(p, data, tdscnt);
302 reply = api_rpc_trans_reply(outbuf, p);
305 /* Wait Named Pipe Handle state */
306 reply = api_WNPHS(outbuf, p, params, tpscnt);
309 /* Set Named Pipe Handle state */
310 reply = api_SNPHS(outbuf, p, params, tpscnt);
315 return api_no_reply(outbuf, mdrcnt);
320 /****************************************************************************
321 handle named pipe commands
322 ****************************************************************************/
323 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
324 uint16 *setup,char *data,char *params,
325 int suwcnt,int tdscnt,int tpscnt,
326 int msrcnt,int mdrcnt,int mprcnt)
328 DEBUG(3,("named pipe command on <%s> name\n", name));
330 if (strequal(name,"LANMAN"))
331 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
333 if (strequal(name,"WKSSVC") ||
334 strequal(name,"SRVSVC") ||
335 strequal(name,"WINREG") ||
336 strequal(name,"SAMR") ||
337 strequal(name,"LSARPC"))
339 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
340 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
343 if (strlen(name) < 1)
344 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
347 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
353 /****************************************************************************
355 ****************************************************************************/
357 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
361 char *data=NULL,*params=NULL;
364 uint16 vuid = SVAL(inbuf,smb_uid);
365 int tpscnt = SVAL(inbuf,smb_vwv0);
366 int tdscnt = SVAL(inbuf,smb_vwv1);
367 int mprcnt = SVAL(inbuf,smb_vwv2);
368 int mdrcnt = SVAL(inbuf,smb_vwv3);
369 int msrcnt = CVAL(inbuf,smb_vwv4);
370 BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
371 BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
372 int pscnt = SVAL(inbuf,smb_vwv9);
373 int psoff = SVAL(inbuf,smb_vwv10);
374 int dscnt = SVAL(inbuf,smb_vwv11);
375 int dsoff = SVAL(inbuf,smb_vwv12);
376 int suwcnt = CVAL(inbuf,smb_vwv13);
378 memset(name, '\0',sizeof(name));
379 fstrcpy(name,smb_buf(inbuf));
381 if (dscnt > tdscnt || pscnt > tpscnt) {
382 exit_server("invalid trans parameters\n");
386 if((data = (char *)malloc(tdscnt)) == NULL) {
387 DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
388 return(ERROR(ERRDOS,ERRnomem));
390 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
394 if((params = (char *)malloc(tpscnt)) == NULL) {
395 DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
396 return(ERROR(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 return(ERROR(ERRDOS,ERRnomem));
407 for (i=0;i<suwcnt;i++)
408 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
412 if (pscnt < tpscnt || dscnt < tdscnt) {
413 /* We need to send an interim response then receive the rest
414 of the parameter/data bytes */
415 outsize = set_message(outbuf,0,0,True);
417 send_smb(smbd_server_fd(),outbuf);
420 /* receive the rest of the trans packet */
421 while (pscnt < tpscnt || dscnt < tdscnt) {
423 int pcnt,poff,dcnt,doff,pdisp,ddisp;
425 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
427 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
429 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
431 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
432 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
440 return(ERROR(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\n");
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 (strncmp(&name[name_offset],"\\PIPE\\",strlen("\\PIPE\\")) == 0) {
482 DEBUG(5,("calling named_pipe\n"));
483 outsize = named_pipe(conn,vuid,outbuf,
484 name+name_offset+strlen("\\PIPE\\"),setup,data,params,
485 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
487 DEBUG(3,("invalid pipe name\n"));
499 if (close_on_completion)
500 close_cnum(conn,vuid);
506 return(ERROR(ERRSRV,ERRnosupport));