put server-side long dce/rpc code in main branch.
[jra/samba/.git] / source3 / smbd / ipc.c
index e3db823a9df896623ff06fb848c8188c34d49197..74ae1152171b34b272ba833a79613f8a9a74b345 100644 (file)
@@ -2,10 +2,10 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Inter-process communication and named pipe handling
-   Copyright (C) Andrew Tridgell 1992-1997
+   Copyright (C) Andrew Tridgell 1992-1998
 
    SMB Version handling
-   Copyright (C) John H Terpstra 1995-1997
+   Copyright (C) John H Terpstra 1995-1998
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
    */
 
 #include "includes.h"
+#include "nterr.h"
 
 #ifdef CHECK_TYPES
 #undef CHECK_TYPES
@@ -131,79 +132,128 @@ static BOOL prefix_ok(char *str,char *prefix)
   return(strncmp(str,prefix,strlen(prefix)) == 0);
 }
 
+/*******************************************************************
+ copies parameters and data, as needed, into the smb buffer
+
+ *both* the data and params sections should be aligned.  this
+ is fudged in the rpc pipes by 
+ at present, only the data section is.  this may be a possible
+ cause of some of the ipc problems being experienced.  lkcl26dec97
+
+ ******************************************************************/
+static void copy_trans_params_and_data(char *outbuf, int align,
+                               struct mem_buf *rparam, struct mem_buf *rdata,
+                               int param_offset, int data_offset,
+                               int param_len, int data_len)
+{
+       char *copy_into = smb_buf(outbuf);
+
+       DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
+                       param_offset, param_offset + param_len,
+                       data_offset , data_offset  + data_len));
+
+       if (param_len) mem_buf_copy(copy_into, rparam, param_offset, param_len);
+       copy_into += param_len + align;
+       if (data_len ) mem_buf_copy(copy_into, rdata , data_offset , data_len);
+}
 
 /****************************************************************************
   send a trans reply
   ****************************************************************************/
-static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
-                            int ldata,int lparam,int lsetup)
+static void send_trans_reply(char *outbuf,
+                               struct mem_buf *rdata,
+                               struct mem_buf *rparam,
+                               uint16 *setup, int lsetup, int max_data_ret)
 {
-  int i;
-  int this_ldata,this_lparam;
-  int tot_data=0,tot_param=0;
-  int align;
+       int i;
+       int this_ldata,this_lparam;
+       int tot_data=0,tot_param=0;
+       int align;
+
+       int ldata  = rdata  ? mem_buf_len(rdata ) : 0;
+       int lparam = rparam ? mem_buf_len(rparam) : 0;
+
+       BOOL buffer_too_large = max_data_ret ? ldata > max_data_ret : False;
 
-  this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */
-  this_ldata = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam));
+       if (buffer_too_large)
+       {
+               DEBUG(5,("send_trans_reply: buffer %d too large %d\n", ldata, max_data_ret));
+               ldata = max_data_ret;
+       }
+
+       this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */
+       this_ldata  = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam));
 
 #ifdef CONFUSE_NETMONITOR_MSRPC_DECODING
-  /* if you don't want Net Monitor to decode your packets, do this!!! */
-  align = ((this_lparam+1)%4);
+       /* if you don't want Net Monitor to decode your packets, do this!!! */
+       align = ((this_lparam+1)%4);
 #else
-  align = (this_lparam%4);
+       align = (this_lparam%4);
 #endif
 
