s3-rpc_cli: make dcerpc_lsa_lookup_sids_generic() public.
[kai/samba.git] / source3 / libsmb / libsmb_dir.c
index 2ece2ab8ed12349ddf5f13f5802baad843a5cd87..700196c10c6fea09960e8015eb6b3962514ea921 100644 (file)
@@ -1,31 +1,36 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    SMB client library implementation
    Copyright (C) Andrew Tridgell 1998
    Copyright (C) Richard Sharpe 2000, 2002
    Copyright (C) John Terpstra 2000
-   Copyright (C) Tom Jansen (Ninja ISD) 2002 
+   Copyright (C) Tom Jansen (Ninja ISD) 2002
    Copyright (C) Derrell Lipman 2003-2008
    Copyright (C) Jeremy Allison 2007, 2008
-   
+
    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 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, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "libsmb/libsmb.h"
+#include "auth_info.h"
 #include "libsmbclient.h"
 #include "libsmb_internal.h"
-
+#include "rpc_client/cli_pipe.h"
+#include "../librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "libsmb/nmblib.h"
+#include "../libcli/smb/smbXcli_base.h"
 
 /*
  * Routine to open a directory
@@ -36,19 +41,19 @@ static void
 remove_dir(SMBCFILE *dir)
 {
        struct smbc_dir_list *d,*f;
-        
+
        d = dir->dir_list;
        while (d) {
-                
+
                f = d; d = d->next;
-                
+
                SAFE_FREE(f->dirent);
                SAFE_FREE(f);
-                
+
        }
-        
+
        dir->dir_list = dir->dir_end = dir->dir_next = NULL;
-        
+
 }
 
 static int
@@ -61,63 +66,63 @@ add_dirent(SMBCFILE *dir,
        int size;
         int name_length = (name == NULL ? 0 : strlen(name));
         int comment_len = (comment == NULL ? 0 : strlen(comment));
-        
+
        /*
-        * Allocate space for the dirent, which must be increased by the 
+        * Allocate space for the dirent, which must be increased by the
         * size of the name and the comment and 1 each for the null terminator.
         */
-        
+
        size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
-        
+
        dirent = (struct smbc_dirent *)SMB_MALLOC(size);
-        
+
        if (!dirent) {
-                
+
                dir->dir_error = ENOMEM;
                return -1;
-                
+
        }
-        
+
        ZERO_STRUCTP(dirent);
-        
+
        if (dir->dir_list == NULL) {
-                
+
                dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
                if (!dir->dir_list) {
-                        
+
                        SAFE_FREE(dirent);
                        dir->dir_error = ENOMEM;
                        return -1;
-                        
+
                }
                ZERO_STRUCTP(dir->dir_list);
-                
+
                dir->dir_end = dir->dir_next = dir->dir_list;
        }
        else {
-                
+
                dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
-                
+
                if (!dir->dir_end->next) {
-                        
+
                        SAFE_FREE(dirent);
                        dir->dir_error = ENOMEM;
                        return -1;
-                        
+
                }
                ZERO_STRUCTP(dir->dir_end->next);
-                
+
                dir->dir_end = dir->dir_end->next;
        }
-        
+
        dir->dir_end->next = NULL;
        dir->dir_end->dirent = dirent;
-        
+
        dirent->smbc_type = type;
        dirent->namelen = name_length;
        dirent->commentlen = comment_len;
        dirent->dirlen = size;
-        
+
         /*
          * dirent->namelen + 1 includes the null (no null termination needed)
          * Ditto for dirent->commentlen.
@@ -126,9 +131,9 @@ add_dirent(SMBCFILE *dir,
        strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
        dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
        strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
-        
+
        return 0;
-        
+
 }
 
 static void
@@ -142,18 +147,19 @@ list_unique_wg_fn(const char *name,
         struct smbc_dirent *dirent;
        int dirent_type;
         int do_remove = 0;
-        
+
        dirent_type = dir->dir_type;
-        
+
        if (add_dirent(dir, name, comment, dirent_type) < 0) {
-                
                /* An error occurred, what do we do? */
                /* FIXME: Add some code here */
+               /* Change cli_NetServerEnum to take a fn
+                  returning NTSTATUS... JRA. */
        }
-        
+
         /* Point to the one just added */
         dirent = dir->dir_end->dirent;
