s3-talloc Change TALLOC_ARRAY() to talloc_array()
[samba.git] / source3 / libsmb / clirap.c
index 6716971fe2cb7fb4c3f6f8e18b5077d38d3a10fb..e5ff1abc18bdf2c1a5128661398f7bc2338cd67c 100644 (file)
-/* 
+/*
    Unix SMB/CIFS implementation.
    client RAP calls
    Copyright (C) Andrew Tridgell         1994-1998
    Copyright (C) Gerald (Jerry) Carter   2004
-   
+   Copyright (C) James Peach            2007
+
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "../librpc/gen_ndr/rap.h"
+#include "../lib/crypto/arcfour.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "async_smb.h"
+#include "libsmb/libsmb.h"
+#include "libsmb/clirap.h"
+#include "trans2.h"
 
+#define PIPE_LANMAN   "\\PIPE\\LANMAN"
 
 /****************************************************************************
-Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
+ Call a remote api
 ****************************************************************************/
-BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name, 
-                  uint16 *setup, uint32 setup_count, uint32 max_setup_count,
-                  char *params, uint32 param_count, uint32 max_param_count,
-                  char *data, uint32 data_count, uint32 max_data_count,
-                  char **rparam, uint32 *rparam_count,
-                  char **rdata, uint32 *rdata_count)
-{
-  cli_send_trans(cli, SMBtrans, 
-                 pipe_name, 
-                 0,0,                         /* fid, flags */
-                 setup, setup_count, max_setup_count,
-                 params, param_count, max_param_count,
-                 data, data_count, max_data_count);
-
-  return (cli_receive_trans(cli, SMBtrans, 
-                            rparam, (unsigned int *)rparam_count,
-                            rdata, (unsigned int *)rdata_count));
-}
 