-  set_message(outbuf,10+lsetup,align+this_ldata+this_lparam,True);
-  if (this_lparam)
-    memcpy(smb_buf(outbuf),param,this_lparam);
-  if (this_ldata)
-    memcpy(smb_buf(outbuf)+this_lparam+align,data,this_ldata);
-
-  SSVAL(outbuf,smb_vwv0,lparam);
-  SSVAL(outbuf,smb_vwv1,ldata);
-  SSVAL(outbuf,smb_vwv3,this_lparam);
-  SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
-  SSVAL(outbuf,smb_vwv5,0);
-  SSVAL(outbuf,smb_vwv6,this_ldata);
-  SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
-  SSVAL(outbuf,smb_vwv8,0);
-  SSVAL(outbuf,smb_vwv9,lsetup);
-  for (i=0;i<lsetup;i++)
-    SSVAL(outbuf,smb_vwv10+i*SIZEOFWORD,setup[i]);
-
-  show_msg(outbuf);
-  send_smb(Client,outbuf);
-
-  tot_data = this_ldata;
-  tot_param = this_lparam;
-
-  while (tot_data < ldata || tot_param < lparam)
-    {
-      this_lparam = MIN(lparam-tot_param,max_send - 500); /* hack */
-      this_ldata = MIN(ldata-tot_data,max_send - (500+this_lparam));
+       set_message(outbuf,10+lsetup,align+this_ldata+this_lparam,True);
+
+       if (buffer_too_large)
+       {
+               /* issue a buffer size warning.  on a DCE/RPC pipe, expect an SMBreadX... */
+               SIVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+               SIVAL(outbuf, smb_rcls, 0x80000000 | NT_STATUS_ACCESS_VIOLATION);
+       }
+
+       copy_trans_params_and_data(outbuf, align,
+                                  rparam     , rdata,
+                                  tot_param  , tot_data,
+                                  this_lparam, this_ldata);
+
+       SSVAL(outbuf,smb_vwv0,lparam);
+       SSVAL(outbuf,smb_vwv1,ldata);
+       SSVAL(outbuf,smb_vwv3,this_lparam);
+       SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
+       SSVAL(outbuf,smb_vwv5,0);
+       SSVAL(outbuf,smb_vwv6,this_ldata);
+       SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
+       SSVAL(outbuf,smb_vwv8,0);
+       SSVAL(outbuf,smb_vwv9,lsetup);
+
+       for (i=0;i<lsetup;i++)
+       {
+               SSVAL(outbuf,smb_vwv10+i*SIZEOFWORD,setup[i]);
+       }
 
-      align = (this_lparam%4);
+       show_msg(outbuf);
+       send_smb(Client,outbuf);
 
-      set_message(outbuf,10,this_ldata+this_lparam+align,False);
-      if (this_lparam)
-       memcpy(smb_buf(outbuf),param+tot_param,this_lparam);
-      if (this_ldata)
-       memcpy(smb_buf(outbuf)+this_lparam+align,data+tot_data,this_ldata);
+       tot_data = this_ldata;
+       tot_param = this_lparam;
 
-      SSVAL(outbuf,smb_vwv3,this_lparam);
-      SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
-      SSVAL(outbuf,smb_vwv5,tot_param);
-      SSVAL(outbuf,smb_vwv6,this_ldata);
-      SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
-      SSVAL(outbuf,smb_vwv8,tot_data);
-      SSVAL(outbuf,smb_vwv9,0);
+       while (tot_data < ldata || tot_param < lparam)
+       {
+               this_lparam = MIN(lparam-tot_param, max_send - 500); /* hack */
+               this_ldata  = MIN(ldata -tot_data , max_send - (500+this_lparam));
 
-      show_msg(outbuf);
-      send_smb(Client,outbuf);
+               align = (this_lparam%4);
 
-      tot_data += this_ldata;
-      tot_param += this_lparam;
-    }
+               set_message(outbuf,10,this_ldata+this_lparam+align,False);
+
+               copy_trans_params_and_data(outbuf, align,
+                                          rparam     , rdata,
+                                          tot_param  , tot_data,
+                                          this_lparam, this_ldata);
+
+               SSVAL(outbuf,smb_vwv3,this_lparam);
+               SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
+               SSVAL(outbuf,smb_vwv5,tot_param);
+               SSVAL(outbuf,smb_vwv6,this_ldata);
+               SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
+               SSVAL(outbuf,smb_vwv8,tot_data);
+               SSVAL(outbuf,smb_vwv9,0);
+
+               show_msg(outbuf);
+               send_smb(Client,outbuf);
+
+               tot_data  += this_ldata;
+               tot_param += this_lparam;
+       }
 }
 
 struct pack_desc {
@@ -280,8 +330,9 @@ static BOOL init_package(struct pack_desc* p, int count, int subcount)
   p->subcount = 0;
   p->curpos = p->format;
   if (i > n) {
+    p->neededlen = i;
     i = n = 0;
-    p->errcode = NERR_BufTooSmall;
+    p->errcode = ERROR_MORE_DATA;
   }
   else
     p->errcode = NERR_Success;
@@ -406,7 +457,7 @@ va_dcl
     p->usedlen += needed;
   }
   else {
-    if (p->errcode == NERR_Success) p->errcode = NERR_BufTooSmall;
+    if (p->errcode == NERR_Success) p->errcode = ERROR_MORE_DATA;
   }
   return 1;
 }
@@ -1252,6 +1303,39 @@ static BOOL api_RNetServerEnum(int cnum, uint16 vuid, char *param, char *data,
   return(True);
 }
 