-        
+
         /* See if this was a duplicate */
         for (dir_list = dir->dir_list;
              dir_list != dir->dir_end;
@@ -163,7 +169,7 @@ list_unique_wg_fn(const char *name,
                         /* Duplicate.  End end of list need to be removed. */
                         do_remove = 1;
                 }
-                
+
                 if (do_remove && dir_list->next == dir->dir_end) {
                         /* Found the end of the list.  Remove it. */
                         dir->dir_end = dir_list;
@@ -183,7 +189,7 @@ list_fn(const char *name,
 {
        SMBCFILE *dir = (SMBCFILE *)state;
        int dirent_type;
-        
+
        /*
          * We need to process the type a little ...
          *
@@ -195,27 +201,27 @@ list_fn(const char *name,
          * administrative shares:
          * ADMIN$, IPC$, C$, D$, E$ ...  are type |= 0x80000000
          */
-        
+
        if (dir->dir_type == SMBC_FILE_SHARE) {
                switch (type) {
                 case 0 | 0x80000000:
                case 0:
                        dirent_type = SMBC_FILE_SHARE;
                        break;
-                        
+
                case 1:
                        dirent_type = SMBC_PRINTER_SHARE;
                        break;
-                        
+
                case 2:
                        dirent_type = SMBC_COMMS_SHARE;
                        break;
-                        
+
                 case 3 | 0x80000000:
                case 3:
                        dirent_type = SMBC_IPC_SHARE;
                        break;
-                        
+
                default:
                        dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
                        break;
@@ -224,31 +230,28 @@ list_fn(const char *name,
        else {
                 dirent_type = dir->dir_type;
         }
-        
+
        if (add_dirent(dir, name, comment, dirent_type) < 0) {
-                
                /* An error occurred, what do we do? */
                /* FIXME: Add some code here */
-                
+               /* Change cli_NetServerEnum to take a fn
+                  returning NTSTATUS... JRA. */
        }
 }
 
-static void
+static NTSTATUS
 dir_list_fn(const char *mnt,
-            file_info *finfo,
+            struct file_info *finfo,
             const char *mask,
             void *state)
 {
-        
-       if (add_dirent((SMBCFILE *)state, finfo->name, "", 
-                      (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
-                
-               /* Handle an error ... */
-                
-               /* FIXME: Add some code ... */
-                
-       } 
-        
+
+       if (add_dirent((SMBCFILE *)state, finfo->name, "",
+                      (finfo->mode&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
+               SMBCFILE *dir = (SMBCFILE *)state;
+               return map_nt_error_from_unix(dir->dir_error);
+       }
+       return NT_STATUS_OK;
 }
 
 static int
@@ -261,60 +264,81 @@ net_share_enum_rpc(struct cli_state *cli,
 {
         int i;
        WERROR result;
-       ENUM_HND enum_hnd;
-        uint32 info_level = 1;
        uint32 preferred_len = 0xffffffff;
         uint32 type;
-       SRV_SHARE_INFO_CTR ctr;
+       struct srvsvc_NetShareInfoCtr info_ctr;
+       struct srvsvc_NetShareCtr1 ctr1;
        fstring name = "";
         fstring comment = "";
-       struct rpc_pipe_client *pipe_hnd;
+       struct rpc_pipe_client *pipe_hnd = NULL;
         NTSTATUS nt_status;
-        
+       uint32_t resume_handle = 0;
+       uint32_t total_entries = 0;
+       struct dcerpc_binding_handle *b;
+
         /* Open the server service pipe */
-        pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status);
-        if (!pipe_hnd) {
+        nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
+                                            &pipe_hnd);
+        if (!NT_STATUS_IS_OK(nt_status)) {
                 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
                 return -1;
         }
-        
+
+       ZERO_STRUCT(info_ctr);
+       ZERO_STRUCT(ctr1);
+
+       info_ctr.level = 1;
+       info_ctr.ctr.ctr1 = &ctr1;
+
+       b = pipe_hnd->binding_handle;
+
         /* Issue the NetShareEnum RPC call and retrieve the response */
-       init_enum_hnd(&enum_hnd, 0);
-       result = rpccli_srvsvc_net_share_enum(pipe_hnd,
-                                              talloc_tos(),
-                                              info_level,
-                                              &ctr,
-                                              preferred_len,
-                                              &enum_hnd);
-        
+       nt_status = dcerpc_srvsvc_NetShareEnumAll(b, talloc_tos(),
+                                                 pipe_hnd->desthost,
+                                                 &info_ctr,
+                                                 preferred_len,
+                                                 &total_entries,
+                                                 &resume_handle,
+                                                 &result);
+
         /* Was it successful? */
-       if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) {
+       if (!NT_STATUS_IS_OK(nt_status)) {
+                /*  Nope.  Go clean up. */
+               result = ntstatus_to_werror(nt_status);
+               goto done;
+       }
+
+       if (!W_ERROR_IS_OK(result)) {
                 /*  Nope.  Go clean up. */
                goto done;
         }
-        
+
+       if (total_entries == 0) {
+                /*  Nope.  Go clean up. */
+               result = WERR_GENERAL_FAILURE;
+               goto done;
+       }
+
         /* For each returned entry... */
-        for (i = 0; i < ctr.num_entries; i++) {
-                
+        for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
+
                 /* pull out the share name */
-                rpcstr_pull_unistr2_fstring(
-                        name, &ctr.share.info1[i].info_1_str.uni_netname);
-                
+               fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
+
                 /* pull out the share's comment */
-                rpcstr_pull_unistr2_fstring(
-                        comment, &ctr.share.info1[i].info_1_str.uni_remark);
-                
+               fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
+
                 /* Get the type value */
-                type = ctr.share.info1[i].info_1.type;
-                
+                type = info_ctr.ctr.ctr1->array[i].type;
+
                 /* Add this share to the list */
                 (*fn)(name, type, comment, state);
         }
-        
+
 done:
         /* Close the server service pipe */
-        cli_rpc_pipe_close(pipe_hnd);
-        
+        TALLOC_FREE(pipe_hnd);
+
         /* Tell 'em if it worked */
         return W_ERROR_IS_OK(result) ? 0 : -1;
 }
@@ -332,10 +356,10 @@ SMBC_check_options(char *server,
         DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
                   "path='%s' options='%s'\n",
                   server, share, path, options));
-        
+
         /* No options at all is always ok */
         if (! *options) return 0;
-        
+
         /* Currently, we don't support any options. */
         return -1;
 }
@@ -359,22 +383,22 @@ SMBC_opendir_ctx(SMBCCTX *context,
        SMBCFILE *dir = NULL;
        struct sockaddr_storage rem_ss;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+
        if (!context || !context->internal->initialized) {
                DEBUG(4, ("no valid context\n"));
-               errno = EINVAL + 8192;
                TALLOC_FREE(frame);
+               errno = EINVAL + 8192;
                return NULL;
-                
+
        }
-        
+
        if (!fname) {
                DEBUG(4, ("no valid fname\n"));
-               errno = EINVAL + 8193;
                TALLOC_FREE(frame);
+               errno = EINVAL + 8193;
                return NULL;
        }
-        
+
        if (SMBC_parse_path(frame,
                             context,
                             fname,
@@ -386,74 +410,75 @@ SMBC_opendir_ctx(SMBCCTX *context,
                             &password,
                             &options)) {
                DEBUG(4, ("no valid path\n"));
-               errno = EINVAL + 8194;
                TALLOC_FREE(frame);
+               errno = EINVAL + 8194;
                return NULL;
        }
-        
+
        DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
                   "path='%s' options='%s'\n",
                   fname, server, share, path, options));
-        
+
         /* Ensure the options are valid */
         if (SMBC_check_options(server, share, path, options)) {
                 DEBUG(4, ("unacceptable options (%s)\n", options));
-                errno = EINVAL + 8195;
                TALLOC_FREE(frame);
+                errno = EINVAL + 8195;
                 return NULL;
         }
-        
+
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->config.user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
-                       errno = ENOMEM;
                        TALLOC_FREE(frame);
+                       errno = ENOMEM;
                        return NULL;
                }
        }
-        
+
        dir = SMB_MALLOC_P(SMBCFILE);
-        
+
        if (!dir) {
-               errno = ENOMEM;
                TALLOC_FREE(frame);
+               errno = ENOMEM;
                return NULL;
        }
-        
+
        ZERO_STRUCTP(dir);
-        
+
        dir->cli_fd   = 0;
        dir->fname    = SMB_STRDUP(fname);
        dir->srv      = NULL;
        dir->offset   = 0;
        dir->file     = False;
        dir->dir_list = dir->dir_next = dir->dir_end = NULL;
-        
+
        if (server[0] == (char)0) {
-                
+
                 int i;
                 int count;
                 int max_lmb_count;
-                struct ip_service *ip_list;
-                struct ip_service server_addr;
+                struct sockaddr_storage *ip_list;
+                struct sockaddr_storage server_addr;
                 struct user_auth_info u_info;
-                
+               NTSTATUS status;
+
                if (share[0] != (char)0 || path[0] != (char)0) {
-                        
-                       errno = EINVAL + 8196;
+
                        if (dir) {
                                SAFE_FREE(dir->fname);
                                SAFE_FREE(dir);
                        }
                        TALLOC_FREE(frame);
+                       errno = EINVAL + 8196;
                        return NULL;
                }
-                
+
                 /* Determine how many local master browsers to query */
-                max_lmb_count = (context->options.browse_max_lmb_count == 0
+                max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
                                  ? INT_MAX
-                                 : context->options.browse_max_lmb_count);
-                
+                                 : smbc_getOptionBrowseMaxLmbCount(context));
+
                memset(&u_info, '\0', sizeof(u_info));
                u_info.username = talloc_strdup(frame,user);
                u_info.password = talloc_strdup(frame,password);
@@ -465,7 +490,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                        TALLOC_FREE(frame);
                        return NULL;
                }
-                
+
                /*
                  * We have server and share and path empty but options
                  * requesting that we scan all master browsers for their list
@@ -474,45 +499,51 @@ SMBC_opendir_ctx(SMBCCTX *context,
                  * doesn't work, then try our other methods which return only
                  * a single master browser.
                  */
-                
+
                 ip_list = NULL;
-                if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
-                                                        &count)))
+               status = name_resolve_bcast(MSBROWSE, 1, talloc_tos(),
+                                           &ip_list, &count);
+                if (!NT_STATUS_IS_OK(status))
                {
-                        
-                        SAFE_FREE(ip_list);
-                        
-                        if (!find_master_ip(workgroup, &server_addr.ss)) {
-                                
+
+                        TALLOC_FREE(ip_list);
+
+                        if (!find_master_ip(workgroup, &server_addr)) {
+
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
-                                errno = ENOENT;
                                TALLOC_FREE(frame);
+                                errno = ENOENT;
                                 return NULL;
                         }
-                        
-                       ip_list = (struct ip_service *)memdup(
-                               &server_addr, sizeof(server_addr));
+
+                       ip_list = (struct sockaddr_storage *)talloc_memdup(
+                               talloc_tos(), &server_addr,
+                               sizeof(server_addr));
                        if (ip_list == NULL) {
-                               errno = ENOMEM;
+                               if (dir) {
+                                       SAFE_FREE(dir->fname);
+                                       SAFE_FREE(dir);
+                               }
                                TALLOC_FREE(frame);
+                               errno = ENOMEM;
                                return NULL;
                        }
                         count = 1;
                 }
-                
+
                 for (i = 0; i < count && i < max_lmb_count; i++) {
                        char addr[INET6_ADDRSTRLEN];
                        char *wg_ptr = NULL;
                        struct cli_state *cli = NULL;
-                        
-                       print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
+
+                       print_sockaddr(addr, sizeof(addr), &ip_list[i]);
                         DEBUG(99, ("Found master browser %d of %d: %s\n",
                                    i+1, MAX(count, max_lmb_count),
                                    addr));
-                        
+
                         cli = get_ipc_connect_master_ip(talloc_tos(),
                                                        &ip_list[i],
                                                         &u_info,
@@ -522,39 +553,43 @@ SMBC_opendir_ctx(SMBCCTX *context,
                        if (!cli) {
                                continue;
                        }
-                        
+
                        workgroup = talloc_strdup(frame, wg_ptr);
-                       server = talloc_strdup(frame, cli->desthost);
-                        
+                       server = talloc_strdup(frame, smbXcli_conn_remote_name(cli->conn));
+
                         cli_shutdown(cli);
-                        
+
                        if (!workgroup || !server) {
-                               errno = ENOMEM;
+                               if (dir) {
+                                       SAFE_FREE(dir->fname);
+                                       SAFE_FREE(dir);
+                               }
                                TALLOC_FREE(frame);
+                               errno = ENOMEM;
                                return NULL;
                        }
-                        
+
                         DEBUG(4, ("using workgroup %s %s\n",
                                   workgroup, server));
-                        
+
                         /*
                          * For each returned master browser IP address, get a
                          * connection to IPC$ on the server if we do not
                          * already have one, and determine the
                          * workgroups/domains that it knows about.
                          */
-                        
+
                         srv = SMBC_server(frame, context, True, server, "IPC$",
                                           &workgroup, &user, &password);
                         if (!srv) {
                                 continue;
                         }
-                        
+
                         dir->srv = srv;
                         dir->dir_type = SMBC_WORKGROUP;
-                        
+
                         /* Now, list the stuff ... */
-                        
+
                         if (!cli_NetServerEnum(srv->cli,
                                                workgroup,
                                                SV_TYPE_DOMAIN_ENUM,
@@ -563,8 +598,8 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                 continue;
                         }
                 }
-                
-                SAFE_FREE(ip_list);
+
+                TALLOC_FREE(ip_list);
         } else {
                 /*
                  * Server not an empty string ... Check the rest and see what
@@ -572,18 +607,18 @@ SMBC_opendir_ctx(SMBCCTX *context,
                  */
                if (*share == '\0') {
                        if (*path != '\0') {
-                                
+
                                 /* Should not have empty share with path */
-                               errno = EINVAL + 8197;
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
                                TALLOC_FREE(frame);
+                               errno = EINVAL + 8197;
                                return NULL;
-                                
+
                        }
-                        
+
                        /*
                          * We don't know if <server> is really a server name
                          * or is a workgroup/domain name.  If we already have
@@ -592,7 +627,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                          * <server><1B>, or <server><20> translates.  We check
                          * to see if <server> is an IP address first.
                          */
-                        
+
                         /*
                          * See if we have an existing server.  Do not
                          * establish a connection if one does not already
@@ -601,39 +636,48 @@ SMBC_opendir_ctx(SMBCCTX *context,
                         srv = SMBC_server(frame, context, False,
                                           server, "IPC$",
                                           &workgroup, &user, &password);
-                        
+
                         /*
                          * If no existing server and not an IP addr, look for
                          * LMB or DMB
                          */
                        if (!srv &&
                             !is_ipaddress(server) &&
-                           (resolve_name(server, &rem_ss, 0x1d) ||   /* LMB */
-                             resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
-                                
+                           (resolve_name(server, &rem_ss, 0x1d, false) ||   /* LMB */
+                             resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
+                               /*
+                                * "server" is actually a workgroup name,
+                                * not a server. Make this clear.
+                                */
+                               char *wgroup = server;
                                fstring buserver;
-                                
+
                                dir->dir_type = SMBC_SERVER;
-                                
+
                                /*
                                 * Get the backup list ...
                                 */
-                               if (!name_status_find(server, 0, 0,
+                               if (!name_status_find(wgroup, 0, 0,
                                                       &rem_ss, buserver)) {
-                                        
+                                       char addr[INET6_ADDRSTRLEN];
+
+                                       print_sockaddr(addr, sizeof(addr), &rem_ss);
                                         DEBUG(0,("Could not get name of "
-                                                 "local/domain master browser "
-                                                 "for server %s\n", server));
+                                                "local/domain master browser "
+                                                "for workgroup %s from "
+                                               "address %s\n",
+                                               wgroup,
+                                               addr));
                                        if (dir) {
                                                SAFE_FREE(dir->fname);
                                                SAFE_FREE(dir);
                                        }
-                                       errno = EPERM;
                                        TALLOC_FREE(frame);
+                                       errno = EPERM;
                                        return NULL;
-                                        
+
                                }
-                                
+
                                /*
                                  * Get a connection to IPC$ on the server if
                                  * we do not already have one
@@ -650,16 +694,16 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                        }
                                        TALLOC_FREE(frame);
                                        return NULL;
-                                        
+
                                }
-                                
+
                                dir->srv = srv;
-                                
+
                                /* Now, list the servers ... */
-                               if (!cli_NetServerEnum(srv->cli, server,
+                               if (!cli_NetServerEnum(srv->cli, wgroup,
                                                        0x0000FFFE, list_fn,
                                                       (void *)dir)) {
-                                        
+
                                        if (dir) {
                                                SAFE_FREE(dir->fname);
                                                SAFE_FREE(dir);
@@ -668,8 +712,8 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                        return NULL;
                                }
                        } else if (srv ||
-                                   (resolve_name(server, &rem_ss, 0x20))) {
-                                
+                                   (resolve_name(server, &rem_ss, 0x20, false))) {
+
                                 /*
                                  * If we hadn't found the server, get one now
                                  */
@@ -679,7 +723,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                                           &workgroup,
                                                           &user, &password);
                                 }
-                                
+
                                 if (!srv) {
                                         if (dir) {
                                                 SAFE_FREE(dir->fname);
@@ -687,14 +731,14 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                         }
                                        TALLOC_FREE(frame);
                                         return NULL;
-                                        
+
                                 }
-                                
+
                                 dir->dir_type = SMBC_FILE_SHARE;
                                 dir->srv = srv;
-                                
+
                                 /* List the shares ... */
-                                
+
                                 if (net_share_enum_rpc(
                                             srv->cli,
                                             list_fn,
@@ -703,7 +747,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                             srv->cli,
                                             list_fn,
                                             (void *)dir) < 0) {
-                                        
+
                                         errno = cli_errno(srv->cli);
                                         if (dir) {
                                                 SAFE_FREE(dir->fname);
@@ -711,7 +755,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                         }
                                        TALLOC_FREE(frame);
                                         return NULL;
-                                        
+
                                 }
                         } else {
                                 /* Neither the workgroup nor server exists */
@@ -723,7 +767,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                TALLOC_FREE(frame);
                                 return NULL;
                        }
-                        
+
                }
                else {
                         /*
@@ -732,13 +776,14 @@ SMBC_opendir_ctx(SMBCCTX *context,
                          */
                        char *targetpath;
                        struct cli_state *targetcli;
-                        
+                       NTSTATUS status;
+
                        /* We connect to the server and list the directory */
                        dir->dir_type = SMBC_FILE_SHARE;
-                        
+
                        srv = SMBC_server(frame, context, True, server, share,
                                           &workgroup, &user, &password);
-                        
+
                        if (!srv) {
                                if (dir) {
                                        SAFE_FREE(dir->fname);
@@ -747,11 +792,11 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                TALLOC_FREE(frame);
                                return NULL;
                        }
-                        
+
                        dir->srv = srv;
-                        
+
                        /* Now, list the files ... */
-                        
+
                         p = path + strlen(path);
                        path = talloc_asprintf_append(path, "\\*");
                        if (!path) {
@@ -762,9 +807,11 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                TALLOC_FREE(frame);
                                return NULL;
                        }
-                        
-                       if (!cli_resolve_path(frame, "", srv->cli, path,
-                                              &targetcli, &targetpath)) {
+
+                       status = cli_resolve_path(
+                               frame, "", context->internal->auth_info,
+                               srv->cli, path, &targetcli, &targetpath);
+                       if (!NT_STATUS_IS_OK(status)) {
                                d_printf("Could not resolve %s\n", path);
                                if (dir) {
                                        SAFE_FREE(dir->fname);
@@ -773,17 +820,17 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                TALLOC_FREE(frame);
                                return NULL;
                        }
-                        
-                       if (cli_list(targetcli, targetpath,
-                                     aDIR | aSYSTEM | aHIDDEN,
-                                     dir_list_fn, (void *)dir) < 0) {
-                                
+
+                       status = cli_list(targetcli, targetpath,
+                                         FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                                         dir_list_fn, (void *)dir);
+                       if (!NT_STATUS_IS_OK(status)) {
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
                                saved_errno = SMBC_errno(context, targetcli);
-                                
+
                                 if (saved_errno == EINVAL) {
                                         /*
                                          * See if they asked to opendir
@@ -793,28 +840,28 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                          * than ENOTDIR.
                                          */
                                         *p = '\0'; /* restore original path */
-                                        
+
                                         if (SMBC_getatr(context, srv, path,
                                                         &mode, NULL,
                                                         NULL, NULL, NULL, NULL,
                                                         NULL) &&
                                             ! IS_DOS_DIR(mode)) {
-                                                
+
                                                 /* It is.  Correct the error value */
                                                 saved_errno = ENOTDIR;
                                         }
                                 }
-                                
+
                                 /*
                                  * If there was an error and the server is no
                                  * good any more...
                                  */
                                 if (cli_is_error(targetcli) &&
-                                    (context->server.check_server_fn)(context, srv)) {
-                                        
+                                    smbc_getFunctionCheckServer(context)(context, srv)) {
+
                                         /* ... then remove it. */
-                                        if ((context->server.remove_unused_server_fn)(context,
-                                                                                      srv)) { 
+                                        if (smbc_getFunctionRemoveUnusedServer(context)(context,
+                                                                                        srv)) {
                                                 /*
                                                  * We could not remove the
                                                  * server completely, remove
@@ -823,22 +870,22 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                                  * will be removed when the
                                                  * last file/dir is closed.
                                                  */
-                                                (context->cache.remove_cached_server_fn)(context, srv);
+                                                smbc_getFunctionRemoveCachedServer(context)(context, srv);
                                         }
                                 }
-                                
-                                errno = saved_errno;
+
                                TALLOC_FREE(frame);
+                                errno = saved_errno;
                                return NULL;
                        }
                }
-                
+
        }
-        
+
        DLIST_ADD(context->internal->files, dir);
        TALLOC_FREE(frame);
        return dir;
-        
+
 }
 
 /*
@@ -850,32 +897,32 @@ SMBC_closedir_ctx(SMBCCTX *context,
                   SMBCFILE *dir)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-        
+
        if (!context || !context->internal->initialized) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
                errno = EBADF;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        remove_dir(dir); /* Clean it up */
-        
+
        DLIST_REMOVE(context->internal->files, dir);
-        
+
        if (dir) {
-                
+
                SAFE_FREE(dir->fname);
                SAFE_FREE(dir);    /* Free the space too */
        }
-        
+
        TALLOC_FREE(frame);
        return 0;
-        
+
 }
 
 static void
@@ -884,34 +931,34 @@ smbc_readdir_internal(SMBCCTX * context,
                       struct smbc_dirent *src,
                       int max_namebuf_len)
 {
-        if (context->options.urlencode_readdir_entries) {
-                
+        if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
+
                 /* url-encode the name.  get back remaining buffer space */
                 max_namebuf_len =
-                        SMBC_urlencode(dest->name, src->name, max_namebuf_len);
-                
+                        smbc_urlencode(dest->name, src->name, max_namebuf_len);
+
                 /* We now know the name length */
                 dest->namelen = strlen(dest->name);
-                
+
                 /* Save the pointer to the beginning of the comment */
                 dest->comment = dest->name + dest->namelen + 1;
-                
+
                 /* Copy the comment */
                 strncpy(dest->comment, src->comment, max_namebuf_len - 1);
                 dest->comment[max_namebuf_len - 1] = '\0';
-                
+
                 /* Save other fields */
                 dest->smbc_type = src->smbc_type;
                 dest->commentlen = strlen(dest->comment);
                 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
                                 (char *) dest);
         } else {
-                
+
                 /* No encoding.  Just copy the entry as is. */
                 memcpy(dest, src, src->dirlen);
                 dest->comment = (char *)(&dest->name + src->namelen + 1);
         }
-        
+
 }
 
 /*
@@ -925,58 +972,57 @@ SMBC_readdir_ctx(SMBCCTX *context,
         int maxlen;
        struct smbc_dirent *dirp, *dirent;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+
        /* Check that all is ok first ... */
-        
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;
                 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
                TALLOC_FREE(frame);
                return NULL;
-                
+
        }
-        
+
        if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
-                
+
                errno = EBADF;
                 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
                TALLOC_FREE(frame);
                return NULL;
-                
+
        }
-        
+
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
-                
+
                errno = ENOTDIR;
                 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
                TALLOC_FREE(frame);
                return NULL;
-                
+
        }
-        
+
        if (!dir->dir_next) {
                TALLOC_FREE(frame);
                return NULL;
         }
-        
+
         dirent = dir->dir_next->dirent;
         if (!dirent) {
-                
+
                 errno = ENOENT;
                TALLOC_FREE(frame);
                 return NULL;
-                
+
         }
-        
-        dirp = (struct smbc_dirent *)context->internal->dirent;
-        maxlen = (sizeof(context->internal->dirent) -
-                  sizeof(struct smbc_dirent));
-        
+
+        dirp = &context->internal->dirent;
+        maxlen = sizeof(context->internal->_dirent_name);
+
         smbc_readdir_internal(context, dirp, dirent, maxlen);
-        
+
         dir->dir_next = dir->dir_next->next;
-        
+
        TALLOC_FREE(frame);
         return dirp;
 }
@@ -997,99 +1043,105 @@ SMBC_getdents_ctx(SMBCCTX *context,
        char *ndir = (char *)dirp;
        struct smbc_dir_list *dirlist;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+
        /* Check that all is ok first ... */
-        
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
-                
+
                errno = EBADF;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
-                
+
                errno = ENOTDIR;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
-       /* 
+
+       /*
         * Now, retrieve the number of entries that will fit in what was passed
-        * We have to figure out if the info is in the list, or we need to 
+        * We have to figure out if the info is in the list, or we need to
         * send a request to the server to get the info.
         */
-        
+
        while ((dirlist = dir->dir_next)) {
                struct smbc_dirent *dirent;
-                
+               struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir;
+
                if (!dirlist->dirent) {
-                        
+
                        errno = ENOENT;  /* Bad error */
                        TALLOC_FREE(frame);
                        return -1;
-                        
+
                }
-                
+
                 /* Do urlencoding of next entry, if so selected */
-                dirent = (struct smbc_dirent *)context->internal->dirent;
-                maxlen = (sizeof(context->internal->dirent) -
-                          sizeof(struct smbc_dirent));
+                dirent = &context->internal->dirent;
+                maxlen = sizeof(context->internal->_dirent_name);
                 smbc_readdir_internal(context, dirent,
                                       dirlist->dirent, maxlen);
-                
+
                 reqd = dirent->dirlen;
-                
+
                if (rem < reqd) {
-                        
+
                        if (rem < count) { /* We managed to copy something */
-                                
+
                                errno = 0;
                                TALLOC_FREE(frame);
                                return count - rem;
-                                
+
                        }
                        else { /* Nothing copied ... */
-                                
+
                                errno = EINVAL;  /* Not enough space ... */
                                TALLOC_FREE(frame);
                                return -1;
-                                
+
                        }
-                        
+
                }
-                
-               memcpy(ndir, dirent, reqd); /* Copy the data in ... */
-                
-               ((struct smbc_dirent *)ndir)->comment = 
-                       (char *)(&((struct smbc_dirent *)ndir)->name +
-                                 dirent->namelen +
-                                 1);
-                
+
+               memcpy(currentEntry, dirent, reqd); /* Copy the data in ... */
+
+               currentEntry->comment = &currentEntry->name[0] +
+                                               dirent->namelen + 1;
+
                ndir += reqd;
-                
                rem -= reqd;
-                
+
+               /* Try and align the struct for the next entry
+                  on a valid pointer boundary by appending zeros */
+               while((rem > 0) && ((unsigned long long)ndir & (sizeof(void*) - 1))) {
+                       *ndir = '\0';
+                       rem--;
+                       ndir++;
+                       currentEntry->dirlen++;
+               }
+
                dir->dir_next = dirlist = dirlist -> next;
        }
-        
+
        TALLOC_FREE(frame);
-        
+
        if (rem == count)
                return 0;
        else
                return count - rem;
-        
+
 }
 
 /*
@@ -1111,21 +1163,22 @@ SMBC_mkdir_ctx(SMBCCTX *context,
        char *targetpath = NULL;
        struct cli_state *targetcli = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+       NTSTATUS status;
+
        if (!context || !context->internal->initialized) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        if (!fname) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        DEBUG(4, ("smbc_mkdir(%s)\n", fname));
-        
+
        if (SMBC_parse_path(frame,
                             context,
                             fname,
@@ -1140,64 +1193,65 @@ SMBC_mkdir_ctx(SMBCCTX *context,
                TALLOC_FREE(frame);
                return -1;
         }
-        
+
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->config.user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
                        return -1;
                }
        }
-        
+
        srv = SMBC_server(frame, context, True,
                           server, share, &workgroup, &user, &password);
-        
+
        if (!srv) {
-                
+
                TALLOC_FREE(frame);
                return -1;  /* errno set by SMBC_server */
-                
+
        }
-        
+
        /*d_printf(">>>mkdir: resolving %s\n", path);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path,
-                              &targetcli, &targetpath)) {
+       status = cli_resolve_path(frame, "", context->internal->auth_info,
+                                 srv->cli, path, &targetcli, &targetpath);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("Could not resolve %s\n", path);
-               TALLOC_FREE(frame);
+                errno = ENOENT;
+                TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
-        
-       if (!cli_mkdir(targetcli, targetpath)) {
-                
+
+       if (!NT_STATUS_IS_OK(cli_mkdir(targetcli, targetpath))) {
                errno = SMBC_errno(context, targetcli);
                TALLOC_FREE(frame);
                return -1;
-                
-       } 
-        
+
+       }
+
        TALLOC_FREE(frame);
        return 0;
-        
+
 }
 
 /*
  * Our list function simply checks to see if a directory is not empty
  */
 
-static int smbc_rmdir_dirempty = True;
-
-static void
+static NTSTATUS
 rmdir_list_fn(const char *mnt,
-              file_info *finfo,
+              struct file_info *finfo,
               const char *mask,
               void *state)
 {
        if (strncmp(finfo->name, ".", 1) != 0 &&
             strncmp(finfo->name, "..", 2) != 0) {
-               smbc_rmdir_dirempty = False;
+               bool *smbc_rmdir_dirempty = (bool *)state;
+               *smbc_rmdir_dirempty = false;
         }
+       return NT_STATUS_OK;
 }
 
 /*
@@ -1218,21 +1272,22 @@ SMBC_rmdir_ctx(SMBCCTX *context,
         char *targetpath = NULL;
        struct cli_state *targetcli = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+       NTSTATUS status;
+
        if (!context || !context->internal->initialized) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        if (!fname) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        DEBUG(4, ("smbc_rmdir(%s)\n", fname));
-        
+
        if (SMBC_parse_path(frame,
                             context,
                             fname,
@@ -1247,47 +1302,47 @@ SMBC_rmdir_ctx(SMBCCTX *context,
                TALLOC_FREE(frame);
                return -1;
         }
-        
+
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->config.user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
                        return -1;
                }
        }
-        
+
        srv = SMBC_server(frame, context, True,
                           server, share, &workgroup, &user, &password);
-        
+
        if (!srv) {
-                
+
                TALLOC_FREE(frame);
                return -1;  /* errno set by SMBC_server */
-                
+
        }
-        
+
        /*d_printf(">>>rmdir: resolving %s\n", path);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path,
-                              &targetcli, &targetpath)) {
+       status = cli_resolve_path(frame, "", context->internal->auth_info,
+                                 srv->cli, path, &targetcli, &targetpath);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("Could not resolve %s\n", path);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
-        
-        
-       if (!cli_rmdir(targetcli, targetpath)) {
-                
+
+       if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetpath))) {
+
                errno = SMBC_errno(context, targetcli);
-                
+
                if (errno == EACCES) {  /* Check if the dir empty or not */
-                        
+
                         /* Local storage to avoid buffer overflows */
                        char *lpath;
-                        
-                       smbc_rmdir_dirempty = True;  /* Make this so ... */
-                        
+                       bool smbc_rmdir_dirempty = true;
+
                        lpath = talloc_asprintf(frame, "%s\\*",
                                                targetpath);
                        if (!lpath) {
@@ -1295,34 +1350,36 @@ SMBC_rmdir_ctx(SMBCCTX *context,
                                TALLOC_FREE(frame);
                                return -1;
                        }
-                        
-                       if (cli_list(targetcli, lpath,
-                                     aDIR | aSYSTEM | aHIDDEN,
-                                     rmdir_list_fn, NULL) < 0) {
-                                
+
+                       status = cli_list(targetcli, lpath,
+                                         FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                                         rmdir_list_fn,
+                                         &smbc_rmdir_dirempty);
+
+                       if (!NT_STATUS_IS_OK(status)) {
                                /* Fix errno to ignore latest error ... */
                                DEBUG(5, ("smbc_rmdir: "
                                           "cli_list returned an error: %d\n",
                                          SMBC_errno(context, targetcli)));
                                errno = EACCES;
-                                
+
                        }
-                        
+
                        if (smbc_rmdir_dirempty)
                                errno = EACCES;
                        else
                                errno = ENOTEMPTY;
-                        
+
                }
-                
+
                TALLOC_FREE(frame);
                return -1;
-                
-       } 
-        
+
+       }
+
        TALLOC_FREE(frame);
        return 0;
-        
+
 }
 
 /*
@@ -1334,38 +1391,38 @@ SMBC_telldir_ctx(SMBCCTX *context,
                  SMBCFILE *dir)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-        
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
-                
+
                errno = EBADF;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
-                
+
                errno = ENOTDIR;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
         /* See if we're already at the end. */
         if (dir->dir_next == NULL) {
                 /* We are. */
                TALLOC_FREE(frame);
                 return -1;
         }
-        
+
        /*
         * We return the pointer here as the offset
         */
@@ -1378,29 +1435,29 @@ SMBC_telldir_ctx(SMBCCTX *context,
  */
 
 static struct smbc_dir_list *
-check_dir_ent(struct smbc_dir_list *list, 
+check_dir_ent(struct smbc_dir_list *list,
               struct smbc_dirent *dirent)
 {
-        
+
        /* Run down the list looking for what we want */
-        
+
        if (dirent) {
-                
+
                struct smbc_dir_list *tmp = list;
-                
+
                while (tmp) {
-                        
+
                        if (tmp->dirent == dirent)
                                return tmp;
-                        
+
                        tmp = tmp->next;
-                        
+
                }
-                
+
        }
-        
+
        return NULL;  /* Not found, or an error */
-        
+
 }
 
 
@@ -1417,50 +1474,50 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
        struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
        struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
-                
+
                errno = ENOTDIR;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        /* Now, check what we were passed and see if it is OK ... */
-        
+
        if (dirent == NULL) {  /* Seek to the begining of the list */
-                
+
                dir->dir_next = dir->dir_list;
                TALLOC_FREE(frame);
                return 0;
-                
+
        }
-        
+
         if (offset == -1) {     /* Seek to the end of the list */
                 dir->dir_next = NULL;
                TALLOC_FREE(frame);
                 return 0;
         }
-        
+
        /* Now, run down the list and make sure that the entry is OK       */
        /* This may need to be changed if we change the format of the list */
-        
+
        if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) {
                errno = EINVAL;   /* Bad entry */
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        dir->dir_next = list_ent;
-        
+
        TALLOC_FREE(frame);
        return 0;
 }
@@ -1474,13 +1531,13 @@ SMBC_fstatdir_ctx(SMBCCTX *context,
                   SMBCFILE *dir,
                   struct stat *st)
 {
-        
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;
                return -1;
        }
-        
+
        /* No code yet ... */
        return 0;
 }
@@ -1496,25 +1553,28 @@ SMBC_chmod_ctx(SMBCCTX *context,
         char *user = NULL;
         char *password = NULL;
         char *workgroup = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
        char *path = NULL;
        uint16 mode;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+        NTSTATUS status;
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        if (!fname) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
-       DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode));
-        
+
+       DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, (unsigned int)newmode));
+
        if (SMBC_parse_path(frame,
                             context,
                             fname,
@@ -1529,37 +1589,47 @@ SMBC_chmod_ctx(SMBCCTX *context,
                TALLOC_FREE(frame);
                return -1;
         }
-        
+
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->config.user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
                        return -1;
                }
        }