-/****************************************************************************
-call a remote api
-****************************************************************************/
-BOOL cli_api(struct cli_state *cli,
+bool cli_api(struct cli_state *cli,
             char *param, int prcnt, int mprcnt,
             char *data, int drcnt, int mdrcnt,
             char **rparam, unsigned int *rprcnt,
             char **rdata, unsigned int *rdrcnt)
 {
-  cli_send_trans(cli,SMBtrans,
-                 PIPE_LANMAN,             /* Name */
-                 0,0,                     /* fid, flags */
-                 NULL,0,0,                /* Setup, length, max */
-                 param, prcnt, mprcnt,    /* Params, length, max */
-                 data, drcnt, mdrcnt      /* Data, length, max */ 
-                );
-
-  return (cli_receive_trans(cli,SMBtrans,
-                            rparam, rprcnt,
-                            rdata, rdrcnt));
-}
+       NTSTATUS status;
+
+       uint8_t *my_rparam, *my_rdata;
+       uint32_t num_my_rparam, num_my_rdata;
+
+       status = cli_trans(talloc_tos(), cli, SMBtrans,
+                          PIPE_LANMAN, 0, /* name, fid */
+                          0, 0,           /* function, flags */
+                          NULL, 0, 0,     /* setup */
+                          (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
+                          (uint8_t *)data, drcnt, mdrcnt,  /* Data, length, max */
+                          NULL,                 /* recv_flags2 */
+                          NULL, 0, NULL,        /* rsetup */
+                          &my_rparam, 0, &num_my_rparam,
+                          &my_rdata, 0, &num_my_rdata);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
 
+       /*
+        * I know this memcpy massively hurts, but there are just tons
+        * of callers of cli_api that eventually need changing to
+        * talloc
+        */
+
+       *rparam = (char *)memdup(my_rparam, num_my_rparam);
+       if (*rparam == NULL) {
+               goto fail;
+       }
+       *rprcnt = num_my_rparam;
+       TALLOC_FREE(my_rparam);
+
+       *rdata = (char *)memdup(my_rdata, num_my_rdata);
+       if (*rdata == NULL) {
+               goto fail;
+       }
+       *rdrcnt = num_my_rdata;
+       TALLOC_FREE(my_rdata);
+
+       return true;
+fail:
+       TALLOC_FREE(my_rdata);
+       TALLOC_FREE(my_rparam);
+       *rparam = NULL;
+       *rprcnt = 0;
+       *rdata = NULL;
+       *rdrcnt = 0;
+       return false;
+}
 
 /****************************************************************************
-perform a NetWkstaUserLogon
+ Perform a NetWkstaUserLogon.
 ****************************************************************************/
-BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
+
+bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
 {
        char *rparam = NULL;
        char *rdata = NULL;
        char *p;
        unsigned int rdrcnt,rprcnt;
-       pstring param;
+       char param[1024];
 
        memset(param, 0, sizeof(param));
-       
+
        /* send a SMBtrans command with api NetWkstaUserLogon */
        p = param;
        SSVAL(p,0,132); /* api number */
        p += 2;
-       pstrcpy_base(p,"OOWb54WrLh",param);
-       p = skip_string(p,1);
-       pstrcpy_base(p,"WB21BWDWWDDDDDDDzzzD",param);
-       p = skip_string(p,1);
+       strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
+       p = skip_string(param,sizeof(param),p);
+       strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
+       p = skip_string(param,sizeof(param),p);
        SSVAL(p,0,1);
        p += 2;
-       pstrcpy_base(p,user,param);
+       strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
        strupper_m(p);
        p += 21;
        p++;
        p += 15;
-       p++; 
-       pstrcpy_base(p, workstation, param);
+       p++;
+       strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
        strupper_m(p);
        p += 16;
        SSVAL(p, 0, CLI_BUFFER_SIZE);
        p += 2;
        SSVAL(p, 0, CLI_BUFFER_SIZE);
        p += 2;
-       
-       if (cli_api(cli, 
+
+       if (cli_api(cli,
                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
                     &rparam, &rprcnt,               /* return params, return size */
@@ -112,7 +137,7 @@ BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
                    )) {
                cli->rap_error = rparam? SVAL(rparam,0) : -1;
                p = rdata;
-               
+
                if (cli->rap_error == 0) {
                        DEBUG(4,("NetWkstaUserLogon success\n"));
                        cli->privileges = SVAL(p, 24);
@@ -122,32 +147,33 @@ BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
                        DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
                }
        }
-       
+
        SAFE_FREE(rparam);
        SAFE_FREE(rdata);
        return (cli->rap_error == 0);
 }
 
 /****************************************************************************
-call a NetShareEnum - try and browse available connections on a host
+ Call a NetShareEnum - try and browse available connections on a host.
 ****************************************************************************/
+
 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
 {
        char *rparam = NULL;
        char *rdata = NULL;
        char *p;
        unsigned int rdrcnt,rprcnt;
-       pstring param;
+       char param[1024];
        int count = -1;
 
        /* now send a SMBtrans command with api RNetShareEnum */
        p = param;
        SSVAL(p,0,0); /* api number */
        p += 2;
-       pstrcpy_base(p,"WrLeh",param);
-       p = skip_string(p,1);
-       pstrcpy_base(p,"B13BWz",param);
-       p = skip_string(p,1);
+       strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
+       p = skip_string(param,sizeof(param),p);
+       strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
+       p = skip_string(param,sizeof(param),p);
        SSVAL(p,0,1);
        /*
         * Win2k needs a *smaller* buffer than 0xFFFF here -
@@ -155,570 +181,951 @@ int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, co
         */
        SSVAL(p,2,0xFFE0);
        p += 4;
-       
-       if (cli_api(cli, 
+
+       if (cli_api(cli,
                    param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
                    NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
                    &rparam, &rprcnt,                /* return params, length */
                    &rdata, &rdrcnt))                /* return data, length */
                {
                        int res = rparam? SVAL(rparam,0) : -1;
-                       
+
                        if (res == 0 || res == ERRmoredata) {
                                int converter=SVAL(rparam,2);
                                int i;
-                               
+                               char *rdata_end = rdata + rdrcnt;
+
                                count=SVAL(rparam,4);
                                p = rdata;
-                               
-                               for (i=0;i<count;i++,p+=20) {
-                                       char *sname = p;
-                                       int type = SVAL(p,14);
-                                       int comment_offset = IVAL(p,16) & 0xFFFF;
-                                       const char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
-                                       pstring s1, s2;
 
-                                       pull_ascii_pstring(s1, sname);
-                                       pull_ascii_pstring(s2, cmnt);
+                               for (i=0;i<count;i++,p+=20) {
+                                       char *sname;
+                                       int type;
+                                       int comment_offset;
+                                       const char *cmnt;
+                                       const char *p1;
+                                       char *s1, *s2;
+                                       size_t len;
+                                       TALLOC_CTX *frame = talloc_stackframe();
+
+                                       if (p + 20 > rdata_end) {
+                                               TALLOC_FREE(frame);
+                                               break;
+                                       }
+
+                                       sname = p;
+                                       type = SVAL(p,14);
+                                       comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
+                                       if (comment_offset < 0 ||
+                                                       comment_offset > (int)rdrcnt) {
+                                               TALLOC_FREE(frame);
+                                               break;
+                                       }
+                                       cmnt = comment_offset?(rdata+comment_offset):"";
+
+                                       /* Work out the comment length. */
+                                       for (p1 = cmnt, len = 0; *p1 &&
+                                                       p1 < rdata_end; len++)
+                                               p1++;
+                                       if (!*p1) {
+                                               len++;
+                                       }
+                                       pull_string_talloc(frame,rdata,0,
+                                               &s1,sname,14,STR_ASCII);
+                                       pull_string_talloc(frame,rdata,0,
+                                               &s2,cmnt,len,STR_ASCII);
+                                       if (!s1 || !s2) {
+                                               TALLOC_FREE(frame);
+                                               continue;
+                                       }
 
                                        fn(s1, type, s2, state);
+
+                                       TALLOC_FREE(frame);
                                }
                        } else {
                                DEBUG(4,("NetShareEnum res=%d\n", res));
-                       }      
+                       }
                } else {
                        DEBUG(4,("NetShareEnum failed\n"));
                }
-  
+
        SAFE_FREE(rparam);
        SAFE_FREE(rdata);
-       
+
        return count;
 }
 
-
 /****************************************************************************
-call a NetServerEnum for the specified workgroup and servertype mask.  This
-function then calls the specified callback function for each name returned.
+ Call a NetServerEnum for the specified workgroup and servertype mask.  This
+ function then calls the specified callback function for each name returned.
 
-The callback function takes 4 arguments: the machine name, the server type,
-the comment and a state pointer.
+ The callback function takes 4 arguments: the machine name, the server type,
+ the comment and a state pointer.
 ****************************************************************************/
-BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+
+bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
                       void (*fn)(const char *, uint32, const char *, void *),
                       void *state)
 {
        char *rparam = NULL;
        char *rdata = NULL;
+       char *rdata_end = NULL;
        unsigned int rdrcnt,rprcnt;
        char *p;
-       pstring param;
+       char param[1024];
        int uLevel = 1;
-       int count = -1;
+       size_t len;
+       uint32 func = RAP_NetServerEnum2;
+       char *last_entry = NULL;
+       int total_cnt = 0;
+       int return_cnt = 0;
+       int res;
 
        errno = 0; /* reset */
 
-       /* send a SMBtrans command with api NetServerEnum */
-       p = param;
-       SSVAL(p,0,0x68); /* api number */
-       p += 2;
-       pstrcpy_base(p,"WrLehDz", param);
-       p = skip_string(p,1);
-  
-       pstrcpy_base(p,"B16BBDz", param);
-
-       p = skip_string(p,1);
-       SSVAL(p,0,uLevel);
-       SSVAL(p,2,CLI_BUFFER_SIZE);
-       p += 4;
-       SIVAL(p,0,stype);
-       p += 4;
+       /*
+        * This may take more than one transaction, so we should loop until
+        * we no longer get a more data to process or we have all of the
+        * items.
+        */
+       do {
+               /* send a SMBtrans command with api NetServerEnum */
+               p = param;
+               SIVAL(p,0,func); /* api number */
+               p += 2;
 
-       p += push_ascii(p, workgroup, sizeof(pstring)-PTR_DIFF(p,param)-1, STR_TERMINATE|STR_UPPER);
-       
-       if (cli_api(cli, 
-                    param, PTR_DIFF(p,param), 8,        /* params, length, max */
-                    NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
-                    &rparam, &rprcnt,                   /* return params, return size */
-                    &rdata, &rdrcnt                     /* return data, return size */
-                   )) {
-               int res = rparam? SVAL(rparam,0) : -1;
-                       
-               if (res == 0 || res == ERRmoredata) {
-                       int i;
+               if (func == RAP_NetServerEnum3) {
+                       strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
+               } else {
+                       strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
+               }
+
+               p = skip_string(param, sizeof(param), p);
+               strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
+
+               p = skip_string(param, sizeof(param), p);
+               SSVAL(p,0,uLevel);
+               SSVAL(p,2,CLI_BUFFER_SIZE);
+               p += 4;
+               SIVAL(p,0,stype);
+               p += 4;
+
+               /* If we have more data, tell the server where
+                * to continue from.
+                */
+               len = push_ascii(p,
+                               workgroup,
+                               sizeof(param) - PTR_DIFF(p,param) - 1,
+                               STR_TERMINATE|STR_UPPER);
+
+               if (len == (size_t)-1) {
+                       SAFE_FREE(last_entry);
+                       return false;
+               }
+               p += len;
+
+               if (func == RAP_NetServerEnum3) {
+                       len = push_ascii(p,
+                                       last_entry ? last_entry : "",
+                                       sizeof(param) - PTR_DIFF(p,param) - 1,
+                                       STR_TERMINATE);
+
+                       if (len == (size_t)-1) {
+                               SAFE_FREE(last_entry);
+                               return false;
+                       }
+                       p += len;
+               }
+
+               /* Next time through we need to use the continue api */
+               func = RAP_NetServerEnum3;
+
+               if (!cli_api(cli,
+                       param, PTR_DIFF(p,param), 8, /* params, length, max */
+                       NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+                           &rparam, &rprcnt, /* return params, return size */
+                           &rdata, &rdrcnt)) { /* return data, return size */
+
+                       /* break out of the loop on error */
+                       res = -1;
+                       break;
+               }
+
+               rdata_end = rdata + rdrcnt;
+               res = rparam ? SVAL(rparam,0) : -1;
+
+               if (res == 0 || res == ERRmoredata ||
+                    (res != -1 && cli_errno(cli) == 0)) {
+                       char *sname = NULL;
+                       int i, count;
                        int converter=SVAL(rparam,2);
 
-                       count=SVAL(rparam,4);
+                       /* Get the number of items returned in this buffer */
+                       count = SVAL(rparam, 4);
+
+                       /* The next field contains the number of items left,
+                        * including those returned in this buffer. So the
+                        * first time through this should contain all of the
+                        * entries.
+                        */
+                       if (total_cnt == 0) {
+                               total_cnt = SVAL(rparam, 6);
+                       }
+
+                       /* Keep track of how many we have read */
+                       return_cnt += count;
                        p = rdata;
-                                       
-                       for (i = 0;i < count;i++, p += 26) {
-                               char *sname = p;
-                               int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
-                               const char *cmnt = comment_offset?(rdata+comment_offset):"";
-                               pstring s1, s2;
 
-                               if (comment_offset < 0 || comment_offset > (int)rdrcnt) continue;
+                       /* The last name in the previous NetServerEnum reply is
+                        * sent back to server in the NetServerEnum3 request
+                        * (last_entry). The next reply should repeat this entry
+                        * as the first element. We have no proof that this is
+                        * always true, but from traces that seems to be the
+                        * behavior from Window Servers. So first lets do a lot
+                        * of checking, just being paranoid. If the string
+                        * matches then we already saw this entry so skip it.
+                        *
+                        * NOTE: sv1_name field must be null terminated and has
+                        * a max size of 16 (NetBIOS Name).
+                        */
+                       if (last_entry && count && p &&
+                               (strncmp(last_entry, p, 16) == 0)) {
+                           count -= 1; /* Skip this entry */
+                           return_cnt = -1; /* Not part of total, so don't count. */
+                           p = rdata + 26; /* Skip the whole record */
+                       }
+
+                       for (i = 0; i < count; i++, p += 26) {
+                               int comment_offset;
+                               const char *cmnt;
+                               const char *p1;
+                               char *s1, *s2;
+                               TALLOC_CTX *frame = talloc_stackframe();
+                               uint32_t entry_stype;
+
+                               if (p + 26 > rdata_end) {
+                                       TALLOC_FREE(frame);
+                                       break;
+                               }
 
-                               stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+                               sname = p;
+                               comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
+                               cmnt = comment_offset?(rdata+comment_offset):"";
 
-                               pull_ascii_pstring(s1, sname);
-                               pull_ascii_pstring(s2, cmnt);
-                               fn(s1, stype, s2, state);
+                               if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
+                                       TALLOC_FREE(frame);
+                                       continue;
+                               }
+
+                               /* Work out the comment length. */
+                               for (p1 = cmnt, len = 0; *p1 &&
+                                               p1 < rdata_end; len++)
+                                       p1++;
+                               if (!*p1) {
+                                       len++;
+                               }
+
+                               entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+                               pull_string_talloc(frame,rdata,0,
+                                       &s1,sname,16,STR_ASCII);
+                               pull_string_talloc(frame,rdata,0,
+                                       &s2,cmnt,len,STR_ASCII);
+
+                               if (!s1 || !s2) {
+                                       TALLOC_FREE(frame);
+                                       continue;
+                               }
+
+                               fn(s1, entry_stype, s2, state);
+                               TALLOC_FREE(frame);
+                       }
+
+                       /* We are done with the old last entry, so now we can free it */
+                       if (last_entry) {
+                               SAFE_FREE(last_entry); /* This will set it to null */
                        }
+
+                       /* We always make a copy of  the last entry if we have one */
+                       if (sname) {
+                               last_entry = smb_xstrdup(sname);
+                       }
+
+                       /* If we have more data, but no last entry then error out */
+                       if (!last_entry && (res == ERRmoredata)) {
+                               errno = EINVAL;
+                               res = 0;
+                       }
+
                }
-       }
-  
+
+               SAFE_FREE(rparam);
+               SAFE_FREE(rdata);
+       } while ((res == ERRmoredata) && (total_cnt > return_cnt));
+
        SAFE_FREE(rparam);
        SAFE_FREE(rdata);
+       SAFE_FREE(last_entry);
 
-       if (count < 0) {
-           errno = cli_errno(cli);
+       if (res == -1) {
+               errno = cli_errno(cli);
        } else {
-           if (!count) {
-               /* this is a very special case, when the domain master for the 
-                  work group isn't part of the work group itself, there is something
-                  wild going on */
-               errno = ENOENT;
+               if (!return_cnt) {
+                       /* this is a very special case, when the domain master for the
+                          work group isn't part of the work group itself, there is something
+                          wild going on */
+                       errno = ENOENT;
+               }
            }
-       }
-                       
-       return(count > 0);
-}
-
 
+       return(return_cnt > 0);
+}
 
 /****************************************************************************
-Send a SamOEMChangePassword command
+ Send a SamOEMChangePassword command.
 ****************************************************************************/
-BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
+
+bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
                              const char *old_password)
 {
-  pstring param;
-  unsigned char data[532];
-  char *p = param;
-  unsigned char old_pw_hash[16];
-  unsigned char new_pw_hash[16];
-  unsigned int data_len;
-  unsigned int param_len = 0;
-  char *rparam = NULL;
-  char *rdata = NULL;
-  unsigned int rprcnt, rdrcnt;
-
-  if (strlen(user) >= sizeof(fstring)-1) {
-    DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
-    return False;
-  }
-
-  SSVAL(p,0,214); /* SamOEMChangePassword command. */
-  p += 2;
-  pstrcpy_base(p, "zsT", param);
-  p = skip_string(p,1);
-  pstrcpy_base(p, "B516B16", param);
-  p = skip_string(p,1);
-  pstrcpy_base(p,user, param);
-  p = skip_string(p,1);
-  SSVAL(p,0,532);
-  p += 2;
-
-  param_len = PTR_DIFF(p,param);
-
-  /*
-   * Get the Lanman hash of the old password, we
-   * use this as the key to make_oem_passwd_hash().
-   */
-  E_deshash(old_password, old_pw_hash);
-
-  encode_pw_buffer(data, new_password, STR_ASCII);
-  
+       char param[1024];
+       unsigned char data[532];
+       char *p = param;
+       unsigned char old_pw_hash[16];
+       unsigned char new_pw_hash[16];
+       unsigned int data_len;
+       unsigned int param_len = 0;
+       char *rparam = NULL;
+       char *rdata = NULL;
+       unsigned int rprcnt, rdrcnt;
+
+       if (strlen(user) >= sizeof(fstring)-1) {
+               DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
+               return False;
+       }
+
+       SSVAL(p,0,214); /* SamOEMChangePassword command. */
+       p += 2;
+       strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
+       p = skip_string(param,sizeof(param),p);
+       strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
+       p = skip_string(param,sizeof(param),p);
+       strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
+       p = skip_string(param,sizeof(param),p);
+       SSVAL(p,0,532);
+       p += 2;
+
+       param_len = PTR_DIFF(p,param);
+
+       /*
+        * Get the Lanman hash of the old password, we
+        * use this as the key to make_oem_passwd_hash().
+        */
+       E_deshash(old_password, old_pw_hash);
+
+       encode_pw_buffer(data, new_password, STR_ASCII);
+
 #ifdef DEBUG_PASSWORD
-  DEBUG(100,("make_oem_passwd_hash\n"));
-  dump_data(100, (char *)data, 516);
+       DEBUG(100,("make_oem_passwd_hash\n"));
+       dump_data(100, data, 516);
 #endif
-  SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
-
-  /* 
-   * Now place the old password hash in the data.
-   */
-  E_deshash(new_password, new_pw_hash);
-
-  E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
-
-  data_len = 532;
-    
-  if (cli_send_trans(cli,SMBtrans,
-                    PIPE_LANMAN,                          /* name */
-                    0,0,                                  /* fid, flags */
-                    NULL,0,0,                             /* setup, length, max */
-                    param,param_len,2,                    /* param, length, max */
-                    (char *)data,data_len,0                       /* data, length, max */
-                   ) == False) {
-    DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
-              user ));
-    return False;
-  }
-
-  if (!cli_receive_trans(cli,SMBtrans,
-                       &rparam, &rprcnt,
-                       &rdata, &rdrcnt)) {
-         DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
-                  user ));
-         return False;
-  }
-  
-  if (rparam)
-         cli->rap_error = SVAL(rparam,0);
-  
-  SAFE_FREE(rparam);
-  SAFE_FREE(rdata);
-
-  return (cli->rap_error == 0);
-}
+       arcfour_crypt( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
+
+       /*
+        * Now place the old password hash in the data.
+        */
+       E_deshash(new_password, new_pw_hash);
+
+       E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
+
+       data_len = 532;
+
+       if (!cli_api(cli,
+                    param, param_len, 4,               /* param, length, max */
+                    (char *)data, data_len, 0,         /* data, length, max */
+                    &rparam, &rprcnt,
+                    &rdata, &rdrcnt)) {
+               DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
+                       user ));
+               return False;
+       }
+
+       if (rparam) {
+               cli->rap_error = SVAL(rparam,0);
+       }
 