+/****************************************************************************
+  command 0x34 - suspected of being a "Lookup Names" stub api
+  ****************************************************************************/
+static BOOL api_RNetGroupGetUsers(int cnum, uint16 vuid, char *param, char *data,
+                              int mdrcnt, int mprcnt, char **rdata, 
+                              char **rparam, int *rdata_len, int *rparam_len)
+{
+  char *str1 = param+2;
+  char *str2 = skip_string(str1,1);
+  char *p = skip_string(str2,1);
+  int uLevel = SVAL(p,0);
+  int buf_len = SVAL(p,2);
+  int counted=0;
+  int missed=0;
+
+       DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
+               str1, str2, p, uLevel, buf_len));
+
+  if (!prefix_ok(str1,"zWrLeh")) return False;
+  
+  *rdata_len = 0;
+  *rdata = NULL;
+  
+  *rparam_len = 8;
+  *rparam = REALLOC(*rparam,*rparam_len);
+
+  SSVAL(*rparam,0,0x08AC); /* informational warning message */
+  SSVAL(*rparam,2,0);
+  SSVAL(*rparam,4,counted);
+  SSVAL(*rparam,6,counted+missed);
+
+  return(True);
+}
 
 /****************************************************************************
   get info about a share
@@ -1551,7 +1635,7 @@ static BOOL api_SetUserPassword(int cnum,uint16 vuid, char *param,char *data,
    */
 
   if (password_ok(user,pass1,strlen(pass1),NULL) &&
-      chgpasswd(user,pass1,pass2))
+      chgpasswd(user,pass1,pass2,False))
   {
     SSVAL(*rparam,0,NERR_Success);
   }
@@ -1579,6 +1663,69 @@ static BOOL api_SetUserPassword(int cnum,uint16 vuid, char *param,char *data,
   return(True);
 }
 
+/****************************************************************************
+  Set the user password (SamOEM version - gets plaintext).
+****************************************************************************/
+
+static BOOL api_SamOEMChangePassword(int cnum,uint16 vuid, char *param,char *data,
+                               int mdrcnt,int mprcnt,
+                               char **rdata,char **rparam,
+                               int *rdata_len,int *rparam_len)
+{
+  fstring user;
+  fstring new_passwd;
+  struct smb_passwd *smbpw = NULL;
+  char *p = param + 2;
+
+  *rparam_len = 2;
+  *rparam = REALLOC(*rparam,*rparam_len);
+
+  *rdata_len = 0;
+
+  SSVAL(*rparam,0,NERR_badpass);
+
+  /*
+   * Check the parameter definition is correct.
+   */
+  if(!strequal(param + 2, "zsT")) {
+    DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %sn\n", param + 2));
+    return False;
+  }
+  p = skip_string(p, 1);
+
+  if(!strequal(p, "B516B16")) {
+    DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %sn\n", p));
+    return False;
+  }
+  p = skip_string(p,1);
+
+  fstrcpy(user,p);
+  p = skip_string(p,1);
+
+  if(check_oem_password( user, (unsigned char *)data, &smbpw, 
+                         new_passwd, (int)sizeof(new_passwd)) == False) {
+    return True;
+  }
+
+  /* 
+   * At this point we have the new case-sensitive plaintext
+   * password in the fstring new_passwd. If we wanted to synchronise
+   * with UNIX passwords we would call a UNIX password changing 
+   * function here. However it would have to be done as root
+   * as the plaintext of the old users password is not 
+   * available. JRA.
+   */
+
+  if(lp_unix_password_sync())
+    chgpasswd(user,"", new_passwd, True);
+  if(change_oem_password( smbpw, new_passwd)) {
+    SSVAL(*rparam,0,NERR_Success);
+  }
+
+  return(True);
+}
+
 /****************************************************************************
   delete a print job
   Form: <W> <> 
@@ -2185,8 +2332,11 @@ static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data,
        char *p2;
 
     /* get NIS home of a previously validated user - simeon */
+    /* With share level security vuid will always be zero.
+       Don't depend on vuser being non-null !!. JRA */
     user_struct *vuser = get_valid_user_struct(vuid);
-    DEBUG(3,("  Username of UID %d is %s\n", vuser->uid, vuser->name));
+    if(vuser != NULL)
+      DEBUG(3,("  Username of UID %d is %s\n", vuser->uid, vuser->name));
 
     *rparam_len = 6;
     *rparam = REALLOC(*rparam,*rparam_len);
@@ -2236,7 +2386,7 @@ static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data,
 
                /* EEK! the cifsrap.txt doesn't have this in!!!! */
                SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
-               strcpy(p2,vuser->real_name);    /* simeon */
+               strcpy(p2,((vuser != NULL) ? vuser->real_name : UserName));
                p2 = skip_string(p2,1);
        }
 