-        
+
        srv = SMBC_server(frame, context, True,
                           server, share, &workgroup, &user, &password);
-        
+
        if (!srv) {
                TALLOC_FREE(frame);
                return -1;  /* errno set by SMBC_server */
        }
-        
+       
+       /*d_printf(">>>unlink: resolving %s\n", path);*/
+       status = cli_resolve_path(frame, "", context->internal->auth_info,
+                                 srv->cli, path, &targetcli, &targetpath);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("Could not resolve %s\n", path);
+                errno = ENOENT;
+               TALLOC_FREE(frame);
+               return -1;
+       }
+
        mode = 0;
-        
-       if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
-       if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
-       if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
-       if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
-        
-       if (!cli_setatr(srv->cli, path, mode, 0)) {
-               errno = SMBC_errno(context, srv->cli);
+
+       if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= FILE_ATTRIBUTE_READONLY;
+       if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= FILE_ATTRIBUTE_ARCHIVE;
+       if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= FILE_ATTRIBUTE_SYSTEM;
+       if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= FILE_ATTRIBUTE_HIDDEN;
+
+       if (!NT_STATUS_IS_OK(cli_setatr(targetcli, targetpath, mode, 0))) {
+               errno = SMBC_errno(context, targetcli);
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        TALLOC_FREE(frame);
         return 0;
 }
@@ -1579,48 +1649,48 @@ SMBC_utimes_ctx(SMBCCTX *context,
         time_t access_time;
         time_t write_time;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        if (!fname) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
         if (tbuf == NULL) {
                 access_time = write_time = time(NULL);
         } else {
                 access_time = tbuf[0].tv_sec;
                 write_time = tbuf[1].tv_sec;
         }
-        
+
         if (DEBUGLVL(4)) {
                 char *p;
                 char atimebuf[32];
                 char mtimebuf[32];
-                
+
                 strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
                 atimebuf[sizeof(atimebuf) - 1] = '\0';
                 if ((p = strchr(atimebuf, '\n')) != NULL) {
                         *p = '\0';
                 }
-                
+
                 strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
                 mtimebuf[sizeof(mtimebuf) - 1] = '\0';
                 if ((p = strchr(mtimebuf, '\n')) != NULL) {
                         *p = '\0';
                 }
-                
+
                 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
                         fname, atimebuf, mtimebuf);
         }
-        
+
        if (SMBC_parse_path(frame,
                             context,
                             fname,
@@ -1635,30 +1705,30 @@ SMBC_utimes_ctx(SMBCCTX *context,
                TALLOC_FREE(frame);
                return -1;
         }
-        
+
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->config.user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
                        return -1;
                }
        }
-        
+
        srv = SMBC_server(frame, context, True,
                           server, share, &workgroup, &user, &password);
-        
+
        if (!srv) {
                TALLOC_FREE(frame);
                return -1;      /* errno set by SMBC_server */
        }
-        
+
         if (!SMBC_setatr(context, srv, path,
                          0, access_time, write_time, 0, 0)) {
                TALLOC_FREE(frame);
                 return -1;      /* errno set by SMBC_setatr */
         }
-        
+
        TALLOC_FREE(frame);
         return 0;
 }