+       SAFE_FREE(rparam);
+       SAFE_FREE(rdata);
+
+       return (cli->rap_error == 0);
+}
 
 /****************************************************************************
-send a qpathinfo call
+ Send a qpathinfo call.
 ****************************************************************************/
-BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
-                  time_t *c_time, time_t *a_time, time_t *m_time, 
-                  SMB_OFF_T *size, uint16 *mode)
+
+struct cli_qpathinfo1_state {
+       struct cli_state *cli;
+       uint32_t num_data;
+       uint8_t *data;
+};
+
+static void cli_qpathinfo1_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
+                                      struct event_context *ev,
+                                      struct cli_state *cli,
+                                      const char *fname)
 {
-       unsigned int data_len = 0;
-       unsigned int param_len = 0;
-       unsigned int rparam_len, rdata_len;
-       uint16 setup = TRANSACT2_QPATHINFO;
-       pstring param;
-       char *rparam=NULL, *rdata=NULL;
-       int count=8;
-       BOOL ret;
-       time_t (*date_fn)(struct cli_state *, void *);
-       char *p;
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_qpathinfo1_state *state = NULL;
 
-       p = param;
-       memset(p, 0, 6);
-       SSVAL(p, 0, SMB_INFO_STANDARD);
-       p += 6;
-       p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+       req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->cli = cli;
+       subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
+                                   22, cli->max_xmit);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
+       return req;
+}
 