@@ -2292,7 +2442,7 @@ static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data,
                {
                        SIVAL(p,60,0);          /* auth_flags */
                        SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
-                       strcpy(p2,vuser->real_name);    /* simeon */
+                       strcpy(p2,((vuser != NULL) ? vuser->real_name : UserName));
                        p2 = skip_string(p2,1);
                        SIVAL(p,68,0);          /* urs_comment */
                        SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
@@ -2920,175 +3070,334 @@ static BOOL api_WPrintPortEnum(int cnum,uint16 vuid, char *param,char *data,
   return(True);
 }
 
-
-struct
+struct api_cmd
 {
-  char * name;
   char * pipe_clnt_name;
-#ifdef NTDOMAIN
   char * pipe_srv_name;
-#endif
-  int subcommand;
-  BOOL (*fn) ();
-} api_fd_commands [] =
-  {
-#ifdef NTDOMAIN
-    { "TransactNmPipe",     "lsarpc",  "lsass",        0x26,   api_ntLsarpcTNP },
-    { "TransactNmPipe",     "samr",    "lsass",        0x26,   api_samrTNP },
-    { "TransactNmPipe",     "srvsvc",  "lsass",        0x26,   api_srvsvcTNP },
-    { "TransactNmPipe",     "wkssvc",  "ntsvcs",       0x26,   api_wkssvcTNP },
-    { "TransactNmPipe",     "NETLOGON",        "NETLOGON",     0x26,   api_netlogrpcTNP },
-    { NULL,                        NULL,       NULL,   -1,     (BOOL (*)())api_Unsupported }
-#else
-    { "TransactNmPipe"  ,      "lsarpc",       0x26,   api_LsarpcTNP },
-    { NULL,            NULL,           -1,     (BOOL (*)())api_Unsupported }
-#endif
-  };
+  BOOL (*fn) (pipes_struct *, prs_struct *);
+};
 
-/****************************************************************************
-  handle remote api calls delivered to a named pipe already opened.
-  ****************************************************************************/
-static int api_fd_reply(int cnum,uint16 vuid,char *outbuf,
-                       uint16 *setup,char *data,char *params,
-                       int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
+static struct api_cmd api_fd_commands[] =
 {
-  char *rdata = NULL;
-  char *rparam = NULL;
-  int rdata_len = 0;
-  int rparam_len = 0;
+    { "lsarpc",   "lsass",   api_ntlsa_rpc },
+    { "samr",     "lsass",   api_samr_rpc },
+    { "srvsvc",   "ntsvcs",  api_srvsvc_rpc },
+    { "wkssvc",   "ntsvcs",  api_wkssvc_rpc },
+    { "NETLOGON", "lsass",   api_netlog_rpc },
+    { "winreg",   "winreg",  api_reg_rpc },
+    { NULL,       NULL,      NULL }
+};
 
-  BOOL reply    = False;
-  BOOL bind_req = False;
-  BOOL set_nphs = False;
+static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd)
+{
+       BOOL ntlmssp_auth = False;
+       fstring ack_pipe_name;
+       int i = 0;
 
-  int i;
-  int fd;
-  int subcommand;
-  char *pipe_name;
-  
-  DEBUG(5,("api_fd_reply\n"));
-  /* First find out the name of this file. */
-  if (suwcnt != 2)
-    {
-      DEBUG(0,("Unexpected named pipe transaction.\n"));
-      return(-1);
-    }
-  
-  /* Get the file handle and hence the file name. */
-  fd = setup[1];
-  subcommand = setup[0];
-  pipe_name = get_rpc_pipe_hnd_name(fd);
+       DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__));
 
-  if (pipe_name == NULL)
-  {
-    DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", fd));
-  }
+       for (i = 0; api_fd_commands[i].pipe_clnt_name; i++)
+       {
+               if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) &&
+                   api_fd_commands[i].fn != NULL)
+               {
+                       DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
+                                  api_fd_commands[i].pipe_clnt_name,
+                                  api_fd_commands[i].pipe_srv_name));
+                       fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name);
+                       break;
+               }
+       }
 
