1/* 2 Unix SMB/CIFS implementation. 3 Inter-process communication and named pipe handling 4 Copyright (C) Andrew Tridgell 1992-1998 5 6 SMB Version handling 7 Copyright (C) John H Terpstra 1995-1998 8 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. 13 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. 18 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. 22 */ 23/* 24 This file handles the named pipe and mailslot calls 25 in the SMBtrans protocol 26 */ 27 28#include "includes.h" 29 30extern int max_send; 31 32#define NERR_notsupported 50 33 34extern int smb_read_error; 35 36/******************************************************************* 37 copies parameters and data, as needed, into the smb buffer 38 39 *both* the data and params sections should be aligned. this 40 is fudged in the rpc pipes by 41 at present, only the data section is. this may be a possible 42 cause of some of the ipc problems being experienced. lkcl26dec97 43 44 ******************************************************************/ 45 46static void copy_trans_params_and_data(char *outbuf, int align, 47 char *rparam, int param_offset, int param_len, 48 char *rdata, int data_offset, int data_len) 49{ 50 char *copy_into = smb_buf(outbuf)+1; 51 52 if(param_len < 0) 53 param_len = 0; 54 55 if(data_len < 0) 56 data_len = 0; 57 58 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n", 59 param_offset, param_offset + param_len, 60 data_offset , data_offset + data_len)); 61 62 if (param_len) 63 memcpy(copy_into, &rparam[param_offset], param_len); 64 65 copy_into += param_len + align; 66 67 if (data_len ) 68 memcpy(copy_into, &rdata[data_offset], data_len); 69} 70 71/**************************************************************************** 72 Send a trans reply. 73 ****************************************************************************/ 74 75void send_trans_reply(char *outbuf, 76 char *rparam, int rparam_len, 77 char *rdata, int rdata_len, 78 BOOL buffer_too_large) 79{ 80 int this_ldata,this_lparam; 81 int tot_data_sent = 0; 82 int tot_param_sent = 0; 83 int align; 84 85 int ldata = rdata ? rdata_len : 0; 86 int lparam = rparam ? rparam_len : 0; 87 88 if (buffer_too_large) 89 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata )); 90 91 this_lparam = MIN(lparam,max_send - 500); /* hack */ 92 this_ldata = MIN(ldata,max_send - (500+this_lparam)); 93 94 align = ((this_lparam)%4); 95 96 if (buffer_too_large) { 97 ERROR_BOTH(STATUS_BUFFER_OVERFLOW,ERRDOS,ERRmoredata); 98 } 99 100 set_message(outbuf,10,1+align+this_ldata+this_lparam,True); 101 102 copy_trans_params_and_data(outbuf, align, 103 rparam, tot_param_sent, this_lparam, 104 rdata, tot_data_sent, this_ldata); 105 106 SSVAL(outbuf,smb_vwv0,lparam); 107 SSVAL(outbuf,smb_vwv1,ldata); 108 SSVAL(outbuf,smb_vwv3,this_lparam); 109 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); 110 SSVAL(outbuf,smb_vwv5,0); 111 SSVAL(outbuf,smb_vwv6,this_ldata); 112 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf)); 113 SSVAL(outbuf,smb_vwv8,0); 114 SSVAL(outbuf,smb_vwv9,0); 115 116 show_msg(outbuf); 117 if (!send_smb(smbd_server_fd(),outbuf)) 118 exit_server("send_trans_reply: send_smb failed."); 119 120 tot_data_sent = this_ldata; 121 tot_param_sent = this_lparam; 122 123 while (tot_data_sent < ldata || tot_param_sent < lparam) 124 { 125 this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */ 126 this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam)); 127 128 if(this_lparam < 0) 129 this_lparam = 0; 130 131 if(this_ldata < 0) 132 this_ldata = 0; 133 134 align = (this_lparam%4); 135 136 set_message(outbuf,10,1+this_ldata+this_lparam+align,False); 137 138 copy_trans_params_and_data(outbuf, align, 139 rparam, tot_param_sent, this_lparam, 140 rdata, tot_data_sent, this_ldata); 141 142 SSVAL(outbuf,smb_vwv3,this_lparam); 143 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); 144 SSVAL(outbuf,smb_vwv5,tot_param_sent); 145 SSVAL(outbuf,smb_vwv6,this_ldata); 146 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf)); 147 SSVAL(outbuf,smb_vwv8,tot_data_sent); 148 SSVAL(outbuf,smb_vwv9,0); 149 150 show_msg(outbuf); 151 if (!send_smb(smbd_server_fd(),outbuf)) 152 exit_server("send_trans_reply: send_smb failed."); 153 154 tot_data_sent += this_ldata; 155 tot_param_sent += this_lparam; 156 } 157} 158 159/**************************************************************************** 160 Start the first part of an RPC reply which began with an SMBtrans request. 161****************************************************************************/ 162 163static BOOL api_rpc_trans_reply(char *outbuf, smb_np_struct *p) 164{ 165 BOOL is_data_outstanding; 166 char *rdata = SMB_MALLOC(p->max_trans_reply); 167 int data_len; 168 169 if(rdata == NULL) { 170 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n")); 171 return False; 172 } 173 174 if((data_len = read_from_pipe( p, rdata, p->max_trans_reply, 175 &is_data_outstanding)) < 0) { 176 SAFE_FREE(rdata); 177 return False; 178 } 179 180 send_trans_reply(outbuf, NULL, 0, rdata, data_len, is_data_outstanding); 181 182 SAFE_FREE(rdata); 183 return True; 184} 185 186/**************************************************************************** 187 WaitNamedPipeHandleState 188****************************************************************************/ 189 190static BOOL api_WNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len) 191{ 192 uint16 priority; 193 194 if (!param || param_len < 2) 195 return False; 196 197 priority = SVAL(param,0); 198 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority)); 199 200 if (wait_rpc_pipe_hnd_state(p, priority)) { 201 /* now send the reply */ 202 send_trans_reply(outbuf, NULL, 0, NULL, 0, False); 203 return True; 204 } 205 return False; 206} 207 208 209/**************************************************************************** 210 SetNamedPipeHandleState 211****************************************************************************/ 212 213static BOOL api_SNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len) 214{ 215 uint16 id; 216 217 if (!param || param_len < 2) 218 return False; 219 220 id = SVAL(param,0); 221 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id)); 222 223 if (set_rpc_pipe_hnd_state(p, id)) { 224 /* now send the reply */ 225 send_trans_reply(outbuf, NULL, 0, NULL, 0, False); 226 return True; 227 } 228 return False; 229} 230 231 232/**************************************************************************** 233 When no reply is generated, indicate unsupported. 234 ****************************************************************************/ 235 236static BOOL api_no_reply(char *outbuf, int max_rdata_len) 237{ 238 char rparam[4]; 239 240 /* unsupported */ 241 SSVAL(rparam,0,NERR_notsupported); 242 SSVAL(rparam,2,0); /* converter word */ 243 244 DEBUG(3,("Unsupported API fd command\n")); 245 246 /* now send the reply */ 247 send_trans_reply(outbuf, rparam, 4, NULL, 0, False); 248 249 return -1; 250} 251 252/**************************************************************************** 253 Handle remote api calls delivered to a named pipe already opened. 254 ****************************************************************************/ 255 256static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf, 257 uint16 *setup,char *data,char *params, 258 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt) 259{ 260 BOOL reply = False; 261 smb_np_struct *p = NULL; 262 int pnum; 263 int subcommand; 264 265 DEBUG(5,("api_fd_reply\n")); 266 267 /* First find out the name of this file. */ 268 if (suwcnt != 2) { 269 DEBUG(0,("Unexpected named pipe transaction.\n")); 270 return ERROR_NT(NT_STATUS_INVALID_PARAMETER); 271 } 272 273 /* Get the file handle and hence the file name. */ 274 /* 275 * NB. The setup array has already been transformed 276 * via SVAL and so is in gost byte order. 277 */ 278 pnum = ((int)setup[1]) & 0xFFFF; 279 subcommand = ((int)setup[0]) & 0xFFFF; 280 281 if(!(p = get_rpc_pipe(pnum))) { 282 if (subcommand == TRANSACT_WAITNAMEDPIPEHANDLESTATE) { 283 /* Win9x does this call with a unicode pipe name, not a pnum. */ 284 /* Just return success for now... */ 285 DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n")); 286 send_trans_reply(outbuf, NULL, 0, NULL, 0, False); 287 return -1; 288 } 289 290 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum)); 291 return ERROR_NT(NT_STATUS_INVALID_HANDLE); 292 } 293 294 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", subcommand, p->name, pnum)); 295 296 /* record maximum data length that can be transmitted in an SMBtrans */ 297 p->max_trans_reply = mdrcnt; 298 299 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply)); 300 301 switch (subcommand) { 302 case TRANSACT_DCERPCCMD: 303 /* dce/rpc command */ 304 reply = write_to_pipe(p, data, tdscnt); 305 if (reply) 306 reply = api_rpc_trans_reply(outbuf, p); 307 break; 308 case TRANSACT_WAITNAMEDPIPEHANDLESTATE: 309 /* Wait Named Pipe Handle state */ 310 reply = api_WNPHS(outbuf, p, params, tpscnt); 311 break; 312 case TRANSACT_SETNAMEDPIPEHANDLESTATE: 313 /* Set Named Pipe Handle state */ 314 reply = api_SNPHS(outbuf, p, params, tpscnt); 315 break; 316 default: 317 return ERROR_NT(NT_STATUS_INVALID_PARAMETER); 318 } 319 320 if (!reply) 321 return api_no_reply(outbuf, mdrcnt); 322 323 return -1; 324} 325 326/**************************************************************************** 327 handle named pipe commands 328 ****************************************************************************/ 329static 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) 333{ 334 DEBUG(3,("named pipe command on <%s> name\n", name)); 335 336 if (strequal(name,"LANMAN")) 337 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt); 338 339 if (strequal(name,"WKSSVC") || 340 strequal(name,"SRVSVC") || 341 strequal(name,"WINREG") || 342 strequal(name,"SAMR") || 343 strequal(name,"LSARPC")) 344 { 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); 347 } 348 349 if (strlen(name) < 1) 350 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt); 351 352 if (setup) 353 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1])); 354 355 return 0; 356} 357 358 359/**************************************************************************** 360 Reply to a SMBtrans. 361 ****************************************************************************/ 362 363int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize) 364{ 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 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 fstring local_machine_name; 384 START_PROFILE(SMBtrans); 385 386 memset(name, '\0',sizeof(name)); 387 srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE); 388 389 if (dscnt > tdscnt || pscnt > tpscnt) 390 goto bad_param; 391 392 if (tdscnt) { 393 if((data = (char *)SMB_MALLOC(tdscnt)) == NULL) { 394 DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt)); 395 END_PROFILE(SMBtrans); 396 return(ERROR_DOS(ERRDOS,ERRnomem)); 397 } 398 if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt)) 399 goto bad_param; 400 if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) || 401 (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf))) 402 goto bad_param; 403 404 memcpy(data,smb_base(inbuf)+dsoff,dscnt); 405 } 406 407 if (tpscnt) { 408 if((params = (char *)SMB_MALLOC(tpscnt)) == NULL) { 409 DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt)); 410 SAFE_FREE(data); 411 END_PROFILE(SMBtrans); 412 return(ERROR_DOS(ERRDOS,ERRnomem)); 413 } 414 if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt)) 415 goto bad_param; 416 if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) || 417 (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf))) 418 goto bad_param; 419 420 memcpy(params,smb_base(inbuf)+psoff,pscnt); 421 } 422 423 if (suwcnt) { 424 unsigned int i; 425 if((setup = SMB_MALLOC_ARRAY(uint16,suwcnt)) == NULL) { 426 DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16)))); 427 SAFE_FREE(data); 428 SAFE_FREE(params); 429 END_PROFILE(SMBtrans); 430 return(ERROR_DOS(ERRDOS,ERRnomem)); 431 } 432 if (inbuf+smb_vwv14+(suwcnt*SIZEOFWORD) > inbuf + size) 433 goto bad_param; 434 if ((smb_vwv14+(suwcnt*SIZEOFWORD) < smb_vwv14) || (smb_vwv14+(suwcnt*SIZEOFWORD) < (suwcnt*SIZEOFWORD))) 435 goto bad_param; 436 437 for (i=0;i<suwcnt;i++) 438 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD); 439 } 440 441 442 srv_signing_trans_start(SVAL(inbuf,smb_mid)); 443 444 if (pscnt < tpscnt || dscnt < tdscnt) { 445 /* We need to send an interim response then receive the rest 446 of the parameter/data bytes */ 447 outsize = set_message(outbuf,0,0,True); 448 show_msg(outbuf); 449 srv_signing_trans_stop(); 450 if (!send_smb(smbd_server_fd(),outbuf)) 451 exit_server("reply_trans: send_smb failed."); 452 } 453 454 /* receive the rest of the trans packet */ 455 while (pscnt < tpscnt || dscnt < tdscnt) { 456 BOOL ret; 457 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp; 458 459 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); 460 461 /* 462 * The sequence number for the trans reply is always 463 * based on the last secondary received. 464 */ 465 466 srv_signing_trans_start(SVAL(inbuf,smb_mid)); 467 468 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) { 469 if(ret) { 470 DEBUG(0,("reply_trans: Invalid secondary trans packet\n")); 471 } else { 472 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n", 473 (smb_read_error == READ_ERROR) ? "error" : "timeout" )); 474 } 475 SAFE_FREE(params); 476 SAFE_FREE(data); 477 SAFE_FREE(setup); 478 END_PROFILE(SMBtrans); 479 srv_signing_trans_stop(); 480 return(ERROR_DOS(ERRSRV,ERRerror)); 481 } 482 483 show_msg(inbuf); 484 485 /* Revise total_params and total_data in case they have changed downwards */ 486 if (SVAL(inbuf,smb_vwv0) < tpscnt) 487 tpscnt = SVAL(inbuf,smb_vwv0); 488 if (SVAL(inbuf,smb_vwv1) < tdscnt) 489 tdscnt = SVAL(inbuf,smb_vwv1); 490 491 pcnt = SVAL(inbuf,smb_vwv2); 492 poff = SVAL(inbuf,smb_vwv3); 493 pdisp = SVAL(inbuf,smb_vwv4); 494 495 dcnt = SVAL(inbuf,smb_vwv5); 496 doff = SVAL(inbuf,smb_vwv6); 497 ddisp = SVAL(inbuf,smb_vwv7); 498 499 pscnt += pcnt; 500 dscnt += dcnt; 501 502 if (dscnt > tdscnt || pscnt > tpscnt) 503 goto bad_param; 504 505 if (pcnt) { 506 if (pdisp+pcnt > tpscnt) 507 goto bad_param; 508 if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt)) 509 goto bad_param; 510 if (pdisp > tpscnt) 511 goto bad_param; 512 if ((smb_base(inbuf) + poff + pcnt >= inbuf + bufsize) || 513 (smb_base(inbuf) + poff + pcnt < smb_base(inbuf))) 514 goto bad_param; 515 if (params + pdisp < params) 516 goto bad_param; 517 518 memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt); 519 } 520 521 if (dcnt) { 522 if (ddisp+dcnt > tdscnt) 523 goto bad_param; 524 if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt)) 525 goto bad_param; 526 if (ddisp > tdscnt) 527 goto bad_param; 528 if ((smb_base(inbuf) + doff + dcnt >= inbuf + bufsize) || 529 (smb_base(inbuf) + doff + dcnt < smb_base(inbuf))) 530 goto bad_param; 531 if (data + ddisp < data) 532 goto bad_param; 533 534 memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt); 535 } 536 } 537 538 DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n", 539 name,tdscnt,tpscnt,suwcnt)); 540 541 /* 542 * WinCE wierdness.... 543 */ 544 545 fstrcpy( local_machine_name, get_local_machine_name() ); 546 547 if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine_name, strlen(local_machine_name)) == 0) && 548 (name[strlen(local_machine_name)+1] == '\\')) 549 name_offset = strlen(local_machine_name)+1; 550 551 if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) { 552 name_offset += strlen("\\PIPE"); 553 554 /* Win9x weirdness. When talking to a unicode server Win9x 555 only sends \PIPE instead of \PIPE\ */ 556 557 if (name[name_offset] == '\\') 558 name_offset++; 559 560 DEBUG(5,("calling named_pipe\n")); 561 outsize = named_pipe(conn,vuid,outbuf, 562 name+name_offset,setup,data,params, 563 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt); 564 } else { 565 DEBUG(3,("invalid pipe name\n")); 566 outsize = 0; 567 } 568 569 570 SAFE_FREE(data); 571 SAFE_FREE(params); 572 SAFE_FREE(setup); 573 574 srv_signing_trans_stop(); 575 576 if (close_on_completion) 577 close_cnum(conn,vuid); 578 579 if (one_way) { 580 END_PROFILE(SMBtrans); 581 return(-1); 582 } 583 584 if (outsize == 0) { 585 END_PROFILE(SMBtrans); 586 return(ERROR_DOS(ERRSRV,ERRnosupport)); 587 } 588 589 END_PROFILE(SMBtrans); 590 return(outsize); 591 592 593 bad_param: 594 595 srv_signing_trans_stop(); 596 DEBUG(0,("reply_trans: invalid trans parameters\n")); 597 SAFE_FREE(data); 598 SAFE_FREE(params); 599 SAFE_FREE(setup); 600 END_PROFILE(SMBtrans); 601 return ERROR_NT(NT_STATUS_INVALID_PARAMETER); 602} 603