-       param_len = PTR_DIFF(p, param);
+static void cli_qpathinfo1_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_qpathinfo1_state *state = tevent_req_data(
+               req, struct cli_qpathinfo1_state);
+       NTSTATUS status;
+
+       status = cli_qpathinfo_recv(subreq, state, &state->data,
+                                   &state->num_data);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+       tevent_req_done(req);
+}
 
-       do {
-               ret = (cli_send_trans(cli, SMBtrans2, 
-                                     NULL,           /* Name */
-                                     -1, 0,          /* fid, flags */
-                                     &setup, 1, 0,   /* setup, length, max */
-                                     param, param_len, 10, /* param, length, max */
-                                     NULL, data_len, cli->max_xmit /* data, length, max */
-                                     ) &&
-                      cli_receive_trans(cli, SMBtrans2, 
-                                        &rparam, &rparam_len,
-                                        &rdata, &rdata_len));
-               if (!cli_is_dos_error(cli)) break;
-               if (!ret) {
-                       /* we need to work around a Win95 bug - sometimes
-                          it gives ERRSRV/ERRerror temprarily */
-                       uint8 eclass;
-                       uint32 ecode;
-                       cli_dos_error(cli, &eclass, &ecode);
-                       if (eclass != ERRSRV || ecode != ERRerror) break;
-                       smb_msleep(100);
-               }
-       } while (count-- && ret==False);
+NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
+                            time_t *change_time,
+                            time_t *access_time,
+                            time_t *write_time,
+                            SMB_OFF_T *size,
+                            uint16 *mode)
+{
+       struct cli_qpathinfo1_state *state = tevent_req_data(
+               req, struct cli_qpathinfo1_state);
+       NTSTATUS status;
 
-       if (!ret || !rdata || rdata_len < 22) {
-               return False;
+       time_t (*date_fn)(const void *buf, int serverzone);
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
        }
 
-       if (cli->win95) {
-               date_fn = cli_make_unix_date;
+       if (state->cli->win95) {
+               date_fn = make_unix_date;
        } else {
-               date_fn = cli_make_unix_date2;
+               date_fn = make_unix_date2;
        }
 
-       if (c_time) {
-               *c_time = date_fn(cli, rdata+0);
+       if (change_time) {
+               *change_time = date_fn(state->data+0, state->cli->serverzone);
        }
-       if (a_time) {
-               *a_time = date_fn(cli, rdata+4);
+       if (access_time) {
+               *access_time = date_fn(state->data+4, state->cli->serverzone);
        }
-       if (m_time) {
-               *m_time = date_fn(cli, rdata+8);
+       if (write_time) {
+               *write_time = date_fn(state->data+8, state->cli->serverzone);
        }
        if (size) {
-               *size = IVAL(rdata, 12);
+               *size = IVAL(state->data, 12);
        }
        if (mode) {
-               *mode = SVAL(rdata,l1_attrFile);
+               *mode = SVAL(state->data, l1_attrFile);
        }
-
-       SAFE_FREE(rdata);
-       SAFE_FREE(rparam);
-       return True;
+       return NT_STATUS_OK;
 }
 
+NTSTATUS cli_qpathinfo1(struct cli_state *cli,
+                       const char *fname,
+                       time_t *change_time,
+                       time_t *access_time,
+                       time_t *write_time,
+                       SMB_OFF_T *size,
+                       uint16 *mode)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       if (cli_has_async_calls(cli)) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_qpathinfo1_send(frame, ev, cli, fname);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_qpathinfo1_recv(req, change_time, access_time,
+                                    write_time, size, mode);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
 
 /****************************************************************************
-send a setpathinfo call
+ Send a setpathinfo call.
 ****************************************************************************/
-BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, 
-                     time_t c_time, time_t a_time, time_t m_time, uint16 mode)
+
+NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname,
+                              time_t create_time,
+                              time_t access_time,
+                              time_t write_time,
+                              time_t change_time,
+                              uint16 mode)
 {
        unsigned int data_len = 0;
-       unsigned int param_len = 0;
-       unsigned int rparam_len, rdata_len;
-       uint16 setup = TRANSACT2_SETPATHINFO;
-       pstring param;
-        pstring data;
-       char *rparam=NULL, *rdata=NULL;
-       int count=8;
-       BOOL ret;
-        void (*date_fn)(struct cli_state *, char *buf,int offset,time_t unixdate);
+       char data[40];
        char *p;
 
-       memset(param, 0, sizeof(param));
-       memset(data, 0, sizeof(data));
-
-        p = param;
-
-        /* Add the information level */
-       SSVAL(p, 0, SMB_INFO_STANDARD);
-
-        /* Skip reserved */
-       p += 6;
-
-        /* Add the file name */
-       p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
-
-       param_len = PTR_DIFF(p, param);
-
         p = data;
 
-       if (cli->win95) {
-               date_fn = cli_put_dos_date;
-       } else {
-               date_fn = cli_put_dos_date2;
-       }
+        /*
+         * Add the create, last access, modification, and status change times
+         */
+        put_long_date(p, create_time);
+        p += 8;
 
-        /* Add the create, last access, and modification times */
-        (*date_fn)(cli, p, 0, c_time);
-        (*date_fn)(cli, p, 4, a_time);
-        (*date_fn)(cli, p, 8, m_time);
-        p += 12;
+        put_long_date(p, access_time);
+        p += 8;
+
+        put_long_date(p, write_time);
+        p += 8;
 
-        /* Skip DataSize and AllocationSize */
+        put_long_date(p, change_time);
         p += 8;
 
         /* Add attributes */
-        SSVAL(p, 0, mode);
-        p += 2;
+        SIVAL(p, 0, mode);
+        p += 4;
 
-        /* Add EA size (none) */
+        /* Add padding */
         SIVAL(p, 0, 0);
         p += 4;
 
         data_len = PTR_DIFF(p, data);
 
-       do {
-               ret = (cli_send_trans(cli, SMBtrans2, 
-                                     NULL,           /* Name */
-                                     -1, 0,          /* fid, flags */
-                                     &setup, 1, 0,   /* setup, length, max */
-                                     param, param_len, 10, /* param, length, max */
-                                     data, data_len, cli->max_xmit /* data, length, max */
-                                     ) &&
-                      cli_receive_trans(cli, SMBtrans2, 
-                                        &rparam, &rparam_len,
-                                        &rdata, &rdata_len));
-               if (!cli_is_dos_error(cli)) break;
-               if (!ret) {
-                       /* we need to work around a Win95 bug - sometimes
-                          it gives ERRSRV/ERRerror temprarily */
-                       uint8 eclass;
-                       uint32 ecode;
-                       cli_dos_error(cli, &eclass, &ecode);
-                       if (eclass != ERRSRV || ecode != ERRerror) break;
-                       smb_msleep(100);
-               }
-       } while (count-- && ret==False);
-
-       if (!ret) {
-               return False;
-       }
-
-       SAFE_FREE(rdata);
-       SAFE_FREE(rparam);
-       return True;
+       return cli_setpathinfo(cli, SMB_FILE_BASIC_INFORMATION, fname,
+                              (uint8_t *)data, data_len);
 }
 
-
 /****************************************************************************
-send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
+ Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
 ****************************************************************************/
-BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
-                   time_t *c_time, time_t *a_time, time_t *m_time, 
-                   time_t *w_time, SMB_OFF_T *size, uint16 *mode,
-                   SMB_INO_T *ino)
+
+struct cli_qpathinfo2_state {
+       uint32_t num_data;
+       uint8_t *data;
+};
+
+static void cli_qpathinfo2_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
+                                      struct event_context *ev,
+                                      struct cli_state *cli,
+                                      const char *fname)
 {
-       unsigned int data_len = 0;
-       unsigned int param_len = 0;
-       uint16 setup = TRANSACT2_QPATHINFO;
-       pstring param;
-       char *rparam=NULL, *rdata=NULL;
-       char *p;
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_qpathinfo2_state *state = NULL;
 
-       p = param;
-       memset(p, 0, 6);
-       SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
-       p += 6;
-       p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
-
-       param_len = PTR_DIFF(p, param);
-
-       if (!cli_send_trans(cli, SMBtrans2, 
-                            NULL,                         /* name */
-                            -1, 0,                        /* fid, flags */
-                            &setup, 1, 0,                 /* setup, length, max */
-                            param, param_len, 10,         /* param, length, max */
-                            NULL, data_len, cli->max_xmit /* data, length, max */
-                           )) {
-               return False;
+       req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       subreq = cli_qpathinfo_send(state, ev, cli, fname,
+                                   SMB_QUERY_FILE_ALL_INFO,
+                                   68, cli->max_xmit);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
+       tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
+       return req;
+}
 
-       if (!cli_receive_trans(cli, SMBtrans2,
-                               &rparam, &param_len,
-                               &rdata, &data_len)) {
-               return False;
+static void cli_qpathinfo2_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_qpathinfo2_state *state = tevent_req_data(
+               req, struct cli_qpathinfo2_state);
+       NTSTATUS status;
+
+       status = cli_qpathinfo_recv(subreq, state, &state->data,
+                                   &state->num_data);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
        }
+       tevent_req_done(req);
+}
 