-  DEBUG(3,("Got API command %d on pipe %s (fd %x)",
-            subcommand, pipe_name, fd));
-  DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d,cnum=%d,vuid=%d)\n",
-          tdscnt,tpscnt,mdrcnt,mprcnt,cnum,vuid));
-  
-  for (i = 0; api_fd_commands[i].name; i++)
-  {
-    if (strequal(api_fd_commands[i].pipe_clnt_name, pipe_name) &&
-           api_fd_commands[i].subcommand == subcommand &&
-           api_fd_commands[i].fn)
-    {
-         DEBUG(3,("Doing %s\n", api_fd_commands[i].name));
-         break;
-    }
-  }
-  
-  rdata  = (char *)malloc(1024); if (rdata ) bzero(rdata ,1024);
-  rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
-  
-#ifdef NTDOMAIN
-  /* RPC Pipe command 0x26. */
-  if (data != NULL && api_fd_commands[i].subcommand == 0x26)
-  {
-    RPC_HDR hdr;
+       if (api_fd_commands[i].fn == NULL) return False;
 
-    /* process the rpc header */
-    char *q = smb_io_rpc_hdr(True, &hdr, data, data, 4, 0);
-    
-       /* bind request received */
-    if ((bind_req = ((q != NULL) && (hdr.pkt_type == RPC_BIND))))
-    {
-      RPC_HDR_RB hdr_rb;
+       /* decode the bind request */
+       smb_io_rpc_hdr_rb("", &p->hdr_rb, pd, 0);
 
-      /* decode the bind request */
-      char *p = smb_io_rpc_hdr_rb(True, &hdr_rb, q, data, 4, 0);
+       if (pd->offset == 0) return False;
 
-      if ((bind_req = (p != NULL)))
-      {
-        RPC_HDR_BA hdr_ba;
-        fstring ack_pipe_name;
+       if (p->hdr.auth_len != 0)
+       {
+               /* decode the authentication verifier */
+               smb_io_rpc_auth_ntlmssp_req("", &p->ntlmssp_req, pd, 0);
 
-        /* name has to be \PIPE\xxxxx */
-        strcpy(ack_pipe_name, "\\PIPE\\");
-        strcat(ack_pipe_name, api_fd_commands[i].pipe_srv_name);
+               if (pd->offset == 0) return False;
 
-        /* make a bind acknowledgement */
-        make_rpc_hdr_ba(&hdr_ba,
-               hdr_rb.bba.max_tsize, hdr_rb.bba.max_rsize, hdr_rb.bba.assoc_gid,
-               ack_pipe_name,
-               0x1, 0x0, 0x0,
-               &(hdr_rb.transfer));
+               /* ignore the version number for now */
+               ntlmssp_auth = strequal(p->ntlmssp_req.ntlmssp_str, "NTLMSSP");
+       }
 
-        p = smb_io_rpc_hdr_ba(False, &hdr_ba, rdata + 0x10, rdata, 4, 0);
+       /* name has to be \PIPE\xxxxx */
+       strcpy(ack_pipe_name, "\\PIPE\\");
+       strcat(ack_pipe_name, p->pipe_srv_name);
 
-               rdata_len = PTR_DIFF(p, rdata);
+       DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));
 
-        make_rpc_hdr(&hdr, RPC_BINDACK, 0x0, hdr.call_id, rdata_len);
+       prs_init(&(p->rdata), 1024, 4, 0, False);
+       prs_init(&(p->rhdr ), 0x10, 4, 0, False);
+       prs_init(&(p->rauth), 1024, 4, 0, False);
 
-        p = smb_io_rpc_hdr(False, &hdr, rdata, rdata, 4, 0);
-        
-        reply = (p != NULL);
-      }
-    }
-  }
-#endif
+    /***/
+       /*** do the bind ack first ***/
+    /***/
 
-  /* Set Named Pipe Handle state */
-  if (subcommand == 0x1)
-  {
-    set_nphs = True;
-    reply = api_LsarpcSNPHS(fd, cnum, params);
-  }
+       make_rpc_hdr_ba(&p->hdr_ba,
+                                       p->hdr_rb.bba.max_tsize,
+                       p->hdr_rb.bba.max_rsize,
+                       p->hdr_rb.bba.assoc_gid,
+                                       ack_pipe_name,
+                                       0x1, 0x0, 0x0,
+                                       &(p->hdr_rb.transfer));
 
-  if (!bind_req && !set_nphs)
-  {
-    DEBUG(10,("calling api_fd_command\n"));
+       smb_io_rpc_hdr_ba("", &p->hdr_ba, &p->rdata, 0);
+       mem_realloc_data(p->rdata.data, p->rdata.offset);
 
-    reply = api_fd_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt,
-                               &rdata,&rparam,&rdata_len,&rparam_len);
-    DEBUG(10,("called api_fd_command\n"));
-  }
+    /***/
+       /*** now the authentication ***/
+    /***/
 
