preparing for release of 2.2.3a
[Samba.git] / source / smbd / ipc.c
blobe1c3e7fe4d3c9cec59084c70a3a47c3d89042b94
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Inter-process communication and named pipe handling
5 Copyright (C) Andrew Tridgell 1992-1998
7 SMB Version handling
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
29 #include "includes.h"
31 extern int max_send;
33 extern fstring local_machine;
35 #define NERR_notsupported 50
37 extern int smb_read_error;
38 extern uint32 global_client_caps;
40 /*******************************************************************
41 copies parameters and data, as needed, into the smb buffer
43 *both* the data and params sections should be aligned. this
44 is fudged in the rpc pipes by
45 at present, only the data section is. this may be a possible
46 cause of some of the ipc problems being experienced. lkcl26dec97
48 ******************************************************************/
50 static void copy_trans_params_and_data(char *outbuf, int align,
51 char *rparam, int param_offset, int param_len,
52 char *rdata, int data_offset, int data_len)
54 char *copy_into = smb_buf(outbuf)+1;
56 if(param_len < 0)
57 param_len = 0;
59 if(data_len < 0)
60 data_len = 0;
62 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
63 param_offset, param_offset + param_len,
64 data_offset , data_offset + data_len));
66 if (param_len)
67 memcpy(copy_into, &rparam[param_offset], param_len);
69 copy_into += param_len + align;
71 if (data_len )
72 memcpy(copy_into, &rdata[data_offset], data_len);
75 /****************************************************************************
76 Send a trans reply.
77 ****************************************************************************/
79 void send_trans_reply(char *outbuf,
80 char *rparam, int rparam_len,
81 char *rdata, int rdata_len,
82 BOOL buffer_too_large)
84 int this_ldata,this_lparam;
85 int tot_data_sent = 0;
86 int tot_param_sent = 0;
87 int align;
89 int ldata = rdata ? rdata_len : 0;
90 int lparam = rparam ? rparam_len : 0;
92 if (buffer_too_large)
93 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
95 this_lparam = MIN(lparam,max_send - 500); /* hack */
96 this_ldata = MIN(ldata,max_send - (500+this_lparam));
98 align = ((this_lparam)%4);
100 set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
102 if (buffer_too_large) {
103 /* issue a buffer size warning. on a DCE/RPC pipe, expect an SMBreadX... */
104 if (!(global_client_caps & CAP_STATUS32 )) {
105 /* Win9x version. */
106 SSVAL(outbuf, smb_err, ERRmoredata);
107 SCVAL(outbuf, smb_rcls, ERRDOS);
108 } else {
109 SIVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
110 SIVAL(outbuf, smb_rcls, NT_STATUS_V(STATUS_BUFFER_OVERFLOW));
114 copy_trans_params_and_data(outbuf, align,
115 rparam, tot_param_sent, this_lparam,
116 rdata, tot_data_sent, this_ldata);
118 SSVAL(outbuf,smb_vwv0,lparam);
119 SSVAL(outbuf,smb_vwv1,ldata);
120 SSVAL(outbuf,smb_vwv3,this_lparam);
121 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
122 SSVAL(outbuf,smb_vwv5,0);
123 SSVAL(outbuf,smb_vwv6,this_ldata);
124 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
125 SSVAL(outbuf,smb_vwv8,0);
126 SSVAL(outbuf,smb_vwv9,0);
128 show_msg(outbuf);
129 if (!send_smb(smbd_server_fd(),outbuf))
130 exit_server("send_trans_reply: send_smb failed.\n");
132 tot_data_sent = this_ldata;
133 tot_param_sent = this_lparam;
135 while (tot_data_sent < ldata || tot_param_sent < lparam)
137 this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
138 this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
140 if(this_lparam < 0)
141 this_lparam = 0;
143 if(this_ldata < 0)
144 this_ldata = 0;
146 align = (this_lparam%4);
148 set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
150 copy_trans_params_and_data(outbuf, align,
151 rparam, tot_param_sent, this_lparam,
152 rdata, tot_data_sent, this_ldata);
154 SSVAL(outbuf,smb_vwv3,this_lparam);
155 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
156 SSVAL(outbuf,smb_vwv5,tot_param_sent);
157 SSVAL(outbuf,smb_vwv6,this_ldata);
158 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
159 SSVAL(outbuf,smb_vwv8,tot_data_sent);
160 SSVAL(outbuf,smb_vwv9,0);
162 show_msg(outbuf);
163 if (!send_smb(smbd_server_fd(),outbuf))
164 exit_server("send_trans_reply: send_smb failed.\n");
166 tot_data_sent += this_ldata;
167 tot_param_sent += this_lparam;
171 /****************************************************************************
172 Start the first part of an RPC reply which began with an SMBtrans request.
173 ****************************************************************************/
175 static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p)
177 char *rdata = malloc(p->max_trans_reply);
178 int data_len;
180 if(rdata == NULL) {
181 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
182 return False;
185 if((data_len = read_from_pipe( p, rdata, p->max_trans_reply)) < 0) {
186 SAFE_FREE(rdata);
187 return False;
190 send_trans_reply(outbuf, NULL, 0, rdata, data_len, p->out_data.current_pdu_len > data_len);
192 SAFE_FREE(rdata);
193 return True;
196 /****************************************************************************
197 WaitNamedPipeHandleState
198 ****************************************************************************/
200 static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
202 uint16 priority;
204 if (!param || param_len < 2)
205 return False;
207 priority = SVAL(param,0);
208 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
210 if (wait_rpc_pipe_hnd_state(p, priority)) {
211 /* now send the reply */
212 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
213 return True;
215 return False;
219 /****************************************************************************
220 SetNamedPipeHandleState
221 ****************************************************************************/
223 static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
225 uint16 id;
227 if (!param || param_len < 2)
228 return False;
230 id = SVAL(param,0);
231 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
233 if (set_rpc_pipe_hnd_state(p, id)) {
234 /* now send the reply */
235 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
236 return True;
238 return False;
242 /****************************************************************************
243 When no reply is generated, indicate unsupported.
244 ****************************************************************************/
246 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
248 char rparam[4];
250 /* unsupported */
251 SSVAL(rparam,0,NERR_notsupported);
252 SSVAL(rparam,2,0); /* converter word */
254 DEBUG(3,("Unsupported API fd command\n"));
256 /* now send the reply */
257 send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
259 return -1;
262 /****************************************************************************
263 Handle remote api calls delivered to a named pipe already opened.
264 ****************************************************************************/
266 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
267 uint16 *setup,char *data,char *params,
268 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
270 BOOL reply = False;
271 pipes_struct *p = NULL;
272 int pnum;
273 int subcommand;
275 DEBUG(5,("api_fd_reply\n"));
277 /* First find out the name of this file. */
278 if (suwcnt != 2) {
279 DEBUG(0,("Unexpected named pipe transaction.\n"));
280 return(-1);
283 /* Get the file handle and hence the file name. */
285 * NB. The setup array has already been transformed
286 * via SVAL and so is in gost byte order.
288 pnum = ((int)setup[1]) & 0xFFFF;
289 subcommand = ((int)setup[0]) & 0xFFFF;
291 if(!(p = get_rpc_pipe(pnum))) {
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)", 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 0x26:
305 /* dce/rpc command */
306 reply = write_to_pipe(p, data, tdscnt);
307 if (reply)
308 reply = api_rpc_trans_reply(outbuf, p);
309 break;
310 case 0x53:
311 /* Wait Named Pipe Handle state */
312 reply = api_WNPHS(outbuf, p, params, tpscnt);
313 break;
314 case 0x01:
315 /* Set Named Pipe Handle state */
316 reply = api_SNPHS(outbuf, p, params, tpscnt);
317 break;
320 if (!reply)
321 return api_no_reply(outbuf, mdrcnt);
323 return -1;
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);
352 if (setup)
353 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
355 return 0;
359 /****************************************************************************
360 Reply to a SMBtrans.
361 ****************************************************************************/
363 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
365 fstring name;
366 int name_offset = 0;
367 char *data=NULL,*params=NULL;
368 uint16 *setup=NULL;
369 int outsize = 0;
370 uint16 vuid = SVAL(inbuf,smb_uid);
371 int tpscnt = SVAL(inbuf,smb_vwv0);
372 int tdscnt = SVAL(inbuf,smb_vwv1);
373 int mprcnt = SVAL(inbuf,smb_vwv2);
374 int mdrcnt = SVAL(inbuf,smb_vwv3);
375 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 int pscnt = SVAL(inbuf,smb_vwv9);
379 int psoff = SVAL(inbuf,smb_vwv10);
380 int dscnt = SVAL(inbuf,smb_vwv11);
381 int dsoff = SVAL(inbuf,smb_vwv12);
382 int suwcnt = CVAL(inbuf,smb_vwv13);
383 START_PROFILE(SMBtrans);
385 memset(name, '\0',sizeof(name));
386 fstrcpy(name,smb_buf(inbuf));
388 if (dscnt > tdscnt || pscnt > tpscnt) {
389 exit_server("invalid trans parameters\n");
392 if (tdscnt) {
393 if((data = (char *)malloc(tdscnt)) == NULL) {
394 DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
395 END_PROFILE(SMBtrans);
396 return(ERROR_DOS(ERRDOS,ERRnomem));
398 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
401 if (tpscnt) {
402 if((params = (char *)malloc(tpscnt)) == NULL) {
403 DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
404 END_PROFILE(SMBtrans);
405 return(ERROR_DOS(ERRDOS,ERRnomem));
407 memcpy(params,smb_base(inbuf)+psoff,pscnt);
410 if (suwcnt) {
411 int i;
412 if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
413 DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
414 END_PROFILE(SMBtrans);
415 return(ERROR_DOS(ERRDOS,ERRnomem));
417 for (i=0;i<suwcnt;i++)
418 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
422 if (pscnt < tpscnt || dscnt < tdscnt) {
423 /* We need to send an interim response then receive the rest
424 of the parameter/data bytes */
425 outsize = set_message(outbuf,0,0,True);
426 show_msg(outbuf);
427 if (!send_smb(smbd_server_fd(),outbuf))
428 exit_server("reply_trans: send_smb failed.\n");
431 /* receive the rest of the trans packet */
432 while (pscnt < tpscnt || dscnt < tdscnt) {
433 BOOL ret;
434 int pcnt,poff,dcnt,doff,pdisp,ddisp;
436 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
438 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
439 if(ret) {
440 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
441 } else {
442 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
443 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
445 SAFE_FREE(params);
446 SAFE_FREE(data);
447 SAFE_FREE(setup);
448 END_PROFILE(SMBtrans);
449 return(ERROR_DOS(ERRSRV,ERRerror));
452 show_msg(inbuf);
454 tpscnt = SVAL(inbuf,smb_vwv0);
455 tdscnt = SVAL(inbuf,smb_vwv1);
457 pcnt = SVAL(inbuf,smb_vwv2);
458 poff = SVAL(inbuf,smb_vwv3);
459 pdisp = SVAL(inbuf,smb_vwv4);
461 dcnt = SVAL(inbuf,smb_vwv5);
462 doff = SVAL(inbuf,smb_vwv6);
463 ddisp = SVAL(inbuf,smb_vwv7);
465 pscnt += pcnt;
466 dscnt += dcnt;
468 if (dscnt > tdscnt || pscnt > tpscnt) {
469 exit_server("invalid trans parameters\n");
472 if (pcnt)
473 memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
474 if (dcnt)
475 memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
479 DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
480 name,tdscnt,tpscnt,suwcnt));
483 * WinCE wierdness....
486 if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
487 (name[strlen(local_machine)+1] == '\\'))
488 name_offset = strlen(local_machine)+1;
490 if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
491 name_offset += strlen("\\PIPE");
493 /* Win9x weirdness. When talking to a unicode server Win9x
494 only sends \PIPE instead of \PIPE\ */
496 if (name[name_offset] == '\\')
497 name_offset++;
499 DEBUG(5,("calling named_pipe\n"));
500 outsize = named_pipe(conn,vuid,outbuf,
501 name+name_offset,setup,data,params,
502 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
503 } else {
504 DEBUG(3,("invalid pipe name\n"));
505 outsize = 0;
509 SAFE_FREE(data);
510 SAFE_FREE(params);
511 SAFE_FREE(setup);
513 if (close_on_completion)
514 close_cnum(conn,vuid);
516 if (one_way) {
517 END_PROFILE(SMBtrans);
518 return(-1);
521 if (outsize == 0) {
522 END_PROFILE(SMBtrans);
523 return(ERROR_DOS(ERRSRV,ERRnosupport));
526 END_PROFILE(SMBtrans);
527 return(outsize);