-       if (!rdata || data_len < 22) {
-               return False;
+NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
+                            struct timespec *create_time,
+                            struct timespec *access_time,
+                            struct timespec *write_time,
+                            struct timespec *change_time,
+                            SMB_OFF_T *size, uint16 *mode,
+                            SMB_INO_T *ino)
+{
+       struct cli_qpathinfo2_state *state = tevent_req_data(
+               req, struct cli_qpathinfo2_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
        }
-        
-       if (c_time) {
-                *c_time = interpret_long_date(rdata+0);
+
+       if (create_time) {
+                *create_time = interpret_long_date((char *)state->data+0);
        }
-       if (a_time) {
-               *a_time = interpret_long_date(rdata+8);
+       if (access_time) {
+               *access_time = interpret_long_date((char *)state->data+8);
        }
-       if (w_time) {
-               *w_time = interpret_long_date(rdata+16);
+       if (write_time) {
+               *write_time = interpret_long_date((char *)state->data+16);
        }
-       if (m_time) {
-               *m_time = interpret_long_date(rdata+24);
+       if (change_time) {
+               *change_time = interpret_long_date((char *)state->data+24);
        }
        if (mode) {
-               *mode = SVAL(rdata, 32);
+               *mode = SVAL(state->data, 32);
        }
        if (size) {
-                *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
+                *size = IVAL2_TO_SMB_BIG_UINT(state->data,48);
        }
        if (ino) {
-               *ino = IVAL(rdata, 64);
+               *ino = IVAL(state->data, 64);
        }
-
-       SAFE_FREE(rdata);
-       SAFE_FREE(rparam);
-       return True;
+       return NT_STATUS_OK;
 }
 
+NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
+                       struct timespec *create_time,
+                       struct timespec *access_time,
+                       struct timespec *write_time,
+                       struct timespec *change_time,
+                       SMB_OFF_T *size, uint16 *mode,
+                       SMB_INO_T *ino)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       if (cli_has_async_calls(cli)) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_qpathinfo2_send(frame, ev, cli, fname);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_qpathinfo2_recv(req, create_time, access_time,
+                                    write_time, change_time, size, mode, ino);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
 
 /****************************************************************************
-send a qfileinfo QUERY_FILE_NAME_INFO call
+ Get the stream info
 ****************************************************************************/
-BOOL cli_qfilename(struct cli_state *cli, int fnum, 
-                  pstring name)
+
+static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *data,
+                              size_t data_len,
+                              unsigned int *pnum_streams,
+                              struct stream_struct **pstreams);
+
+struct cli_qpathinfo_streams_state {
+       uint32_t num_data;
+       uint8_t *data;
+};
+
+static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
+                                             struct tevent_context *ev,
+                                             struct cli_state *cli,
+                                             const char *fname)
 {
-       unsigned int data_len = 0;
-       unsigned int param_len = 0;
-       uint16 setup = TRANSACT2_QFILEINFO;
-       pstring param;
-       char *rparam=NULL, *rdata=NULL;
-
-       param_len = 4;
-       memset(param, 0, param_len);
-       SSVAL(param, 0, fnum);
-       SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
-
-       if (!cli_send_trans(cli, SMBtrans2, 
-                            NULL,                         /* name */
-                            -1, 0,                        /* fid, flags */
-                            &setup, 1, 0,                 /* setup, length, max */
-                            param, param_len, 2,          /* param, length, max */
-                            NULL, data_len, cli->max_xmit /* data, length, max */
-                           )) {
-               return False;
-       }
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_qpathinfo_streams_state *state = NULL;
 
-       if (!cli_receive_trans(cli, SMBtrans2,
-                               &rparam, &param_len,
-                               &rdata, &data_len)) {
-               return False;
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_qpathinfo_streams_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       subreq = cli_qpathinfo_send(state, ev, cli, fname,
+                                   SMB_FILE_STREAM_INFORMATION,
+                                   0, cli->max_xmit);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
+       tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
+       return req;
+}
 
-       if (!rdata || data_len < 4) {
-               return False;
+static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_qpathinfo_streams_state *state = tevent_req_data(
+               req, struct cli_qpathinfo_streams_state);
+       NTSTATUS status;
+
+       status = cli_qpathinfo_recv(subreq, state, &state->data,
+                                   &state->num_data);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
        }
+       tevent_req_done(req);
+}
 
-       clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
+NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
+                                   TALLOC_CTX *mem_ctx,
+                                   unsigned int *pnum_streams,
+                                   struct stream_struct **pstreams)
+{
+       struct cli_qpathinfo_streams_state *state = tevent_req_data(
+                req, struct cli_qpathinfo_streams_state);
+        NTSTATUS status;
 
-       return True;
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
+                               pnum_streams, pstreams)) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+       return NT_STATUS_OK;
 }
 
+NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
+                              TALLOC_CTX *mem_ctx,
+                              unsigned int *pnum_streams,
+                              struct stream_struct **pstreams)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       if (cli_has_async_calls(cli)) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
+                                           pstreams);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
 
-/****************************************************************************
-send a qfileinfo call
-****************************************************************************/
-BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
-                  uint16 *mode, SMB_OFF_T *size,
-                  time_t *c_time, time_t *a_time, time_t *m_time, 
-                  time_t *w_time, SMB_INO_T *ino)
+static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
+                              size_t data_len,
+                              unsigned int *pnum_streams,
+                              struct stream_struct **pstreams)
 {
-       unsigned int data_len = 0;
-       unsigned int param_len = 0;
-       uint16 setup = TRANSACT2_QFILEINFO;
-       pstring param;
-       char *rparam=NULL, *rdata=NULL;
+       unsigned int num_streams;
+       struct stream_struct *streams;
+       unsigned int ofs;
+
+       num_streams = 0;
+       streams = NULL;
+       ofs = 0;
+
+       while ((data_len > ofs) && (data_len - ofs >= 24)) {
+               uint32_t nlen, len;
+               size_t size;
+               void *vstr;
+               struct stream_struct *tmp;
+               uint8_t *tmp_buf;
+
+               tmp = talloc_realloc(mem_ctx, streams,
+                                          struct stream_struct,
+                                          num_streams+1);
+
+               if (tmp == NULL) {
+                       goto fail;
+               }
+               streams = tmp;
 
-       /* if its a win95 server then fail this - win95 totally screws it
-          up */
-       if (cli->win95) return False;
+               nlen                      = IVAL(rdata, ofs + 0x04);
+
+               streams[num_streams].size = IVAL_TO_SMB_OFF_T(
+                       rdata, ofs + 0x08);
+               streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
+                       rdata, ofs + 0x10);
 
-       param_len = 4;
+               if (nlen > data_len - (ofs + 24)) {
+                       goto fail;
+               }
 
-       memset(param, 0, param_len);
-       SSVAL(param, 0, fnum);
-       SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
+               /*
+                * We need to null-terminate src, how do I do this with
+                * convert_string_talloc??
+                */
 
-       if (!cli_send_trans(cli, SMBtrans2, 
-                            NULL,                         /* name */
-                            -1, 0,                        /* fid, flags */
-                            &setup, 1, 0,                 /* setup, length, max */
-                            param, param_len, 2,          /* param, length, max */
-                            NULL, data_len, cli->max_xmit /* data, length, max */
-                           )) {
-               return False;
+               tmp_buf = talloc_array(streams, uint8_t, nlen+2);
+               if (tmp_buf == NULL) {
+                       goto fail;
+               }
+
+               memcpy(tmp_buf, rdata+ofs+24, nlen);
+               tmp_buf[nlen] = 0;
+               tmp_buf[nlen+1] = 0;
+
+               if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
+                                          nlen+2, &vstr, &size))
+               {
+                       TALLOC_FREE(tmp_buf);
+                       goto fail;
+               }
+
+               TALLOC_FREE(tmp_buf);
+               streams[num_streams].name = (char *)vstr;
+               num_streams++;
+
+               len = IVAL(rdata, ofs);
+               if (len > data_len - ofs) {
+                       goto fail;
+               }
+               if (len == 0) break;
+               ofs += len;
        }
 