-  if (rdata_len > mdrcnt || rparam_len > mprcnt)
-  {
-    reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt,
-                          &rdata,&rparam,&rdata_len,&rparam_len);
-  }
-  
-  /* if we get False back then it's actually unsupported */
-  if (!reply)
-  {
-    api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt,
-                   &rdata,&rparam,&rdata_len,&rparam_len);
-  }
-  
-  /* now send the reply */
-  send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
-  
-  if (rdata ) free(rdata );
-  if (rparam) free(rparam);
-  
-  return(-1);
+       if (ntlmssp_auth)
+       {
+               uint8 data[16];
+               bzero(data, sizeof(data)); /* first 8 bytes are non-zero */
+
+               make_rpc_auth_ntlmssp_resp(&p->ntlmssp_resp,
+                                          0x0a, 0x06, 0,
+                                          "NTLMSSP", 2,
+                                          0x00000000, 0x0000b2b3, 0x000082b1,
+                                          data);
+               smb_io_rpc_auth_ntlmssp_resp("", &p->ntlmssp_resp, &p->rauth, 0);
+               mem_realloc_data(p->rauth.data, p->rauth.offset);
+       }
+
+    /***/
+       /*** then do the header, now we know the length ***/
+    /***/
+
+       make_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+                                p->hdr.call_id,
+                    p->rdata.offset + p->rauth.offset,
+                    p->rauth.offset);
+
+       smb_io_rpc_hdr("", &p->hdr, &p->rhdr, 0);
+       mem_realloc_data(p->rhdr.data, p->rdata.offset);
+
+    /***/
+       /*** link rpc header, bind acknowledgment and authentication responses ***/
+    /***/
+
+       p->rhdr.data->offset.start = 0;
+       p->rhdr.data->offset.end   = p->rhdr.offset;
+       p->rhdr.data->next         = p->rdata.data;
+
+       if (ntlmssp_auth)
+       {
+               p->rdata.data->offset.start = p->rhdr.offset;
+               p->rdata.data->offset.end   = p->rhdr.offset + p->rdata.offset;
+               p->rdata.data->next         = p->rauth.data;
+
+               p->rauth.data->offset.start = p->rhdr.offset + p->rdata.offset;
+               p->rauth.data->offset.end   = p->rhdr.offset + p->rauth.offset + p->rdata.offset;
+               p->rauth.data->next         = NULL;
+       }
+       else
+       {
+               p->rdata.data->offset.start = p->rhdr.offset;
+               p->rdata.data->offset.end   = p->rhdr.offset + p->rdata.offset;
+               p->rdata.data->next         = NULL;
+       }
+
+       return True;
+}
+
+static BOOL api_pipe_request(pipes_struct *p, prs_struct *pd)
+{
+       int i = 0;
+
+       for (i = 0; api_fd_commands[i].pipe_clnt_name; i++)
+       {
+               if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) &&
+                   api_fd_commands[i].fn != NULL)
+               {
+                       DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name));
+                       return api_fd_commands[i].fn(p, pd);
+               }
+       }
+       return False;
+}
+
+static BOOL api_dce_rpc_command(char *outbuf,
+                               pipes_struct *p,
+                               prs_struct *pd)
+{
+       BOOL reply = False;
+       if (pd->data == NULL) return False;
+
+       /* process the rpc header */
+       smb_io_rpc_hdr("", &p->hdr, pd, 0);
+
+       if (pd->offset == 0) return False;
+
+       switch (p->hdr.pkt_type)
+       {
+               case RPC_BIND   :
+               {
+                       reply = api_pipe_bind_req(p, pd);
+                       break;
+               }
+               case RPC_REQUEST:
+               {
+                       reply = api_pipe_request (p, pd);
+                       break;
+               }
+       }
+
+       if (reply)
+       {
+               /* now send the reply */
+               send_trans_reply(outbuf, p->rhdr.data, NULL, NULL, 0, p->file_offset);
+
+               if (mem_buf_len(p->rhdr.data) <= p->file_offset)
+               {
+                       /* all of data was sent: no need to wait for SMBreadX calls */
+                       mem_free_data(p->rhdr .data);
+                       mem_free_data(p->rdata.data);
+               }
+       }
+
+       return reply;
+}
+
+/****************************************************************************
+ SetNamedPipeHandleState 
+****************************************************************************/
+static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param)
+{
+       uint16 id;
+
+       if (!param) return False;
+
+       id = param[0] + (param[1] << 8);
+       DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n", id));
+
+       if (set_rpc_pipe_hnd_state(p, id))
+       {
+               /* now send the reply */
+               send_trans_reply(outbuf, NULL, NULL, NULL, 0, p->file_offset);
+
+               return True;
+       }
+       return False;
 }
 
 