@@ -1681,22 +1751,23 @@ SMBC_unlink_ctx(SMBCCTX *context,
        struct cli_state *targetcli = NULL;
        SMBCSRV *srv = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+        NTSTATUS status;
+
        if (!context || !context->internal->initialized) {
-                
+
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        if (!fname) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        if (SMBC_parse_path(frame,
                             context,
                             fname,
@@ -1711,80 +1782,82 @@ SMBC_unlink_ctx(SMBCCTX *context,
                TALLOC_FREE(frame);
                 return -1;
         }
-        
+
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->config.user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
                        return -1;
                }
        }
-        
+
        srv = SMBC_server(frame, context, True,
                           server, share, &workgroup, &user, &password);
-        
+
        if (!srv) {
                TALLOC_FREE(frame);
                return -1;  /* SMBC_server sets errno */
-                
+
        }
-        
+
        /*d_printf(">>>unlink: resolving %s\n", path);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path,
-                              &targetcli, &targetpath)) {
+       status = cli_resolve_path(frame, "", context->internal->auth_info,
+                                 srv->cli, path, &targetcli, &targetpath);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("Could not resolve %s\n", path);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
-        
-       if (!cli_unlink(targetcli, targetpath)) {
-                
+
+       if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetpath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))) {
+
                errno = SMBC_errno(context, targetcli);
-                
+
                if (errno == EACCES) { /* Check if the file is a directory */
-                        
+
                        int saverr = errno;
-                       SMB_OFF_T size = 0;
+                       off_t size = 0;
                        uint16 mode = 0;
                        struct timespec write_time_ts;
                         struct timespec access_time_ts;
                         struct timespec change_time_ts;
                        SMB_INO_T ino = 0;
-                        
+
                        if (!SMBC_getatr(context, srv, path, &mode, &size,
                                         NULL,
                                          &access_time_ts,
                                          &write_time_ts,
                                          &change_time_ts,
                                          &ino)) {
-                                
+
                                /* Hmmm, bad error ... What? */
-                                
+
                                errno = SMBC_errno(context, targetcli);
                                TALLOC_FREE(frame);
                                return -1;
-                                
+
                        }
                        else {
-                                
+
                                if (IS_DOS_DIR(mode))
                                        errno = EISDIR;
                                else
                                        errno = saverr;  /* Restore this */
-                                
+
                        }
                }
-                
+
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
        TALLOC_FREE(frame);
        return 0;  /* Success ... */
-        
+
 }
 
 /*
@@ -1793,7 +1866,7 @@ SMBC_unlink_ctx(SMBCCTX *context,
 
 int
 SMBC_rename_ctx(SMBCCTX *ocontext,
-                const char *oname, 
+                const char *oname,
                 SMBCCTX *ncontext,
                 const char *nname)
 {
@@ -1814,24 +1887,25 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
         struct cli_state *targetcli2 = NULL;
        SMBCSRV *srv = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
-        
+        NTSTATUS status;
+
        if (!ocontext || !ncontext ||
            !ocontext->internal->initialized ||
            !ncontext->internal->initialized) {
-                
+
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        if (!oname || !nname) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
-        
+
        if (SMBC_parse_path(frame,
                             ocontext,
                             oname,
@@ -1846,16 +1920,16 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        if (!user1 || user1[0] == (char)0) {
-               user1 = talloc_strdup(frame, ocontext->config.user);
+               user1 = talloc_strdup(frame, smbc_getUser(ocontext));
                if (!user1) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
                        return -1;
                }
        }
-        
+
        if (SMBC_parse_path(frame,
                             ncontext,
                             nname,
@@ -1870,16 +1944,16 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
                TALLOC_FREE(frame);
                 return -1;
        }
-        
+
        if (!user2 || user2[0] == (char)0) {
-               user2 = talloc_strdup(frame, ncontext->config.user);
+               user2 = talloc_strdup(frame, smbc_getUser(ncontext));
                if (!user2) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
                        return -1;
                }
        }
-        
+
        if (strcmp(server1, server2) || strcmp(share1, share2) ||
            strcmp(user1, user2)) {
                /* Can't rename across file systems, or users?? */