-       if (!cli_receive_trans(cli, SMBtrans2,
-                               &rparam, &param_len,
-                               &rdata, &data_len)) {
-               return False;
+       *pnum_streams = num_streams;
+       *pstreams = streams;
+       return true;
+
+ fail:
+       TALLOC_FREE(streams);
+       return false;
+}
+
+/****************************************************************************
+ Send a qfileinfo QUERY_FILE_NAME_INFO call.
+****************************************************************************/
+
+NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum, char *name,
+                      size_t namelen)
+{
+       uint8_t *rdata;
+       uint32_t num_rdata;
+       NTSTATUS status;
+
+       status = cli_qfileinfo(talloc_tos(), cli, fnum,
+                              SMB_QUERY_FILE_NAME_INFO,
+                              4, cli->max_xmit,
+                              &rdata, &num_rdata);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       if (!rdata || data_len < 68) {
-               return False;
+       clistr_pull((const char *)rdata, name, rdata+4, namelen, IVAL(rdata, 0),
+                   STR_UNICODE);
+       TALLOC_FREE(rdata);
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Send a qfileinfo call.
+****************************************************************************/
+
+NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum,
+                            uint16 *mode, SMB_OFF_T *size,
+                            struct timespec *create_time,
+                            struct timespec *access_time,
+                            struct timespec *write_time,
+                            struct timespec *change_time,
+                            SMB_INO_T *ino)
+{
+       uint8_t *rdata;
+       uint32_t num_rdata;
+       NTSTATUS status;
+
+       /* if its a win95 server then fail this - win95 totally screws it
+          up */
+       if (cli->win95) {
+               return NT_STATUS_NOT_SUPPORTED;
        }
 
-       if (c_time) {
-               *c_time = interpret_long_date(rdata+0) - cli->serverzone;
+       status = cli_qfileinfo(talloc_tos(), cli, fnum,
+                              SMB_QUERY_FILE_ALL_INFO,
+                              68, MIN(cli->max_xmit, 0xffff),
+                              &rdata, &num_rdata);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
-       if (a_time) {
-               *a_time = interpret_long_date(rdata+8) - cli->serverzone;
+
+       if (create_time) {
+               *create_time = interpret_long_date((char *)rdata+0);
        }
-       if (m_time) {
-               *m_time = interpret_long_date(rdata+16) - cli->serverzone;
+       if (access_time) {
+               *access_time = interpret_long_date((char *)rdata+8);
        }
-       if (w_time) {
-               *w_time = interpret_long_date(rdata+24) - cli->serverzone;
+       if (write_time) {
+               *write_time = interpret_long_date((char *)rdata+16);
+       }
+       if (change_time) {
+               *change_time = interpret_long_date((char *)rdata+24);
        }
        if (mode) {
                *mode = SVAL(rdata, 32);
@@ -730,192 +1137,152 @@ BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
                *ino = IVAL(rdata, 64);
        }
 
-       SAFE_FREE(rdata);
-       SAFE_FREE(rparam);
-       return True;
+       TALLOC_FREE(rdata);
+       return NT_STATUS_OK;
 }
 
-
 /****************************************************************************
-send a qpathinfo BASIC_INFO call
+ Send a qpathinfo BASIC_INFO call.
 ****************************************************************************/
-BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, 
-                          SMB_STRUCT_STAT *sbuf, uint32 *attributes )
-{
-       unsigned int param_len = 0;
-       unsigned int data_len = 0;
-       uint16 setup = TRANSACT2_QPATHINFO;
-       char param[sizeof(pstring)+6];
-       char *rparam=NULL, *rdata=NULL;
-       char *p;
-       pstring path;
-       int len;
-       
-       /* send full paths to dfs root shares */
-       
-       if ( cli->dfsroot )
-               pstr_sprintf(path, "\\%s\\%s\\%s", cli->desthost, cli->share, name );
-       else
-               pstrcpy( path, name );
-       
-       /* cleanup */
-       
-       len = strlen( path );
-       if ( path[len] == '\\' )
-               path[len] = '\0';
 
-       p = param;
-       memset(p, 0, 6);
-       SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
-       p += 6;
-       p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
-       param_len = PTR_DIFF(p, param);
+struct cli_qpathinfo_basic_state {
+       uint32_t num_data;
+       uint8_t *data;
+};
 
-       if (!cli_send_trans(cli, SMBtrans2,
-               NULL,                        /* name */
-               -1, 0,                       /* fid, flags */
-               &setup, 1, 0,                /* setup, length, max */
-               param, param_len, 2,         /* param, length, max */
-               NULL,  0, cli->max_xmit      /* data, length, max */
-               )) {
-                       return False;
-       }
+static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
 
-       if (!cli_receive_trans(cli, SMBtrans2,
-               &rparam, &param_len,
-               &rdata, &data_len)) {
-                       return False;
-       }
+struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
+                                           struct event_context *ev,
+                                           struct cli_state *cli,
+                                           const char *fname)
+{
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_qpathinfo_basic_state *state = NULL;
 
-       if (data_len < 36) {
-               SAFE_FREE(rdata);
-               SAFE_FREE(rparam);
-               return False;
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_qpathinfo_basic_state);
+       if (req == NULL) {
+               return NULL;
        }
-
-       sbuf->st_atime = interpret_long_date( rdata+8 );
-       sbuf->st_mtime = interpret_long_date( rdata+16 );
-       sbuf->st_ctime = interpret_long_date( rdata+24 );
-       
-       *attributes = IVAL( rdata, 32 );
-       
-       SAFE_FREE(rparam);
-       SAFE_FREE(rdata);
-       
-       return True;
+       subreq = cli_qpathinfo_send(state, ev, cli, fname,
+                                   SMB_QUERY_FILE_BASIC_INFO,
+                                   36, cli->max_xmit);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
+       return req;
 }
 
-/****************************************************************************
-send a qfileinfo call
-****************************************************************************/
-
-BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
+static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
 {
-       unsigned int data_len = 0;
-       unsigned int param_len = 0;
-       uint16 setup = TRANSACT2_QFILEINFO;
-       pstring param;
-       char *rparam=NULL, *rdata=NULL;
-
-       *poutdata = NULL;
-       *poutlen = 0;
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_qpathinfo_basic_state *state = tevent_req_data(
+               req, struct cli_qpathinfo_basic_state);
+       NTSTATUS status;
+
+       status = cli_qpathinfo_recv(subreq, state, &state->data,
+                                   &state->num_data);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+       tevent_req_done(req);
+}
 
-       /* if its a win95 server then fail this - win95 totally screws it
-          up */
-       if (cli->win95)
-               return False;
+NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
+                                 SMB_STRUCT_STAT *sbuf, uint32 *attributes)
+{
+       struct cli_qpathinfo_basic_state *state = tevent_req_data(
+               req, struct cli_qpathinfo_basic_state);
+       NTSTATUS status;
 
-       param_len = 4;
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
 
-       memset(param, 0, param_len);
-       SSVAL(param, 0, fnum);
-       SSVAL(param, 2, level);
+       sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
+       sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
+       sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
+       *attributes = IVAL(state->data, 32);
+       return NT_STATUS_OK;
+}
 
-       if (!cli_send_trans(cli, SMBtrans2, 
-                            NULL,                           /* name */
-                            -1, 0,                          /* fid, flags */
-                            &setup, 1, 0,                   /* setup, length, max */
-                            param, param_len, 2,            /* param, length, max */
-                            NULL, data_len, cli->max_xmit   /* data, length, max */
-                           )) {
-               return False;
+NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
+                            SMB_STRUCT_STAT *sbuf, uint32 *attributes)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       if (cli_has_async_calls(cli)) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
        }
-
-       if (!cli_receive_trans(cli, SMBtrans2,
-                               &rparam, &param_len,
-                               &rdata, &data_len)) {
-               return False;
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
        }
-
-       *poutdata = memdup(rdata, data_len);
-       *poutlen = data_len;
-
-       SAFE_FREE(rdata);
-       SAFE_FREE(rparam);
-       return True;
+       req = cli_qpathinfo_basic_send(frame, ev, cli, name);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
 }
 
-
-
 /****************************************************************************
-send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
+ Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
 ****************************************************************************/
+
 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
 {
-       unsigned int data_len = 0;
-       unsigned int param_len = 0;
-       uint16 setup = TRANSACT2_QPATHINFO;
-       pstring param;
-       char *rparam=NULL, *rdata=NULL;
-       int count=8;
-       char *p;
-       BOOL ret;
+       uint8_t *rdata;
+       uint32_t num_rdata;
        unsigned int len;
-
-       p = param;
-       memset(p, 0, 6);
-       SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
-       p += 6;
-       p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
-
-       param_len = PTR_DIFF(p, param);
-
-       do {
-               ret = (cli_send_trans(cli, SMBtrans2, 
-                                     NULL,           /* Name */
-                                     -1, 0,          /* fid, flags */
-                                     &setup, 1, 0,   /* setup, length, max */
-                                     param, param_len, 10, /* param, length, max */
-                                     NULL, data_len, cli->max_xmit /* data, length, max */
-                                     ) &&
-                      cli_receive_trans(cli, SMBtrans2, 
-                                        &rparam, &param_len,
-                                        &rdata, &data_len));
-               if (!ret && cli_is_dos_error(cli)) {
-                       /* we need to work around a Win95 bug - sometimes
-                          it gives ERRSRV/ERRerror temprarily */
-                       uint8 eclass;
-                       uint32 ecode;
-                       cli_dos_error(cli, &eclass, &ecode);
-                       if (eclass != ERRSRV || ecode != ERRerror) break;
-                       smb_msleep(100);
-               }
-       } while (count-- && ret==False);
-
-       if (!ret || !rdata || data_len < 4) {
-               return NT_STATUS_UNSUCCESSFUL;
+       char *converted = NULL;
+       size_t converted_size = 0;
+       NTSTATUS status;
+
+       status = cli_qpathinfo(talloc_tos(), cli, fname,
+                              SMB_QUERY_FILE_ALT_NAME_INFO,
+                              4, cli->max_xmit, &rdata, &num_rdata);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        len = IVAL(rdata, 0);
 
-       if (len > data_len - 4) {
+       if (len > num_rdata - 4) {
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
+       /* The returned data is a pushed string, not raw data. */
+       if (!convert_string_talloc(talloc_tos(),
+                                  cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
+                                  CH_UNIX,
+                                  rdata + 4,
+                                  len,
+                                  &converted,
+                                  &converted_size)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       fstrcpy(alt_name, converted);
 
-       SAFE_FREE(rdata);
-       SAFE_FREE(rparam);
+       TALLOC_FREE(converted);
+       TALLOC_FREE(rdata);
 
        return NT_STATUS_OK;
 }