+/****************************************************************************
+ when no reply is generated, indicate unsupported.
+ ****************************************************************************/
+static BOOL api_no_reply(char *outbuf, int max_rdata_len)
+{
+       struct mem_buf rparam;
+
+       mem_init(&rparam, 0);
+       mem_alloc_data(&rparam, 4);
+
+       rparam.offset.start = 0;
+       rparam.offset.end   = 4;
+
+       /* unsupported */
+       SSVAL(rparam.data,0,NERR_notsupported);
+       SSVAL(rparam.data,2,0); /* converter word */
+
+       DEBUG(3,("Unsupported API fd command\n"));
+
+       /* now send the reply */
+       send_trans_reply(outbuf, NULL, &rparam, NULL, 0, max_rdata_len);
+
+       mem_free_data(&rparam);
+
+       return(-1);
+}
+
+/****************************************************************************
+  handle remote api calls delivered to a named pipe already opened.
+  ****************************************************************************/
+static int api_fd_reply(int cnum,uint16 vuid,char *outbuf,
+                       uint16 *setup,char *data,char *params,
+                       int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
+{
+       BOOL reply    = False;
+
+       int pnum;
+       int subcommand;
+       pipes_struct *p = NULL;
+       prs_struct pd;
+       struct mem_buf data_buf;
+
+       DEBUG(5,("api_fd_reply\n"));
+
+       /* fake up a data buffer from the api_fd_reply data parameters */
+       mem_create(&data_buf, data, tdscnt, 0, False);
+       data_buf.offset.start = 0;
+       data_buf.offset.end   = tdscnt;
+
+       /* fake up a parsing structure */
+       pd.data = &data_buf;
+       pd.align = 4;
+       pd.io = True;
+       pd.offset = 0;
+
+       /* First find out the name of this file. */
+       if (suwcnt != 2)
+       {
+               DEBUG(0,("Unexpected named pipe transaction.\n"));
+               return(-1);
+       }
+
+       /* Get the file handle and hence the file name. */
+       pnum = setup[1];
+       subcommand = setup[0];
+       get_rpc_pipe(pnum, &p);
+
+       if (p != NULL)
+       {
+               DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)",
+                                 subcommand, p->name, pnum));
+               DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d,cnum=%d,vuid=%d)\n",
+                                 tdscnt,tpscnt,mdrcnt,mprcnt,cnum,vuid));
+
+               /* record maximum data length that can be transmitted in an SMBtrans */
+               p->file_offset = mdrcnt;
+
+                DEBUG(10,("api_fd_reply: p:%p file_offset: %d\n",
+                           p, p->file_offset));
+
+               switch (subcommand)
+               {
+                       case 0x26:
+                       {
+                               /* dce/rpc command */
+                               reply = api_dce_rpc_command(outbuf, p, &pd);
+                               break;
+                       }
+                       case 0x01:
+                       {
+                               /* Set Named Pipe Handle state */
+                               reply = api_SNPHS(outbuf, p, params);
+                               break;
+                       }
+               }
+       }
+       else
+       {
+               DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
+       }
+
+       if (!reply)
+       {
+               return api_no_reply(outbuf, mdrcnt);
+       }
+       return -1;
+}
 
 /****************************************************************************
   the buffer was too small
@@ -3139,35 +3448,37 @@ struct
 {
   char *name;
   int id;
-  BOOL (*fn)();
+  BOOL (*fn)(int,uint16,char *,char *,int,int,char **,char **,int *,int *);
   int flags;
 } api_commands[] = {
-  {"RNetShareEnum",    0,      (BOOL (*)())api_RNetShareEnum,0},
-  {"RNetShareGetInfo", 1,      (BOOL (*)())api_RNetShareGetInfo,0},
-  {"RNetServerGetInfo",        13,     (BOOL (*)())api_RNetServerGetInfo,0},
-  {"RNetUserGetInfo",  56,     (BOOL (*)())api_RNetUserGetInfo,0},
-  {"NetUserGetGroups", 59,     (BOOL (*)())api_NetUserGetGroups,0},
-  {"NetWkstaGetInfo",  63,     (BOOL (*)())api_NetWkstaGetInfo,0},
-  {"DosPrintQEnum",    69,     (BOOL (*)())api_DosPrintQEnum,0},
-  {"DosPrintQGetInfo", 70,     (BOOL (*)())api_DosPrintQGetInfo,0},
-  {"WPrintJobEnumerate",76,    (BOOL (*)())api_WPrintJobEnumerate,0},
-  {"WPrintJobGetInfo", 77,     (BOOL (*)())api_WPrintJobGetInfo,0},
-  {"RDosPrintJobDel",  81,     (BOOL (*)())api_RDosPrintJobDel,0},
-  {"RDosPrintJobPause",        82,     (BOOL (*)())api_RDosPrintJobDel,0},
-  {"RDosPrintJobResume",83,    (BOOL (*)())api_RDosPrintJobDel,0},
-  {"WPrintDestEnum",   84,     (BOOL (*)())api_WPrintDestEnum,0},
-  {"WPrintDestGetInfo",        85,     (BOOL (*)())api_WPrintDestGetInfo,0},
-  {"NetRemoteTOD",     91,     (BOOL (*)())api_NetRemoteTOD,0},
-  {"WPrintQueuePurge", 103,    (BOOL (*)())api_WPrintQueuePurge,0},
-  {"NetServerEnum",    104,    (BOOL (*)())api_RNetServerEnum,0},
-  {"WAccessGetUserPerms",105,  (BOOL (*)())api_WAccessGetUserPerms,0},
-  {"SetUserPassword",  115,    (BOOL (*)())api_SetUserPassword,0},
-  {"WWkstaUserLogon",  132,    (BOOL (*)())api_WWkstaUserLogon,0},
-  {"PrintJobInfo",     147,    (BOOL (*)())api_PrintJobInfo,0},
-  {"WPrintDriverEnum", 205,    (BOOL (*)())api_WPrintDriverEnum,0},
-  {"WPrintQProcEnum",  206,    (BOOL (*)())api_WPrintQProcEnum,0},
-  {"WPrintPortEnum",   207,    (BOOL (*)())api_WPrintPortEnum,0},
-  {NULL,               -1,     (BOOL (*)())api_Unsupported,0}};
+  {"RNetShareEnum",    0,      api_RNetShareEnum,0},
+  {"RNetShareGetInfo", 1,      api_RNetShareGetInfo,0},
+  {"RNetServerGetInfo",        13,     api_RNetServerGetInfo,0},
+  {"RNetGroupGetUsers", 52,    api_RNetGroupGetUsers,0},
+  {"RNetUserGetInfo",  56,     api_RNetUserGetInfo,0},
+  {"NetUserGetGroups", 59,     api_NetUserGetGroups,0},
+  {"NetWkstaGetInfo",  63,     api_NetWkstaGetInfo,0},
+  {"DosPrintQEnum",    69,     api_DosPrintQEnum,0},
+  {"DosPrintQGetInfo", 70,     api_DosPrintQGetInfo,0},
+  {"WPrintJobEnumerate",76,    api_WPrintJobEnumerate,0},
+  {"WPrintJobGetInfo", 77,     api_WPrintJobGetInfo,0},
+  {"RDosPrintJobDel",  81,     api_RDosPrintJobDel,0},
+  {"RDosPrintJobPause",        82,     api_RDosPrintJobDel,0},
+  {"RDosPrintJobResume",83,    api_RDosPrintJobDel,0},
+  {"WPrintDestEnum",   84,     api_WPrintDestEnum,0},
+  {"WPrintDestGetInfo",        85,     api_WPrintDestGetInfo,0},
+  {"NetRemoteTOD",     91,     api_NetRemoteTOD,0},
+  {"WPrintQueuePurge", 103,    api_WPrintQueuePurge,0},
+  {"NetServerEnum",    104,    api_RNetServerEnum,0},
+  {"WAccessGetUserPerms",105,  api_WAccessGetUserPerms,0},
+  {"SetUserPassword",  115,    api_SetUserPassword,0},
+  {"WWkstaUserLogon",  132,    api_WWkstaUserLogon,0},
+  {"PrintJobInfo",     147,    api_PrintJobInfo,0},
+  {"WPrintDriverEnum", 205,    api_WPrintDriverEnum,0},
+  {"WPrintQProcEnum",  206,    api_WPrintQProcEnum,0},
+  {"WPrintPortEnum",   207,    api_WPrintPortEnum,0},
+  {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
+  {NULL,               -1,     api_Unsupported,0}};
 
 
 /****************************************************************************
@@ -3177,6 +3488,8 @@ static int api_reply(int cnum,uint16 vuid,char *outbuf,char *data,char *params,
                     int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
 {
   int api_command = SVAL(params,0);
+  struct mem_buf rdata_buf;
+  struct mem_buf rparam_buf;
   char *rdata = NULL;
   char *rparam = NULL;
   int rdata_len = 0;
@@ -3216,14 +3529,20 @@ static int api_reply(int cnum,uint16 vuid,char *outbuf,char *data,char *params,
                    &rdata,&rparam,&rdata_len,&rparam_len);
 
       
+  mem_create(&rdata_buf , rdata , rdata_len , 0, False);
+  mem_create(&rparam_buf, rparam, rparam_len, 0, False);
+
+  rdata_buf.offset.start = 0;
+  rdata_buf.offset.end   = rdata_len;
+
+  rparam_buf.offset.start = 0;
+  rparam_buf.offset.end   = rparam_len;
 
   /* now send the reply */
-  send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
+  send_trans_reply(outbuf, &rdata_buf, &rparam_buf, NULL, 0, 0);
 
-  if (rdata)
-    free(rdata);
-  if (rparam)
-    free(rparam);
+  if (rdata ) free(rdata);
+  if (rparam) free(rparam);
   
   return(-1);
 }