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, smb_np_struct *p)
168 BOOL is_data_outstanding;
169 char *rdata = malloc(p->max_trans_reply);
173 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
177 if((data_len = read_from_pipe( p, rdata, p->max_trans_reply,
178 &is_data_outstanding)) < 0) {
183 send_trans_reply(outbuf, NULL, 0, rdata, data_len, is_data_outstanding);
189 /****************************************************************************
190 WaitNamedPipeHandleState
191 ****************************************************************************/
193 static BOOL api_WNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len)
197 if (!param || param_len < 2)
200 priority = SVAL(param,0);
201 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
203 if (wait_rpc_pipe_hnd_state(p, priority)) {
204 /* now send the reply */
205 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
212 /****************************************************************************
213 SetNamedPipeHandleState
214 ****************************************************************************/
216 static BOOL api_SNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len)
220 if (!param || param_len < 2)
224 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
226 if (set_rpc_pipe_hnd_state(p, id)) {
227 /* now send the reply */
228 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
235 /****************************************************************************
236 When no reply is generated, indicate unsupported.
237 ****************************************************************************/
239 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
244 SSVAL(rparam,0,NERR_notsupported);
245 SSVAL(rparam,2,0); /* converter word */
247 DEBUG(3,("Unsupported API fd command\n"));
249 /* now send the reply */
250 send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
255 /****************************************************************************
256 Handle remote api calls delivered to a named pipe already opened.
257 ****************************************************************************/
259 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
260 uint16 *setup,char *data,char *params,
261 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
264 smb_np_struct *p = NULL;
268 DEBUG(5,("api_fd_reply\n"));
270 /* First find out the name of this file. */
272 DEBUG(0,("Unexpected named pipe transaction.\n"));
276 /* Get the file handle and hence the file name. */
278 * NB. The setup array has already been transformed
279 * via SVAL and so is in gost byte order.
281 pnum = ((int)setup[1]) & 0xFFFF;
282 subcommand = ((int)setup[0]) & 0xFFFF;
284 if(!(p = get_rpc_pipe(pnum))) {
285 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
286 return api_no_reply(outbuf, mdrcnt);
289 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand, p->name, pnum));
291 /* record maximum data length that can be transmitted in an SMBtrans */
292 p->max_trans_reply = mdrcnt;
294 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
296 switch (subcommand) {
298 /* dce/rpc command */
299 reply = write_to_pipe(p, data, tdscnt);
301 reply = api_rpc_trans_reply(outbuf, p);
304 /* Wait Named Pipe Handle state */
305 reply = api_WNPHS(outbuf, p, params, tpscnt);
308 /* Set Named Pipe Handle state */
309 reply = api_SNPHS(outbuf, p, params, tpscnt);
314 return api_no_reply(outbuf, mdrcnt);
319 /****************************************************************************
320 handle named pipe commands
321 ****************************************************************************/
322 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
323 uint16 *setup,char *data,char *params,
324 int suwcnt,int tdscnt,int tpscnt,
325 int msrcnt,int mdrcnt,int mprcnt)
327 DEBUG(3,("named pipe command on <%s> name\n", name));
329 if (strequal(name,"LANMAN"))
330 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
332 if (strequal(name,"WKSSVC") ||
333 strequal(name,"SRVSVC") ||
334 strequal(name,"WINREG") ||
335 strequal(name,"SAMR") ||
336 strequal(name,"LSARPC"))
338 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
339 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
342 if (strlen(name) < 1)
343 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
346 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
352 /****************************************************************************
354 ****************************************************************************/
356 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
360 char *data=NULL,*params=NULL;
363 uint16 vuid = SVAL(inbuf,smb_uid);
364 int tpscnt = SVAL(inbuf,smb_vwv0);
365 int tdscnt = SVAL(inbuf,smb_vwv1);
366 int mprcnt = SVAL(inbuf,smb_vwv2);
367 int mdrcnt = SVAL(inbuf,smb_vwv3);
368 int msrcnt = CVAL(inbuf,smb_vwv4);
369 BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
370 BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
371 int pscnt = SVAL(inbuf,smb_vwv9);
372 int psoff = SVAL(inbuf,smb_vwv10);
373 int dscnt = SVAL(inbuf,smb_vwv11);
374 int dsoff = SVAL(inbuf,smb_vwv12);
375 int suwcnt = CVAL(inbuf,smb_vwv13);
376 START_PROFILE(SMBtrans);
378 memset(name, '\0',sizeof(name));
379 srvstr_pull(inbuf, name, smb_buf(inbuf), sizeof(name), -1, STR_TERMINATE);
381 if (dscnt > tdscnt || pscnt > tpscnt) {
382 exit_server("invalid trans parameters");
386 if((data = (char *)malloc(tdscnt)) == NULL) {
387 DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
388 END_PROFILE(SMBtrans);
389 return(ERROR_DOS(ERRDOS,ERRnomem));
391 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
395 if((params = (char *)malloc(tpscnt)) == NULL) {
396 DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
397 END_PROFILE(SMBtrans);
398 return(ERROR_DOS(ERRDOS,ERRnomem));
400 memcpy(params,smb_base(inbuf)+psoff,pscnt);
405 if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
406 DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
407 END_PROFILE(SMBtrans);
408 return(ERROR_DOS(ERRDOS,ERRnomem));
410 for (i=0;i<suwcnt;i++)
411 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
415 if (pscnt < tpscnt || dscnt < tdscnt) {
416 /* We need to send an interim response then receive the rest
417 of the parameter/data bytes */
418 outsize = set_message(outbuf,0,0,True);
420 if (!send_smb(smbd_server_fd(),outbuf))
421 exit_server("reply_trans: send_smb failed.");
424 /* receive the rest of the trans packet */
425 while (pscnt < tpscnt || dscnt < tdscnt) {
427 int pcnt,poff,dcnt,doff,pdisp,ddisp;
429 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
431 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
433 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
435 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
436 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
441 END_PROFILE(SMBtrans);
442 return(ERROR_DOS(ERRSRV,ERRerror));
447 tpscnt = SVAL(inbuf,smb_vwv0);
448 tdscnt = SVAL(inbuf,smb_vwv1);
450 pcnt = SVAL(inbuf,smb_vwv2);
451 poff = SVAL(inbuf,smb_vwv3);
452 pdisp = SVAL(inbuf,smb_vwv4);
454 dcnt = SVAL(inbuf,smb_vwv5);
455 doff = SVAL(inbuf,smb_vwv6);
456 ddisp = SVAL(inbuf,smb_vwv7);
461 if (dscnt > tdscnt || pscnt > tpscnt) {
462 exit_server("invalid trans parameters");
466 memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
468 memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
472 DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
473 name,tdscnt,tpscnt,suwcnt));
476 * WinCE wierdness....
479 if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
480 (name[strlen(local_machine)+1] == '\\'))
481 name_offset = strlen(local_machine)+1;
483 if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
484 name_offset += strlen("\\PIPE");
486 /* Win9x weirdness. When talking to a unicode server Win9x
487 only sends \PIPE instead of \PIPE\ */
489 if (name[name_offset] == '\\')
492 DEBUG(5,("calling named_pipe\n"));
493 outsize = named_pipe(conn,vuid,outbuf,
494 name+name_offset,setup,data,params,
495 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
497 DEBUG(3,("invalid pipe name\n"));
506 if (close_on_completion)
507 close_cnum(conn,vuid);
510 END_PROFILE(SMBtrans);
515 END_PROFILE(SMBtrans);
516 return(ERROR_DOS(ERRSRV,ERRnosupport));
519 END_PROFILE(SMBtrans);