@@ -1887,33 +1961,50 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
                TALLOC_FREE(frame);
                return -1;
        }
-        
+
        srv = SMBC_server(frame, ocontext, True,
                           server1, share1, &workgroup, &user1, &password1);
        if (!srv) {
                TALLOC_FREE(frame);
                return -1;
-                
+
        }
-        
+
+       /* set the credentials to make DFS work */
+       smbc_set_credentials_with_fallback(ocontext,
+                                          workgroup,
+                                          user1,
+                                          password1);
+
        /*d_printf(">>>rename: resolving %s\n", path1);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path1,
-                              &targetcli1, &targetpath1)) {
+       status = cli_resolve_path(frame, "", ocontext->internal->auth_info,
+                                 srv->cli, path1, &targetcli1, &targetpath1);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("Could not resolve %s\n", path1);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
+       
+       /* set the credentials to make DFS work */
+       smbc_set_credentials_with_fallback(ncontext,
+                                          workgroup,
+                                          user2,
+                                          password2);
+       
        /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
        /*d_printf(">>>rename: resolving %s\n", path2);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path2,
-                              &targetcli2, &targetpath2)) {
+       status = cli_resolve_path(frame, "", ncontext->internal->auth_info,
+                                 srv->cli, path2, &targetcli2, &targetpath2);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("Could not resolve %s\n", path2);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
-        
-       if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
+
+       if (strcmp(smbXcli_conn_remote_name(targetcli1->conn), smbXcli_conn_remote_name(targetcli2->conn)) ||
             strcmp(targetcli1->share, targetcli2->share))
        {
                /* can't rename across file systems */
@@ -1921,21 +2012,21 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
                TALLOC_FREE(frame);
                return -1;
        }
-        
-       if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
+
+       if (!NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1, targetpath2))) {
                int eno = SMBC_errno(ocontext, targetcli1);
-                
+
                if (eno != EEXIST ||
-                   !cli_unlink(targetcli1, targetpath2) ||
-                   !cli_rename(targetcli1, targetpath1, targetpath2)) {
-                        
+                   !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) ||
+                   !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1, targetpath2))) {
+
                        errno = eno;
                        TALLOC_FREE(frame);
                        return -1;
-                        
+
                }
        }
-        
+
        TALLOC_FREE(frame);
        return 0; /* Success */
 }