Allow clearing all settable DOS mode bits. A mode value of zero is ignored by
[ira/wip.git] / source3 / libsmb / libsmbclient.c
index f6c793a13b788cfb8ee9afbea9a478a6e743f087..2eb580a52d416aa071e5a85e586cb2ec3538360e 100644 (file)
@@ -6,6 +6,7 @@
    Copyright (C) John Terpstra 2000
    Copyright (C) Tom Jansen (Ninja ISD) 2002 
    Copyright (C) Derrell Lipman 2003, 2004
+   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
@@ -18,8 +19,7 @@
    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"
@@ -112,7 +112,7 @@ smbc_lseek_ctx(SMBCCTX *context,
                off_t offset,
                int whence);
 
-extern BOOL in_client;
+extern bool in_client;
 
 /*
  * Is the logging working / configfile read ? 
@@ -133,6 +133,7 @@ hex2int( unsigned int _char )
 
 /*
  * smbc_urldecode()
+ * and smbc_urldecode_talloc() (internal fn.)
  *
  * Convert strings of %xx to their single character equivalent.  Each 'x' must
  * be a valid hexadecimal digit, or that % sequence is left undecoded.
@@ -142,53 +143,87 @@ hex2int( unsigned int _char )
  * Returns the number of % sequences which could not be converted due to lack
  * of two following hexadecimal digits.
  */
-int
-smbc_urldecode(char *dest, char * src, size_t max_dest_len)
+static int
+smbc_urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src)
 {
-        int old_length = strlen(src);
-        int i = 0;
-        int err_count = 0;
-        pstring temp;
-        char * p;
+       int old_length = strlen(src);
+       int i = 0;
+       int err_count = 0;
+       size_t newlen = 1;
+       char *p, *dest;
 
-        if ( old_length == 0 ) {
-                return 0;
-        }
+       if (old_length == 0) {
+               return 0;
+       }
+
+       *pp_dest = NULL;
+       for (i = 0; i < old_length; ) {
+               unsigned char character = src[i++];
+
+               if (character == '%') {
+                       int a = i+1 < old_length ? hex2int(src[i]) : -1;
+                       int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
 
-        p = temp;
-        while ( i < old_length ) {
-                unsigned char character = src[ i++ ];
+                       /* Replace valid sequence */
+                       if (a != -1 && b != -1) {
+                               /* Replace valid %xx sequence with %dd */
+                               character = (a * 16) + b;
+                               if (character == '\0') {
+                                       break; /* Stop at %00 */
+                               }
+                               i += 2;
+                       } else {
+                               err_count++;
+                       }
+               }
+               newlen++;
+       }
+
+       dest = TALLOC_ARRAY(ctx, char, newlen);
+       if (!dest) {
+               return err_count;
+       }
+
+       err_count = 0;
+       for (p = dest, i = 0; i < old_length; ) {
+                unsigned char character = src[i++];
 
                 if (character == '%') {
-                        int a = i+1 < old_length ? hex2int( src[i] ) : -1;
-                        int b = i+1 < old_length ? hex2int( src[i+1] ) : -1;
+                        int a = i+1 < old_length ? hex2int(src[i]) : -1;
+                        int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
 
                         /* Replace valid sequence */
                         if (a != -1 && b != -1) {
-
                                 /* Replace valid %xx sequence with %dd */
                                 character = (a * 16) + b;
-
                                 if (character == '\0') {
                                         break; /* Stop at %00 */
                                 }
-
                                 i += 2;
                         } else {
-
                                 err_count++;
                         }
                 }
-
                 *p++ = character;
         }
 
         *p = '\0';
+       *pp_dest = dest;
+        return err_count;
+}
 
-        strncpy(dest, temp, max_dest_len - 1);
-        dest[max_dest_len - 1] = '\0';
+int
+smbc_urldecode(char *dest, char *src, size_t max_dest_len)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       char *pdest;
+       int ret = smbc_urldecode_talloc(frame, &pdest, src);
 
-        return err_count;
+       if (pdest) {
+               strlcpy(dest, pdest, max_dest_len);
+       }
+       TALLOC_FREE(frame);
+       return ret;
 }
 
 /*
@@ -200,7 +235,7 @@ smbc_urldecode(char *dest, char * src, size_t max_dest_len)
  * Returns the remaining buffer length.
  */
 int
-smbc_urlencode(char * dest, char * src, int max_dest_len)
+smbc_urlencode(char *dest, char *src, int max_dest_len)
 {
         char hex[] = "0123456789ABCDEF";
 
@@ -227,7 +262,7 @@ smbc_urlencode(char * dest, char * src, int max_dest_len)
 
         *dest++ = '\0';
         max_dest_len--;
-        
+
         return max_dest_len;
 }
 
@@ -271,37 +306,46 @@ smbc_urlencode(char * dest, char * src, int max_dest_len)
 static const char *smbc_prefix = "smb:";
 
 static int
-smbc_parse_path(SMBCCTX *context,
+smbc_parse_path(TALLOC_CTX *ctx,
+               SMBCCTX *context,
                 const char *fname,
-                char *workgroup, int workgroup_len,
-                char *server, int server_len,
-                char *share, int share_len,
-                char *path, int path_len,
-               char *user, int user_len,
-                char *password, int password_len,
-                char *options, int options_len)
+                char **pp_workgroup,
+                char **pp_server,
+                char **pp_share,
+                char **pp_path,
+               char **pp_user,
+                char **pp_password,
+                char **pp_options)
 {
-       static pstring s;
-       pstring userinfo;
+       char *s;
        const char *p;
        char *q, *r;
        int len;
 
-       server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
+       /* Ensure these returns are at least valid pointers. */
+       *pp_server = talloc_strdup(ctx, "");
+       *pp_share = talloc_strdup(ctx, "");
+       *pp_path = talloc_strdup(ctx, "");
+       *pp_user = talloc_strdup(ctx, "");
+       *pp_password = talloc_strdup(ctx, "");
+
+       if (!*pp_server || !*pp_share || !*pp_path ||
+                       !*pp_user || !*pp_password) {
+               return -1;
+       }
 
         /*
          * Assume we wont find an authentication domain to parse, so default
          * to the workgroup in the provided context.
          */
-        if (workgroup != NULL) {
-                strncpy(workgroup, context->workgroup, workgroup_len - 1);
-                workgroup[workgroup_len - 1] = '\0';
-        }
+       if (pp_workgroup != NULL) {
+               *pp_workgroup = talloc_strdup(ctx, context->workgroup);
+       }
 
-        if (options != NULL && options_len > 0) {
-                options[0] = (char)0;
-        }
-       pstrcpy(s, fname);
+       if (pp_options) {
+               *pp_options = talloc_strdup(ctx, "");
+       }
+       s = talloc_strdup(ctx, fname);
 
        /* see if it has the right prefix */
        len = strlen(smbc_prefix);
@@ -314,10 +358,8 @@ smbc_parse_path(SMBCCTX *context,
        /* Watch the test below, we are testing to see if we should exit */
 
        if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
-
                 DEBUG(1, ("Invalid path (does not begin with smb://"));
                return -1;
-
        }
 
        p += 2;  /* Skip the double slash */
@@ -326,17 +368,19 @@ smbc_parse_path(SMBCCTX *context,
         if ((q = strrchr(p, '?')) != NULL ) {
                 /* There are options.  Null terminate here and point to them */
                 *q++ = '\0';
-                
+
                 DEBUG(4, ("Found options '%s'", q));
 
-                /* Copy the options */
-                if (options != NULL && options_len > 0) {
-                        safe_strcpy(options, q, options_len - 1);
-                }
-        }
+               /* Copy the options */
+               if (*pp_options != NULL) {
+                       TALLOC_FREE(*pp_options);
+                       *pp_options = talloc_strdup(ctx, q);
+               }
+       }
 
-       if (*p == (char)0)
-           goto decoding;
+       if (*p == '\0') {
+               goto decoding;
+       }
 
        if (*p == '/') {
                int wl = strlen(context->workgroup);
@@ -345,13 +389,16 @@ smbc_parse_path(SMBCCTX *context,
                        wl = 16;
                }
 
-               strncpy(server, context->workgroup, wl);
-                server[wl] = '\0';
+               *pp_server = talloc_strdup(ctx, context->workgroup);
+               if (!*pp_server) {
+                       return -1;
+               }
+                       *pp_server[wl] = '\0';
                return 0;
        }
 
        /*
-        * ok, its for us. Now parse out the server, share etc. 
+        * ok, its for us. Now parse out the server, share etc.
         *
         * However, we want to parse out [[domain;]user[:password]@] if it
         * exists ...
@@ -361,81 +408,78 @@ smbc_parse_path(SMBCCTX *context,
        q = strchr_m(p, '@');
        r = strchr_m(p, '/');
        if (q && (!r || q < r)) {
-               pstring username, passwd, domain;
-               const char *u = userinfo;
-
-               next_token_no_ltrim(&p, userinfo, "@", sizeof(fstring));
+               char *userinfo = NULL;
+               const char *u;
 
-               username[0] = passwd[0] = domain[0] = 0;
+               next_token_no_ltrim_talloc(ctx, &p, &userinfo, "@");
+               if (!userinfo) {
+                       return -1;
+               }
+               u = userinfo;
 
                if (strchr_m(u, ';')) {
-      
-                       next_token_no_ltrim(&u, domain, ";", sizeof(fstring));
-
+                       char *workgroup;
+                       next_token_no_ltrim_talloc(ctx, &u, &workgroup, ";");
+                       if (!workgroup) {
+                               return -1;
+                       }
+                       if (pp_workgroup) {
+                               *pp_workgroup = workgroup;
+                       }
                }
 
                if (strchr_m(u, ':')) {
-
-                       next_token_no_ltrim(&u, username, ":", sizeof(fstring));
-
-                       pstrcpy(passwd, u);
-
-               }
-               else {
-
-                       pstrcpy(username, u);
-
+                       next_token_no_ltrim_talloc(ctx, &u, pp_user, ":");
+                       if (!*pp_user) {
+                               return -1;
+                       }
+                       *pp_password = talloc_strdup(ctx, u);
+                       if (!*pp_password) {
+                               return -1;
+                       }
+               } else {
+                       *pp_user = talloc_strdup(ctx, u);
+                       if (!*pp_user) {
+                               return -1;
+                       }
                }
-
-                if (domain[0] && workgroup) {
-                        strncpy(workgroup, domain, workgroup_len - 1);
-                        workgroup[workgroup_len - 1] = '\0';
-                }
-
-               if (username[0]) {
-                       strncpy(user, username, user_len - 1);
-                        user[user_len - 1] = '\0';
-                }
-
-               if (passwd[0]) {
-                       strncpy(password, passwd, password_len - 1);
-                        password[password_len - 1] = '\0';
-                }
-
        }
 
-       if (!next_token(&p, server, "/", sizeof(fstring))) {
-
+       if (!next_token_talloc(ctx, &p, pp_server, "/")) {
                return -1;
-
        }
 
-       if (*p == (char)0) goto decoding;  /* That's it ... */
-  
-       if (!next_token(&p, share, "/", sizeof(fstring))) {
+       if (*p == (char)0) {
+               goto decoding;  /* That's it ... */
+       }
 
+       if (!next_token_talloc(ctx, &p, pp_share, "/")) {
                return -1;
-
        }
 
         /*
          * Prepend a leading slash if there's a file path, as required by
          * NetApp filers.
          */
-        *path = '\0';
         if (*p != '\0') {
-                *path = '/';
-                safe_strcpy(path + 1, p, path_len - 2);
-        }
-
-       all_string_sub(path, "/", "\\", 0);
+               *pp_path = talloc_asprintf(ctx,
+                                       "\\%s",
+                                       p);
+        } else {
+               *pp_path = talloc_strdup(ctx, "");
+       }
+       if (!*pp_path) {
+               return -1;
+       }
+       string_replace(*pp_path, '/', '\\');
 
  decoding:
-       (void) smbc_urldecode(path, path, path_len);
-       (void) smbc_urldecode(server, server, server_len);
-       (void) smbc_urldecode(share, share, share_len);
-       (void) smbc_urldecode(user, user, user_len);
-       (void) smbc_urldecode(password, password, password_len);
+
+       (void) smbc_urldecode_talloc(ctx, pp_path, *pp_path);
+       (void) smbc_urldecode_talloc(ctx, pp_server, *pp_server);
+       (void) smbc_urldecode_talloc(ctx, pp_share, *pp_share);
+       (void) smbc_urldecode_talloc(ctx, pp_user, *pp_user);
+       (void) smbc_urldecode_talloc(ctx, pp_password, *pp_password);
 
        return 0;
 }
@@ -503,30 +547,8 @@ smbc_check_server(SMBCCTX * context,
         socklen_t size;
         struct sockaddr addr;
 
-        /*
-         * Although the use of port 139 is not a guarantee that we're using
-         * netbios, we assume so.  We don't want to send a keepalive packet if
-         * not netbios because it's not valid, and Vista, at least,
-         * disconnects the client on such a request.
-         */
-        if (server->cli->port == 139) {
-                /* Assuming netbios.  Send a keepalive packet */
-                if ( send_keepalive(server->cli->fd) == False ) {
-                        return 1;
-                }
-        } else {
-                /*
-                 * Assuming not netbios.  Try a different method to detect if
-                 * the connection is still alive.
-                 */
-                size = sizeof(addr);
-                if (getpeername(server->cli->fd, &addr, &size) == -1) {
-                        return 1;
-                }
-        }
-
-       /* connection is ok */
-       return 0;
+        size = sizeof(addr);
+        return (getpeername(server->cli->fd, &addr, &size) == -1);
 }
 
 /* 
@@ -551,7 +573,7 @@ smbc_remove_unused_server(SMBCCTX * context,
                if (file->srv == srv) {
                        /* Still used */
                        DEBUG(3, ("smbc_remove_usused_server: "
-                                  "%p still used by %p.\n", 
+                                  "%p still used by %p.\n",
                                  srv, file));
                        return 1;
                }
@@ -564,44 +586,81 @@ smbc_remove_unused_server(SMBCCTX * context,
 
        DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
 
-       context->callbacks.remove_cached_srv_fn(context, srv);
+       (context->callbacks.remove_cached_srv_fn)(context, srv);
 
         SAFE_FREE(srv);
-       
        return 0;
 }
 
+/****************************************************************
+ * Call the auth_fn with fixed size (fstring) buffers.
+ ***************************************************************/
+
+static void call_auth_fn(TALLOC_CTX *ctx,
+                       SMBCCTX *context,
+                       const char *server,
+                       const char *share,
+                       char **pp_workgroup,
+                       char **pp_username,
+                       char **pp_password)
+{
+       fstring workgroup;
+       fstring username;
+       fstring password;
+
+       strlcpy(workgroup, *pp_workgroup, sizeof(workgroup));
+       strlcpy(username, *pp_username, sizeof(username));
+       strlcpy(password, *pp_password, sizeof(password));
+
+       if (context->internal->_auth_fn_with_context != NULL) {
+                       (context->internal->_auth_fn_with_context)(
+                               context,
+                               server, share,
+                               workgroup, sizeof(workgroup),
+                               username, sizeof(username),
+                               password, sizeof(password));
+       } else {
+               (context->callbacks.auth_fn)(
+                       server, share,
+                       workgroup, sizeof(workgroup),
+                       username, sizeof(username),
+                       password, sizeof(password));
+       }
+
+       TALLOC_FREE(*pp_workgroup);
+       TALLOC_FREE(*pp_username);
+       TALLOC_FREE(*pp_password);
+
+       *pp_workgroup = talloc_strdup(ctx, workgroup);
+       *pp_username = talloc_strdup(ctx, username);
+       *pp_password = talloc_strdup(ctx, password);
+}
+
 static SMBCSRV *
-find_server(SMBCCTX *context,
-            const char *server,
-            const char *share,
-            fstring workgroup,
-            fstring username,
-            fstring password)
+find_server(TALLOC_CTX *ctx,
+               SMBCCTX *context,
+               const char *server,
+               const char *share,
+               char **pp_workgroup,
+               char **pp_username,
+               char **pp_password)
 {
         SMBCSRV *srv;
         int auth_called = 0;
-        
+
  check_server_cache:
 
-       srv = context->callbacks.get_cached_srv_fn(context, server, share, 
-                                                  workgroup, username);
-
-       if (!auth_called && !srv && (!username[0] || !password[0])) {
-                if (context->internal->_auth_fn_with_context != NULL) {
-                         context->internal->_auth_fn_with_context(
-                                context,
-                                server, share,
-                                workgroup, sizeof(fstring),
-                                username, sizeof(fstring),
-                                password, sizeof(fstring));
-                } else {
-                        context->callbacks.auth_fn(
-                                server, share,
-                                workgroup, sizeof(fstring),
-                                username, sizeof(fstring),
-                                password, sizeof(fstring));
-                }
+       srv = (context->callbacks.get_cached_srv_fn)(context, server, share,
+                                               *pp_workgroup, *pp_username);
+
+       if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] ||
+                               !*pp_password || !(*pp_password)[0])) {
+               call_auth_fn(ctx, context, server, share,
+                               pp_workgroup, pp_username, pp_password);
+
+               if (!pp_workgroup || !pp_username || !pp_password) {
+                       return NULL;
+               }
 
                /*
                  * However, smbc_auth_fn may have picked up info relating to
@@ -610,33 +669,33 @@ find_server(SMBCCTX *context,
                  */
                auth_called = 1;
                goto check_server_cache;
-               
+
        }
-       
+
        if (srv) {
-               if (context->callbacks.check_server_fn(context, srv)) {
+               if ((context->callbacks.check_server_fn)(context, srv)) {
                        /*
-                         * This server is no good anymore 
+                         * This server is no good anymore
                          * Try to remove it and check for more possible
                          * servers in the cache
                          */
-                       if (context->callbacks.remove_unused_server_fn(context,
-                                                                       srv)) { 
+                       if ((context->callbacks.remove_unused_server_fn)(context,
+                                                                         srv)) { 
                                 /*
                                  * We could not remove the server completely,
                                  * remove it from the cache so we will not get
                                  * it again. It will be removed when the last
                                  * file/dir is closed.
                                  */
-                               context->callbacks.remove_cached_srv_fn(context,
-                                                                        srv);
+                               (context->callbacks.remove_cached_srv_fn)(context,
+                                                                          srv);
                        }
-                       
+
                        /*
                          * Maybe there are more cached connections to this
                          * server
                          */
-                       goto check_server_cache; 
+                       goto check_server_cache;
                }
 
                return srv;
@@ -649,7 +708,7 @@ find_server(SMBCCTX *context,
  * Connect to a server, possibly on an existing connection
  *
  * Here, what we want to do is: If the server and username
- * match an existing connection, reuse that, otherwise, establish a 
+ * match an existing connection, reuse that, otherwise, establish a
  * new connection.
  *
  * If we have to create a new connection, call the auth_fn to get the
@@ -657,27 +716,27 @@ find_server(SMBCCTX *context,
  */
 
 static SMBCSRV *
-smbc_server(SMBCCTX *context,
-            BOOL connect_if_not_found,
-            const char *server,
-            const char *share, 
-            fstring workgroup,
-            fstring username, 
-            fstring password)
+smbc_server(TALLOC_CTX *ctx,
+               SMBCCTX *context,
+               bool connect_if_not_found,
+               const char *server,
+               const char *share,
+               char **pp_workgroup,
+               char **pp_username,
+               char **pp_password)
 {
        SMBCSRV *srv=NULL;
        struct cli_state *c;
        struct nmb_name called, calling;
        const char *server_n = server;
-       pstring ipenv;
-       struct in_addr ip;
+       struct sockaddr_storage ss;
        int tried_reverse = 0;
         int port_try_first;
         int port_try_next;
         const char *username_used;
        NTSTATUS status;
 
-       zero_ip(&ip);
+       zero_addr(&ss);
        ZERO_STRUCT(c);
 
        if (server[0] == 0) {
@@ -686,9 +745,9 @@ smbc_server(SMBCCTX *context,
        }
 
         /* Look for a cached connection */
-        srv = find_server(context, server, share,
-                          workgroup, username, password);
-        
+        srv = find_server(ctx, context, server, share,
+                          pp_workgroup, pp_username, pp_password);
+
         /*
          * If we found a connection and we're only allowed one share per
          * server...
@@ -705,29 +764,33 @@ smbc_server(SMBCCTX *context,
                  */
                 if (srv->cli->cnum == (uint16) -1) {
                         /* Ensure we have accurate auth info */
-                        if (context->internal->_auth_fn_with_context != NULL) {
-                                context->internal->_auth_fn_with_context(
-                                        context,
-                                        server, share,
-                                        workgroup, sizeof(fstring),
-                                        username, sizeof(fstring),
-                                        password, sizeof(fstring));
-                        } else {
-                                context->callbacks.auth_fn(
-                                        server, share,
-                                        workgroup, sizeof(fstring),
-                                        username, sizeof(fstring),
-                                        password, sizeof(fstring));
-                        }
+                       call_auth_fn(ctx, context, server, share,
+                               pp_workgroup, pp_username, pp_password);
+
+                       if (!*pp_workgroup || !*pp_username || !*pp_password) {
+                               errno = ENOMEM;
+                               cli_shutdown(srv->cli);
+                               srv->cli = NULL;
+                               (context->callbacks.remove_cached_srv_fn)(context,
+                                                                       srv);
+                               return NULL;
+                       }
+
+                       /*
+                        * We don't need to renegotiate encryption
+                        * here as the encryption context is not per
+                        * tid.
+                        */
+
+                       if (!cli_send_tconX(srv->cli, share, "?????",
+                                               *pp_password,
+                                               strlen(*pp_password)+1)) {
 
-                        if (! cli_send_tconX(srv->cli, share, "?????",
-                                             password, strlen(password)+1)) {
-                        
                                 errno = smbc_errno(context, srv->cli);
                                 cli_shutdown(srv->cli);
                                srv->cli = NULL;
-                                context->callbacks.remove_cached_srv_fn(context,
-                                                                        srv);
+                                (context->callbacks.remove_cached_srv_fn)(context,
+                                                                          srv);
                                 srv = NULL;
                         }
 
@@ -741,7 +804,7 @@ smbc_server(SMBCCTX *context,
                         }
                 }
         }
-        
+
         /* If we have a connection... */
         if (srv) {
 
@@ -755,17 +818,21 @@ smbc_server(SMBCCTX *context,
                 return NULL;
         }
 
+       if (!*pp_workgroup || !*pp_username || !*pp_password) {
+               errno = ENOMEM;
+               return NULL;
+       }
+
        make_nmb_name(&calling, context->netbios_name, 0x0);
        make_nmb_name(&called , server, 0x20);
 
        DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
-  
+
        DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
 
  again:
-       slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
 
-       zero_ip(&ip);
+       zero_addr(&ss);
 
        /* have to open a new connection */
        if ((c = cli_initialise()) == NULL) {
@@ -796,13 +863,13 @@ smbc_server(SMBCCTX *context,
 
         c->port = port_try_first;
 
-       status = cli_connect(c, server_n, &ip);
+       status = cli_connect(c, server_n, &ss);
        if (!NT_STATUS_IS_OK(status)) {
 
                 /* First connection attempt failed.  Try alternate port. */
                 c->port = port_try_next;
 
-                status = cli_connect(c, server_n, &ip);
+                status = cli_connect(c, server_n, &ss);
                if (!NT_STATUS_IS_OK(status)) {
                        cli_shutdown(c);
                        errno = ETIMEDOUT;
@@ -821,18 +888,20 @@ smbc_server(SMBCCTX *context,
 
                        if (is_ipaddress(server) && !tried_reverse) {
                                fstring remote_name;
-                               struct in_addr rem_ip;
+                               struct sockaddr_storage rem_ss;
 
-                               if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) {
+                               if (!interpret_string_addr(&rem_ss, server,
+                                                       NI_NUMERICHOST)) {
                                        DEBUG(4, ("Could not convert IP address "
-                                               "%s to struct in_addr\n", server));
+                                               "%s to struct sockaddr_storage\n",
+                                               server));
                                        errno = ETIMEDOUT;
                                        return NULL;
                                }
 
                                tried_reverse++; /* Yuck */
 
-                               if (name_status_find("*", 0, 0, rem_ip, remote_name)) {
+                               if (name_status_find("*", 0, 0, &rem_ss, remote_name)) {
                                        make_nmb_name(&called, remote_name, 0x20);
                                        goto again;
                                }
@@ -841,30 +910,30 @@ smbc_server(SMBCCTX *context,
                errno = ETIMEDOUT;
                return NULL;
        }
-  
+
        DEBUG(4,(" session request ok\n"));
-  
+
        if (!cli_negprot(c)) {
                cli_shutdown(c);
                errno = ETIMEDOUT;
                return NULL;
        }
 
-        username_used = username;
+        username_used = *pp_username;
+
+       if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
+                                              *pp_password, strlen(*pp_password),
+                                              *pp_password, strlen(*pp_password),
+                                              *pp_workgroup))) {
 
-       if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, 
-                                              password, strlen(password),
-                                              password, strlen(password),
-                                              workgroup))) {
-                
                 /* Failed.  Try an anonymous login, if allowed by flags. */
                 username_used = "";
 
                 if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) ||
                      !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
-                                                       password, 1,
-                                                       password, 0,
-                                                       workgroup))) {
+                                                       *pp_password, 1,
+                                                       *pp_password, 0,
+                                                       *pp_workgroup))) {
 
                         cli_shutdown(c);
                         errno = EPERM;
@@ -875,14 +944,38 @@ smbc_server(SMBCCTX *context,
        DEBUG(4,(" session setup ok\n"));
 
        if (!cli_send_tconX(c, share, "?????",
-                           password, strlen(password)+1)) {
+                           *pp_password, strlen(*pp_password)+1)) {
                errno = smbc_errno(context, c);
                cli_shutdown(c);
                return NULL;
        }
-  
+
        DEBUG(4,(" tconx ok\n"));
-  
+
+       if (context->internal->_smb_encryption_level) {
+               /* Attempt UNIX smb encryption. */
+               if (!NT_STATUS_IS_OK(cli_force_encryption(c,
+                                               username_used,
+                                               *pp_password,
+                                               *pp_workgroup))) {
+
+                       /*
+                        * context->internal->_smb_encryption_level == 1
+                        * means don't fail if encryption can't be negotiated,
+                        * == 2 means fail if encryption can't be negotiated.
+                        */
+
+                       DEBUG(4,(" SMB encrypt failed\n"));
+
+                       if (context->internal->_smb_encryption_level == 2) {
+                               cli_shutdown(c);
+                               errno = EPERM;
+                               return NULL;
+                       }
+               }
+               DEBUG(4,(" SMB encrypt ok\n"));
+       }
+
        /*
         * Ok, we have got a nice connection
         * Let's allocate a server structure.
@@ -904,7 +997,10 @@ smbc_server(SMBCCTX *context,
        /* now add it to the cache (internal or external)  */
        /* Let the cache function set errno if it wants to */
        errno = 0;
-       if (context->callbacks.add_cached_srv_fn(context, srv, server, share, workgroup, username)) {
+       if ((context->callbacks.add_cached_srv_fn)(context, srv,
+                                               server, share,
+                                               *pp_workgroup,
+                                               *pp_username)) {
                int saved_errno = errno;
                DEBUG(3, (" Failed to add server to cache\n"));
                errno = saved_errno;
@@ -913,8 +1009,8 @@ smbc_server(SMBCCTX *context,
                }
                goto failed;
        }
-       
-       DEBUG(2, ("Server connect ok: //%s/%s: %p\n", 
+
+       DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
                  server, share, srv));
 
        DLIST_ADD(context->internal->_servers, srv);
@@ -925,7 +1021,7 @@ smbc_server(SMBCCTX *context,
        if (!srv) {
                return NULL;
        }
-  
+
        SAFE_FREE(srv);
        return NULL;
 }
@@ -935,16 +1031,16 @@ smbc_server(SMBCCTX *context,
  * connection.  This works similarly to smbc_server().
  */
 static SMBCSRV *
-smbc_attr_server(SMBCCTX *context,
-                 const char *server,
-                 const char *share, 
-                 fstring workgroup,
-                 fstring username,
-                 fstring password,
-                 POLICY_HND *pol)
+smbc_attr_server(TALLOC_CTX *ctx,
+               SMBCCTX *context,
+               const char *server,
+               const char *share,
+               char **pp_workgroup,
+               char **pp_username,
+               char **pp_password)
 {
         int flags;
-        struct in_addr ip;
+        struct sockaddr_storage ss;
        struct cli_state *ipc_cli;
        struct rpc_pipe_client *pipe_hnd;
         NTSTATUS nt_status;
@@ -955,41 +1051,35 @@ smbc_attr_server(SMBCCTX *context,
          * our "special" share name '*IPC$', which is an impossible real share
          * name due to the leading asterisk.
          */
-        ipc_srv = find_server(context, server, "*IPC$",
-                              workgroup, username, password);
+        ipc_srv = find_server(ctx, context, server, "*IPC$",
+                              pp_workgroup, pp_username, pp_password);
         if (!ipc_srv) {
 
                 /* We didn't find a cached connection.  Get the password */
-                if (*password == '\0') {
+               if (!*pp_password || (*pp_password)[0] == '\0') {
                         /* ... then retrieve it now. */
-                        if (context->internal->_auth_fn_with_context != NULL) {
-                                context->internal->_auth_fn_with_context(
-                                        context,
-                                        server, share,
-                                        workgroup, sizeof(fstring),
-                                        username, sizeof(fstring),
-                                        password, sizeof(fstring));
-                        } else {
-                                context->callbacks.auth_fn(
-                                        server, share,
-                                        workgroup, sizeof(fstring),
-                                        username, sizeof(fstring),
-                                        password, sizeof(fstring));
-                        }
+                       call_auth_fn(ctx, context, server, share,
+                               pp_workgroup, pp_username, pp_password);
+                       if (!*pp_workgroup || !*pp_username || !*pp_password) {
+                               errno = ENOMEM;
+                               return NULL;
+                       }
                 }
-        
+
                 flags = 0;
                 if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
                         flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
                 }
 
-                zero_ip(&ip);
+                zero_addr(&ss);
                 nt_status = cli_full_connection(&ipc_cli,
-                                                global_myname(), server, 
-                                                &ip, 0, "IPC$", "?????",  
-                                                username, workgroup,
-                                                password, flags,
-                                                Undefined, NULL);
+                                               global_myname(), server,
+                                               &ss, 0, "IPC$", "?????",
+                                               *pp_username,
+                                               *pp_workgroup,
+                                               *pp_password,
+                                               flags,
+                                               Undefined, NULL);
                 if (! NT_STATUS_IS_OK(nt_status)) {
                         DEBUG(1,("cli_full_connection failed! (%s)\n",
                                  nt_errstr(nt_status)));
@@ -997,6 +1087,30 @@ smbc_attr_server(SMBCCTX *context,
                         return NULL;
                 }
 
+               if (context->internal->_smb_encryption_level) {
+                       /* Attempt UNIX smb encryption. */
+                       if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli,
+                                               *pp_username,
+                                               *pp_password,
+                                               *pp_workgroup))) {
+
+                               /*
+                                * context->internal->_smb_encryption_level == 1
+                                * means don't fail if encryption can't be negotiated,
+                                * == 2 means fail if encryption can't be negotiated.
+                                */
+
+                               DEBUG(4,(" SMB encrypt failed on IPC$\n"));
+
+                               if (context->internal->_smb_encryption_level == 2) {
+                                       cli_shutdown(ipc_cli);
+                                       errno = EPERM;
+                                       return NULL;
+                               }
+                       }
+                       DEBUG(4,(" SMB encrypt ok on IPC$\n"));
+               }
+
                 ipc_srv = SMB_MALLOC_P(SMBCSRV);
                 if (!ipc_srv) {
                         errno = ENOMEM;
@@ -1007,46 +1121,44 @@ smbc_attr_server(SMBCCTX *context,
                 ZERO_STRUCTP(ipc_srv);
                 ipc_srv->cli = ipc_cli;
 
-                if (pol) {
-                        pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli,
-                                                            PI_LSARPC,
-                                                            &nt_status);
-                        if (!pipe_hnd) {
-                                DEBUG(1, ("cli_nt_session_open fail!\n"));
-                                errno = ENOTSUP;
-                                cli_shutdown(ipc_srv->cli);
-                                free(ipc_srv);
-                                return NULL;
-                        }
+                pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli,
+                                                    PI_LSARPC,
+                                                    &nt_status);
+                if (!pipe_hnd) {
+                    DEBUG(1, ("cli_nt_session_open fail!\n"));
+                    errno = ENOTSUP;
+                    cli_shutdown(ipc_srv->cli);
+                    free(ipc_srv);
+                    return NULL;
+                }
 
-                        /*
-                         * Some systems don't support
-                         * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000
-                         * so we might as well do it too.
-                         */
-        
-                        nt_status = rpccli_lsa_open_policy(
-                                pipe_hnd,
-                                ipc_srv->cli->mem_ctx,
-                                True, 
-                                GENERIC_EXECUTE_ACCESS,
-                                pol);
-        
-                        if (!NT_STATUS_IS_OK(nt_status)) {
-                                errno = smbc_errno(context, ipc_srv->cli);
-                                cli_shutdown(ipc_srv->cli);
-                                return NULL;
-                        }
+                /*
+                 * Some systems don't support
+                 * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000
+                 * so we might as well do it too.
+                 */
+
+                nt_status = rpccli_lsa_open_policy(
+                    pipe_hnd,
+                    talloc_tos(),
+                    True,
+                    GENERIC_EXECUTE_ACCESS,
+                    &ipc_srv->pol);
+
+                if (!NT_STATUS_IS_OK(nt_status)) {
+                    errno = smbc_errno(context, ipc_srv->cli);
+                    cli_shutdown(ipc_srv->cli);
+                    return NULL;
                 }
 
                 /* now add it to the cache (internal or external) */
 
                 errno = 0;      /* let cache function set errno if it likes */
-                if (context->callbacks.add_cached_srv_fn(context, ipc_srv,
-                                                         server,
-                                                         "*IPC$",
-                                                         workgroup,
-                                                         username)) {
+                if ((context->callbacks.add_cached_srv_fn)(context, ipc_srv,
+                                                       server,
+                                                       "*IPC$",
+                                                       *pp_workgroup,
+                                                       *pp_username)) {
                         DEBUG(3, (" Failed to add server to cache\n"));
                         if (errno == 0) {
                                 errno = ENOMEM;
@@ -1072,18 +1184,20 @@ smbc_open_ctx(SMBCCTX *context,
               int flags,
               mode_t mode)
 {
-       fstring server, share, user, password, workgroup;
-       pstring path;
-        pstring targetpath;
-       struct cli_state *targetcli;
+       char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = NULL;
+       char *path = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
        SMBCSRV *srv   = NULL;
        SMBCFILE *file = NULL;
        int fd;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
 
                errno = EINVAL;  /* Best I can think of ... */
+               TALLOC_FREE(frame);
                return NULL;
 
        }
@@ -1091,63 +1205,68 @@ smbc_open_ctx(SMBCCTX *context,
        if (!fname) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return NULL;
 
        }
 
-       if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
-                return NULL;
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return NULL;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return NULL;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       srv = smbc_server(frame, context, True,
+                          server, share, &workgroup, &user, &password);
 
        if (!srv) {
-
                if (errno == EPERM) errno = EACCES;
+               TALLOC_FREE(frame);
                return NULL;  /* smbc_server sets errno */
-    
        }
 
        /* Hmmm, the test for a directory is suspect here ... FIXME */
 
        if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
-    
                fd = -1;
-
-       }
-       else {
-         
+       } else {
                file = SMB_MALLOC_P(SMBCFILE);
 
                if (!file) {
-
                        errno = ENOMEM;
+                       TALLOC_FREE(frame);
                        return NULL;
-
                }
 
                ZERO_STRUCTP(file);
 
                /*d_printf(">>>open: resolving %s\n", path);*/
-               if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
-               {
+               if (!cli_resolve_path(frame, "", srv->cli, path, &targetcli, &targetpath)) {
                        d_printf("Could not resolve %s\n", path);
                        SAFE_FREE(file);
+                       TALLOC_FREE(frame);
                        return NULL;
                }
                /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
-               
+
                if ((fd = cli_open(targetcli, targetpath, flags,
                                    context->internal->_share_mode)) < 0) {
 
@@ -1155,6 +1274,7 @@ smbc_open_ctx(SMBCCTX *context,
 
                        SAFE_FREE(file);
                        errno = smbc_errno(context, targetcli);
+                       TALLOC_FREE(frame);
                        return NULL;
 
                }
@@ -1195,10 +1315,12 @@ smbc_open_ctx(SMBCCTX *context,
                         if (smbc_lseek_ctx(context, file, 0, SEEK_END) < 0) {
                                 (void) smbc_close_ctx(context, file);
                                 errno = ENXIO;
+                               TALLOC_FREE(frame);
                                 return NULL;
                         }
                 }
 
+               TALLOC_FREE(frame);
                return file;
 
        }
@@ -1209,13 +1331,15 @@ smbc_open_ctx(SMBCCTX *context,
                int eno = 0;
 
                eno = smbc_errno(context, srv->cli);
-               file = context->opendir(context, fname);
+               file = (context->opendir)(context, fname);
                if (!file) errno = eno;
+               TALLOC_FREE(frame);
                return file;
 
        }
 
        errno = EINVAL; /* FIXME, correct errno ? */
+       TALLOC_FREE(frame);
        return NULL;
 
 }
@@ -1254,9 +1378,11 @@ smbc_read_ctx(SMBCCTX *context,
               size_t count)
 {
        int ret;
-       fstring server, share, user, password;
-       pstring path, targetpath;
-       struct cli_state *targetcli;
+       char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+       char *path = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
         /*
          * offset:
@@ -1271,8 +1397,8 @@ smbc_read_ctx(SMBCCTX *context,
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -1280,8 +1406,8 @@ smbc_read_ctx(SMBCCTX *context,
        DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
-
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -1291,39 +1417,43 @@ smbc_read_ctx(SMBCCTX *context,
        /* Check that the buffer exists ... */
 
        if (buf == NULL) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
 
        /*d_printf(">>>read: parsing %s\n", file->fname);*/
-       if (smbc_parse_path(context, file->fname,
-                            NULL, 0,
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+       if (smbc_parse_path(frame,
+                               context,
+                               file->fname,
+                               NULL,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
         }
-       
+
        /*d_printf(">>>read: resolving %s\n", path);*/
-       if (!cli_resolve_path("", file->srv->cli, path,
-                              &targetcli, targetpath))
-       {
+       if (!cli_resolve_path(frame, "", file->srv->cli, path,
+                              &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
-       
+
        ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count);
 
        if (ret < 0) {
 
                errno = smbc_errno(context, targetcli);
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -1332,6 +1462,7 @@ smbc_read_ctx(SMBCCTX *context,
 
        DEBUG(4, ("  --> %d\n", ret));
 
+       TALLOC_FREE(frame);
        return ret;  /* Success, ret bytes of data ... */
 
 }
@@ -1348,32 +1479,33 @@ smbc_write_ctx(SMBCCTX *context,
 {
        int ret;
         off_t offset;
-       fstring server, share, user, password;
-       pstring path, targetpath;
-       struct cli_state *targetcli;
+       char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+       char *path = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        /* First check all pointers before dereferencing them */
-       
+
        if (!context || !context->internal ||
            !context->internal->_initialized) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
-
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
-    
        }
 
        /* Check that the buffer exists ... */
 
        if (buf == NULL) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -1381,42 +1513,45 @@ smbc_write_ctx(SMBCCTX *context,
         offset = file->offset; /* See "offset" comment in smbc_read_ctx() */
 
        /*d_printf(">>>write: parsing %s\n", file->fname);*/
-       if (smbc_parse_path(context, file->fname,
-                            NULL, 0,
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+       if (smbc_parse_path(frame,
+                               context,
+                               file->fname,
+                               NULL,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
         }
-       
+
        /*d_printf(">>>write: resolving %s\n", path);*/
-       if (!cli_resolve_path("", file->srv->cli, path,
-                              &targetcli, targetpath))
-       {
+       if (!cli_resolve_path(frame, "", file->srv->cli, path,
+                              &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>write: resolved path as %s\n", targetpath);*/
 
-
        ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count);
 
        if (ret <= 0) {
-
                errno = smbc_errno(context, targetcli);
+               TALLOC_FREE(frame);
                return -1;
 
        }
 
        file->offset += ret;
 
+       TALLOC_FREE(frame);
        return ret;  /* Success, 0 bytes of data ... */
 }
+
 /*
  * Routine to close() a file ...
  */
@@ -1425,51 +1560,54 @@ static int
 smbc_close_ctx(SMBCCTX *context,
                SMBCFILE *file)
 {
-        SMBCSRV *srv; 
-       fstring server, share, user, password;
-       pstring path, targetpath;
-       struct cli_state *targetcli;
+        SMBCSRV *srv;
+       char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+       char *path = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
-
        }
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
-   
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
-
        }
 
        /* IS a dir ... */
        if (!file->file) {
-               
-               return context->closedir(context, file);
-
+               TALLOC_FREE(frame);
+               return (context->closedir)(context, file);
        }
 
        /*d_printf(">>>close: parsing %s\n", file->fname);*/
-       if (smbc_parse_path(context, file->fname,
-                            NULL, 0,
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+       if (smbc_parse_path(frame,
+                               context,
+                               file->fname,
+                               NULL,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
         }
-       
+
        /*d_printf(">>>close: resolving %s\n", path);*/
-       if (!cli_resolve_path("", file->srv->cli, path,
-                              &targetcli, targetpath))
-       {
+       if (!cli_resolve_path(frame, "", file->srv->cli, path,
+                              &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>close: resolved path as %s\n", targetpath);*/
@@ -1485,8 +1623,8 @@ smbc_close_ctx(SMBCCTX *context,
                DLIST_REMOVE(context->internal->_files, file);
                SAFE_FREE(file->fname);
                SAFE_FREE(file);
-               context->callbacks.remove_unused_server_fn(context, srv);
-
+               (context->callbacks.remove_unused_server_fn)(context, srv);
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -1494,6 +1632,7 @@ smbc_close_ctx(SMBCCTX *context,
        DLIST_REMOVE(context->internal->_files, file);
        SAFE_FREE(file->fname);
        SAFE_FREE(file);
+       TALLOC_FREE(frame);
 
        return 0;
 }
@@ -1502,48 +1641,58 @@ smbc_close_ctx(SMBCCTX *context,
  * Get info from an SMB server on a file. Use a qpathinfo call first
  * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
  */
-static BOOL
+static bool
 smbc_getatr(SMBCCTX * context,
             SMBCSRV *srv,
-            char *path, 
+            char *path,
             uint16 *mode,
-            SMB_OFF_T *size, 
+            SMB_OFF_T *size,
             struct timespec *create_time_ts,
             struct timespec *access_time_ts,
             struct timespec *write_time_ts,
             struct timespec *change_time_ts,
             SMB_INO_T *ino)
 {
-       pstring fixedpath;
-       pstring targetpath;
-       struct cli_state *targetcli;
+       char *fixedpath = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
        time_t write_time;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
        }
 
        /* path fixup for . and .. */
-       if (strequal(path, ".") || strequal(path, ".."))
-               pstrcpy(fixedpath, "\\");
-       else
-       {
-               pstrcpy(fixedpath, path);
+       if (strequal(path, ".") || strequal(path, "..")) {
+               fixedpath = talloc_strdup(frame, "\\");
+               if (!fixedpath) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       } else {
+               fixedpath = talloc_strdup(frame, path);
+               if (!fixedpath) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
                trim_string(fixedpath, NULL, "\\..");
                trim_string(fixedpath, NULL, "\\.");
        }
        DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
-  
-       if (!cli_resolve_path( "", srv->cli, fixedpath, &targetcli, targetpath))
-       {
+
+       if (!cli_resolve_path(frame, "", srv->cli, fixedpath,
+                               &targetcli, &targetpath)) {
                d_printf("Couldn't resolve %s\n", path);
+               TALLOC_FREE(frame);
                return False;
        }
-       
+
        if (!srv->no_pathinfo2 &&
             cli_qpathinfo2(targetcli, targetpath,
                            create_time_ts,
@@ -1551,12 +1700,14 @@ smbc_getatr(SMBCCTX * context,
                            write_time_ts,
                            change_time_ts,
                            size, mode, ino)) {
-            return True;
+               TALLOC_FREE(frame);
+               return True;
         }
 
        /* if this is NT then don't bother with the getatr */
        if (targetcli->capabilities & CAP_NT_SMBS) {
                 errno = EPERM;
+               TALLOC_FREE(frame);
                 return False;
         }
 
@@ -1573,20 +1724,22 @@ smbc_getatr(SMBCCTX * context,
                 if (create_time_ts != NULL) {
                         *create_time_ts = w_time_ts;
                 }
-                
+
                 if (access_time_ts != NULL) {
                         *access_time_ts = w_time_ts;
                 }
-                
+
                 if (change_time_ts != NULL) {
                         *change_time_ts = w_time_ts;
                 }
 
                srv->no_pathinfo2 = True;
+               TALLOC_FREE(frame);
                return True;
        }
 
         errno = EPERM;
+       TALLOC_FREE(frame);
        return False;
 
 }
@@ -1601,7 +1754,7 @@ smbc_getatr(SMBCCTX * context,
  *
  * "mode" (attributes) parameter may be set to -1 if it is not to be set.
  */
-static BOOL
+static bool
 smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, 
             time_t create_time,
             time_t access_time,
@@ -1611,6 +1764,7 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
 {
         int fd;
         int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
         /*
          * First, try setpathinfo (if qpathinfo succeeded), for it is the
@@ -1643,6 +1797,7 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
                 if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
 
                         errno = smbc_errno(context, srv->cli);
+                       TALLOC_FREE(frame);
                         return -1;
                 }
 
@@ -1667,10 +1822,12 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
 
                 if (! ret) {
                         errno = smbc_errno(context, srv->cli);
+                       TALLOC_FREE(frame);
                         return False;
                 }
         }
 
+       TALLOC_FREE(frame);
         return True;
 }
 
@@ -1682,53 +1839,66 @@ static int
 smbc_unlink_ctx(SMBCCTX *context,
                 const char *fname)
 {
-       fstring server, share, user, password, workgroup;
-       pstring path, targetpath;
-       struct cli_state *targetcli;
+       char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = NULL;
+       char *path = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
        SMBCSRV *srv = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !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(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       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( "", srv->cli, path, &targetcli, targetpath))
-       {
+       if (!cli_resolve_path(frame, "", srv->cli, path,
+                               &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
@@ -1757,6 +1927,7 @@ smbc_unlink_ctx(SMBCCTX *context,
                                /* Hmmm, bad error ... What? */
 
                                errno = smbc_errno(context, targetcli);
+                               TALLOC_FREE(frame);
                                return -1;
 
                        }
@@ -1770,10 +1941,12 @@ smbc_unlink_ctx(SMBCCTX *context,
                        }
                }
 
+               TALLOC_FREE(frame);
                return -1;
 
        }
 
+       TALLOC_FREE(frame);
        return 0;  /* Success ... */
 
 }
@@ -1788,103 +1961,128 @@ smbc_rename_ctx(SMBCCTX *ocontext,
                 SMBCCTX *ncontext,
                 const char *nname)
 {
-       fstring server1;
-        fstring share1;
-        fstring server2;
-        fstring share2;
-        fstring user1;
-        fstring user2;
-        fstring password1;
-        fstring password2;
-        fstring workgroup;
-       pstring path1;
-        pstring path2;
-        pstring targetpath1;
-        pstring targetpath2;
-       struct cli_state *targetcli1;
-        struct cli_state *targetcli2;
+       char *server1 = NULL;
+        char *share1 = NULL;
+        char *server2 = NULL;
+        char *share2 = NULL;
+        char *user1 = NULL;
+        char *user2 = NULL;
+        char *password1 = NULL;
+        char *password2 = NULL;
+        char *workgroup = NULL;
+       char *path1 = NULL;
+        char *path2 = NULL;
+        char *targetpath1 = NULL;
+        char *targetpath2 = NULL;
+       struct cli_state *targetcli1 = NULL;
+        struct cli_state *targetcli2 = NULL;
        SMBCSRV *srv = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!ocontext || !ncontext || 
+       if (!ocontext || !ncontext ||
            !ocontext->internal || !ncontext->internal ||
-           !ocontext->internal->_initialized || 
+           !ocontext->internal->_initialized ||
            !ncontext->internal->_initialized) {
-
                errno = EINVAL;  /* Best I can think of ... */
+               TALLOC_FREE(frame);
                return -1;
-
        }
-       
-       if (!oname || !nname) {
 
+       if (!oname || !nname) {
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
-
        }
-       
+
        DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
 
-       smbc_parse_path(ocontext, oname,
-                        workgroup, sizeof(workgroup),
-                        server1, sizeof(server1),
-                        share1, sizeof(share1),
-                        path1, sizeof(path1),
-                        user1, sizeof(user1),
-                        password1, sizeof(password1),
-                        NULL, 0);
+       if (smbc_parse_path(frame,
+                       ocontext,
+                       oname,
+                       &workgroup,
+                       &server1,
+                       &share1,
+                       &path1,
+                       &user1,
+                       &password1,
+                        NULL)) {
+                errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
+       }
 
-       if (user1[0] == (char)0) fstrcpy(user1, ocontext->user);
+       if (!user1 || user1[0] == (char)0) {
+               user1 = talloc_strdup(frame, ocontext->user);
+               if (!user1) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       smbc_parse_path(ncontext, nname,
-                        NULL, 0,
-                        server2, sizeof(server2),
-                        share2, sizeof(share2),
-                        path2, sizeof(path2),
-                        user2, sizeof(user2),
-                        password2, sizeof(password2),
-                        NULL, 0);
+       if (smbc_parse_path(frame,
+                               ncontext,
+                               nname,
+                               NULL,
+                               &server2,
+                               &share2,
+                               &path2,
+                               &user2,
+                               &password2,
+                               NULL)) {
+                errno = EINVAL;
+               TALLOC_FREE(frame);
+                return -1;
+       }
 
-       if (user2[0] == (char)0) fstrcpy(user2, ncontext->user);
+       if (!user2 || user2[0] == (char)0) {
+               user2 = talloc_strdup(frame, ncontext->user);
+               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?? */
-
                errno = EXDEV;
+               TALLOC_FREE(frame);
                return -1;
-
        }
 
-       srv = smbc_server(ocontext, True,
-                          server1, share1, workgroup, user1, password1);
+       srv = smbc_server(frame, ocontext, True,
+                          server1, share1, &workgroup, &user1, &password1);
        if (!srv) {
-
+               TALLOC_FREE(frame);
                return -1;
 
        }
 
        /*d_printf(">>>rename: resolving %s\n", path1);*/
-       if (!cli_resolve_path( "", srv->cli, path1, &targetcli1, targetpath1))
-       {
+       if (!cli_resolve_path(frame, "", srv->cli, path1,
+                               &targetcli1, &targetpath1)) {
                d_printf("Could not resolve %s\n", path1);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
        /*d_printf(">>>rename: resolving %s\n", path2);*/
-       if (!cli_resolve_path( "", srv->cli, path2, &targetcli2, targetpath2))
-       {
+       if (!cli_resolve_path(frame, "", srv->cli, path2,
+                               &targetcli2, &targetpath2)) {
                d_printf("Could not resolve %s\n", path2);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
-       
+
        if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
             strcmp(targetcli1->share, targetcli2->share))
        {
                /* can't rename across file systems */
-               
                errno = EXDEV;
+               TALLOC_FREE(frame);
                return -1;
        }
 
@@ -1896,13 +2094,14 @@ smbc_rename_ctx(SMBCCTX *ocontext,
                    !cli_rename(targetcli1, targetpath1, targetpath2)) {
 
                        errno = eno;
+                       TALLOC_FREE(frame);
                        return -1;
 
                }
        }
 
+       TALLOC_FREE(frame);
        return 0; /* Success */
-
 }
 
 /*
@@ -1916,21 +2115,23 @@ smbc_lseek_ctx(SMBCCTX *context,
                int whence)
 {
        SMB_OFF_T size;
-       fstring server, share, user, password;
-       pstring path, targetpath;
-       struct cli_state *targetcli;
+       char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+       char *path = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
-               
        }
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
 
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -1938,6 +2139,7 @@ smbc_lseek_ctx(SMBCCTX *context,
        if (!file->file) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;      /* Can't lseek a dir ... */
 
        }
@@ -1953,36 +2155,39 @@ smbc_lseek_ctx(SMBCCTX *context,
 
        case SEEK_END:
                /*d_printf(">>>lseek: parsing %s\n", file->fname);*/
-               if (smbc_parse_path(context, file->fname,
-                                    NULL, 0,
-                                    server, sizeof(server),
-                                    share, sizeof(share),
-                                    path, sizeof(path),
-                                    user, sizeof(user),
-                                    password, sizeof(password),
-                                    NULL, 0)) {
-                        
-                                       errno = EINVAL;
-                                       return -1;
-                       }
-               
+               if (smbc_parse_path(frame,
+                                       context,
+                                       file->fname,
+                                       NULL,
+                                       &server,
+                                       &share,
+                                       &path,
+                                       &user,
+                                       &password,
+                                       NULL)) {
+                       errno = EINVAL;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+
                /*d_printf(">>>lseek: resolving %s\n", path);*/
-               if (!cli_resolve_path("", file->srv->cli, path,
-                                      &targetcli, targetpath))
-               {
+               if (!cli_resolve_path(frame, "", file->srv->cli, path,
+                                      &targetcli, &targetpath)) {
                        d_printf("Could not resolve %s\n", path);
+                       TALLOC_FREE(frame);
                        return -1;
                }
                /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
-               
+
                if (!cli_qfileinfo(targetcli, file->cli_fd, NULL,
-                                   &size, NULL, NULL, NULL, NULL, NULL)) 
+                                   &size, NULL, NULL, NULL, NULL, NULL))
                {
                    SMB_OFF_T b_size = size;
                        if (!cli_getattrE(targetcli, file->cli_fd,
-                                          NULL, &b_size, NULL, NULL, NULL)) 
+                                          NULL, &b_size, NULL, NULL, NULL))
                    {
                        errno = EINVAL;
+                       TALLOC_FREE(frame);
                        return -1;
                    } else
                        size = b_size;
@@ -1996,6 +2201,7 @@ smbc_lseek_ctx(SMBCCTX *context,
 
        }
 
+       TALLOC_FREE(frame);
        return file->offset;
 
 }
@@ -2008,7 +2214,6 @@ static ino_t
 smbc_inode(SMBCCTX *context,
            const char *name)
 {
-
        if (!context || !context->internal ||
            !context->internal->_initialized) {
 
@@ -2034,6 +2239,7 @@ smbc_setup_stat(SMBCCTX *context,
                 SMB_OFF_T size,
                 int mode)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        
        st->st_mode = 0;
 
@@ -2054,6 +2260,9 @@ smbc_setup_stat(SMBCCTX *context,
 #endif
 #ifdef HAVE_STAT_ST_BLOCKS
        st->st_blocks = (size+511)/512;
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+       st->st_rdev = 0;
 #endif
        st->st_uid = getuid();
        st->st_gid = getgid();
@@ -2068,6 +2277,7 @@ smbc_setup_stat(SMBCCTX *context,
                st->st_ino = smbc_inode(context, fname);
        }
        
+       TALLOC_FREE(frame);
        return True;  /* FIXME: Is this needed ? */
 
 }
@@ -2081,79 +2291,90 @@ smbc_stat_ctx(SMBCCTX *context,
               const char *fname,
               struct stat *st)
 {
-       SMBCSRV *srv;
-       fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-       pstring path;
+       SMBCSRV *srv = NULL;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
        struct timespec write_time_ts;
         struct timespec access_time_ts;
         struct timespec change_time_ts;
        SMB_OFF_T size = 0;
        uint16 mode = 0;
        SMB_INO_T ino = 0;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !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_stat(%s)\n", fname));
 
-       if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame,context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       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_getatr(context, srv, path, &mode, &size, 
+       if (!smbc_getatr(context, srv, path, &mode, &size,
                         NULL,
                          &access_time_ts,
                          &write_time_ts,
                          &change_time_ts,
                          &ino)) {
-
                errno = smbc_errno(context, srv->cli);
+               TALLOC_FREE(frame);
                return -1;
-               
        }
 
        st->st_ino = ino;
 
-       smbc_setup_stat(context, st, path, size, mode);
+       smbc_setup_stat(context, st, (char *) fname, size, mode);
 
        set_atimespec(st, access_time_ts);
        set_ctimespec(st, change_time_ts);
        set_mtimespec(st, write_time_ts);
        st->st_dev   = srv->dev;
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -2172,54 +2393,55 @@ smbc_fstat_ctx(SMBCCTX *context,
         struct timespec write_time_ts;
        SMB_OFF_T size;
        uint16 mode;
-       fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-       pstring path;
-        pstring targetpath;
-       struct cli_state *targetcli;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *path = NULL;
+        char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
        SMB_INO_T ino = 0;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
-
        }
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
-
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
-
        }
 
        if (!file->file) {
-
-               return context->fstatdir(context, file, st);
-
+               TALLOC_FREE(frame);
+               return (context->fstatdir)(context, file, st);
        }
 
        /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
-       if (smbc_parse_path(context, file->fname,
-                            NULL, 0,
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+       if (smbc_parse_path(frame,
+                               context,
+                               file->fname,
+                               NULL,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
         }
-       
+
        /*d_printf(">>>fstat: resolving %s\n", path);*/
-       if (!cli_resolve_path("", file->srv->cli, path,
-                              &targetcli, targetpath))
-       {
+       if (!cli_resolve_path(frame, "", file->srv->cli, path,
+                              &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
@@ -2237,6 +2459,7 @@ smbc_fstat_ctx(SMBCCTX *context,
                                &change_time, &access_time, &write_time)) {
 
                        errno = EINVAL;
+                       TALLOC_FREE(frame);
                        return -1;
                }
 
@@ -2254,6 +2477,7 @@ smbc_fstat_ctx(SMBCCTX *context,
        set_mtimespec(st, write_time_ts);
        st->st_dev = file->srv->dev;
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -2421,14 +2645,13 @@ list_fn(const char *name,
          * Disk share     = 0x00000000
          * Print share    = 0x00000001
          * Comms share    = 0x00000002 (obsolete?)
-         * IPC$ share     = 0x00000003 
+         * IPC$ share     = 0x00000003
          *
          * administrative shares:
          * ADMIN$, IPC$, C$, D$, E$ ...  are type |= 0x80000000
          */
-        
+
        if (dir->dir_type == SMBC_FILE_SHARE) {
-               
                switch (type) {
                 case 0 | 0x80000000:
                case 0:
@@ -2492,15 +2715,15 @@ net_share_enum_rpc(struct cli_state *cli,
                    void *state)
 {
         int i;
-       NTSTATUS result;
-       uint32 enum_hnd;
+       WERROR result;
+       ENUM_HND enum_hnd;
         uint32 info_level = 1;
        uint32 preferred_len = 0xffffffff;
-       struct srvsvc_NetShareCtr1 ctr1;
-       union srvsvc_NetShareCtr ctr;
-        void *mem_ctx;
+        uint32 type;
+       SRV_SHARE_INFO_CTR ctr;
+       fstring name = "";
+        fstring comment = "";
        struct rpc_pipe_client *pipe_hnd;
-       uint32 numentries;
         NTSTATUS nt_status;
 
         /* Open the server service pipe */
@@ -2510,47 +2733,45 @@ net_share_enum_rpc(struct cli_state *cli,
                 return -1;
         }
 
-        /* Allocate a context for parsing and for the entries in "ctr" */
-        mem_ctx = talloc_init("libsmbclient: net_share_enum_rpc");
-        if (mem_ctx == NULL) {
-                DEBUG(0, ("out of memory for net_share_enum_rpc!\n"));
-                cli_rpc_pipe_close(pipe_hnd);
-                return -1; 
-        }
-
-       ZERO_STRUCT(ctr1);
-       ctr.ctr1 = &ctr1;
-
         /* Issue the NetShareEnum RPC call and retrieve the response */
-       enum_hnd = 0;
-       result = rpccli_srvsvc_NetShareEnum(pipe_hnd, mem_ctx, NULL,
-                                           &info_level, &ctr, preferred_len,
-                                           &numentries, &enum_hnd);
+       init_enum_hnd(&enum_hnd, 0);
+       result = rpccli_srvsvc_net_share_enum(pipe_hnd,
+                                              talloc_tos(),
+                                              info_level,
+                                              &ctr,
+                                              preferred_len,
+                                              &enum_hnd);
 
         /* Was it successful? */
-       if (!NT_STATUS_IS_OK(result) || numentries == 0) {
+       if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) {
                 /*  Nope.  Go clean up. */
                goto done;
         }
 
         /* For each returned entry... */
-        for (i = 0; i < numentries; i++) {
+        for (i = 0; i < ctr.num_entries; i++) {
+
+                /* pull out the share name */
+                rpcstr_pull_unistr2_fstring(
+                        name, &ctr.share.info1[i].info_1_str.uni_netname);
+
+                /* pull out the share's comment */
+                rpcstr_pull_unistr2_fstring(
+                        comment, &ctr.share.info1[i].info_1_str.uni_remark);
+
+                /* Get the type value */
+                type = ctr.share.info1[i].info_1.type;
 
                 /* Add this share to the list */
-                (*fn)(ctr.ctr1->array[i].name, 
-                                         ctr.ctr1->array[i].type, 
-                                         ctr.ctr1->array[i].comment, state);
+                (*fn)(name, type, comment, state);
         }
 
 done:
         /* Close the server service pipe */
         cli_rpc_pipe_close(pipe_hnd);
 
-        /* Free all memory which was allocated for this request */
-        TALLOC_FREE(mem_ctx);
-
         /* Tell 'em if it worked */
-        return NT_STATUS_IS_OK(result) ? 0 : -1;
+        return W_ERROR_IS_OK(result) ? 0 : -1;
 }
 
 
@@ -2560,20 +2781,22 @@ smbc_opendir_ctx(SMBCCTX *context,
                  const char *fname)
 {
         int saved_errno;
-       fstring server, share, user, password, options;
-       pstring workgroup;
-       pstring path;
+       char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *options = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
         uint16 mode;
-        char *p;
+        char *p = NULL;
        SMBCSRV *srv  = NULL;
        SMBCFILE *dir = NULL;
-        struct _smbc_callbacks *cb;
-       struct in_addr rem_ip;
+        struct _smbc_callbacks *cb = NULL;
+       struct sockaddr_storage rem_ss;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
                DEBUG(4, ("no valid context\n"));
                errno = EINVAL + 8192;
+               TALLOC_FREE(frame);
                return NULL;
 
        }
@@ -2581,19 +2804,23 @@ smbc_opendir_ctx(SMBCCTX *context,
        if (!fname) {
                DEBUG(4, ("no valid fname\n"));
                errno = EINVAL + 8193;
+               TALLOC_FREE(frame);
                return NULL;
        }
 
-       if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            options, sizeof(options))) {
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               &options)) {
                DEBUG(4, ("no valid path\n"));
                errno = EINVAL + 8194;
+               TALLOC_FREE(frame);
                return NULL;
        }
 
@@ -2605,18 +2832,25 @@ smbc_opendir_ctx(SMBCCTX *context,
         if (smbc_check_options(server, share, path, options)) {
                 DEBUG(4, ("unacceptable options (%s)\n", options));
                 errno = EINVAL + 8195;
+               TALLOC_FREE(frame);
                 return NULL;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return NULL;
+               }
+       }
 
        dir = SMB_MALLOC_P(SMBCFILE);
 
        if (!dir) {
-
                errno = ENOMEM;
+               TALLOC_FREE(frame);
                return NULL;
-
        }
 
        ZERO_STRUCTP(dir);
@@ -2636,7 +2870,6 @@ smbc_opendir_ctx(SMBCCTX *context,
                 struct ip_service *ip_list;
                 struct ip_service server_addr;
                 struct user_auth_info u_info;
-                struct cli_state *cli;
 
                if (share[0] != (char)0 || path[0] != (char)0) {
 
@@ -2645,6 +2878,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                                SAFE_FREE(dir->fname);
                                SAFE_FREE(dir);
                        }
+                       TALLOC_FREE(frame);
                        return NULL;
                }
 
@@ -2653,8 +2887,17 @@ smbc_opendir_ctx(SMBCCTX *context,
                                  ? INT_MAX
                                  : context->options.browse_max_lmb_count);
 
-                pstrcpy(u_info.username, user);
-                pstrcpy(u_info.password, password);
+               memset(&u_info, '\0', sizeof(u_info));
+               u_info.username = talloc_strdup(frame,user);
+               u_info.password = talloc_strdup(frame,password);
+               if (!u_info.username || !u_info.password) {
+                       if (dir) {
+                               SAFE_FREE(dir->fname);
+                               SAFE_FREE(dir);
+                       }
+                       TALLOC_FREE(frame);
+                       return NULL;
+               }
 
                /*
                  * We have server and share and path empty but options
@@ -2666,39 +2909,64 @@ smbc_opendir_ctx(SMBCCTX *context,
                  */
 
                 ip_list = NULL;
-                if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
+                if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
+                                    &count)))
+               {
 
                         SAFE_FREE(ip_list);
 
-                        if (!find_master_ip(workgroup, &server_addr.ip)) {
+                        if (!find_master_ip(workgroup, &server_addr.ss)) {
 
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
                                 errno = ENOENT;
+                               TALLOC_FREE(frame);
                                 return NULL;
                         }
 
-                        ip_list = &server_addr;
+                       ip_list = (struct ip_service *)memdup(
+                               &server_addr, sizeof(server_addr));
+                       if (ip_list == NULL) {
+                               errno = ENOMEM;
+                               TALLOC_FREE(frame);
+                               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);
                         DEBUG(99, ("Found master browser %d of %d: %s\n",
                                    i+1, MAX(count, max_lmb_count),
-                                   inet_ntoa(ip_list[i].ip)));
-                        
-                        cli = get_ipc_connect_master_ip(&ip_list[i],
-                                                        workgroup, &u_info);
-                       /* cli == NULL is the master browser refused to talk or 
+                                   addr));
+
+                        cli = get_ipc_connect_master_ip(talloc_tos(),
+                                                       &ip_list[i],
+                                                        &u_info,
+                                                       &wg_ptr);
+                       /* cli == NULL is the master browser refused to talk or
                           could not be found */
-                       if ( !cli )
+                       if (!cli) {
                                continue;
+                       }
+
+                       workgroup = talloc_strdup(frame, wg_ptr);
+                       server = talloc_strdup(frame, cli->desthost);
 
-                        fstrcpy(server, cli->desthost);
                         cli_shutdown(cli);
 
+                       if (!workgroup || !server) {
+                               errno = ENOMEM;
+                               TALLOC_FREE(frame);
+                               return NULL;
+                       }
+
                         DEBUG(4, ("using workgroup %s %s\n",
                                   workgroup, server));
 
@@ -2708,18 +2976,18 @@ smbc_opendir_ctx(SMBCCTX *context,
                          * already have one, and determine the
                          * workgroups/domains that it knows about.
                          */
-                
-                        srv = smbc_server(context, True, server, "IPC$",
-                                          workgroup, user, password);
+
+                        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,
@@ -2730,7 +2998,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                 }
 
                 SAFE_FREE(ip_list);
-        } else { 
+        } else {
                 /*
                  * Server not an empty string ... Check the rest and see what
                  * gives
@@ -2744,8 +3012,9 @@ smbc_opendir_ctx(SMBCCTX *context,
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
+                               TALLOC_FREE(frame);
                                return NULL;
-       
+
                        }
 
                        /*
@@ -2762,8 +3031,8 @@ smbc_opendir_ctx(SMBCCTX *context,
                          * establish a connection if one does not already
                          * exist.
                          */
-                        srv = smbc_server(context, False, server, "IPC$",
-                                          workgroup, user, password);
+                        srv = smbc_server(frame, context, False, server, "IPC$",
+                                          &workgroup, &user, &password);
 
                         /*
                          * If no existing server and not an IP addr, look for
@@ -2771,8 +3040,8 @@ smbc_opendir_ctx(SMBCCTX *context,
                          */
                        if (!srv &&
                             !is_ipaddress(server) &&
-                           (resolve_name(server, &rem_ip, 0x1d) ||   /* LMB */
-                             resolve_name(server, &rem_ip, 0x1b) )) { /* DMB */
+                           (resolve_name(server, &rem_ss, 0x1d) ||   /* LMB */
+                             resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
 
                                fstring buserver;
 
@@ -2782,7 +3051,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                                 * Get the backup list ...
                                 */
                                if (!name_status_find(server, 0, 0,
-                                                      rem_ip, buserver)) {
+                                                      &rem_ss, buserver)) {
 
                                         DEBUG(0, ("Could not get name of "
                                                   "local/domain master browser "
@@ -2792,6 +3061,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                                                SAFE_FREE(dir);
                                        }
                                        errno = EPERM;
+                                       TALLOC_FREE(frame);
                                        return NULL;
 
                                }
@@ -2800,15 +3070,16 @@ smbc_opendir_ctx(SMBCCTX *context,
                                  * Get a connection to IPC$ on the server if
                                  * we do not already have one
                                  */
-                               srv = smbc_server(context, True,
+                               srv = smbc_server(frame, context, True,
                                                   buserver, "IPC$",
-                                                  workgroup, user, password);
+                                                  &workgroup, &user, &password);
                                if (!srv) {
                                        DEBUG(0, ("got no contact to IPC$\n"));
                                        if (dir) {
                                                SAFE_FREE(dir->fname);
                                                SAFE_FREE(dir);
                                        }
+                                       TALLOC_FREE(frame);
                                        return NULL;
 
                                }
@@ -2824,17 +3095,18 @@ smbc_opendir_ctx(SMBCCTX *context,
                                                SAFE_FREE(dir->fname);
                                                SAFE_FREE(dir);
                                        }
+                                       TALLOC_FREE(frame);
                                        return NULL;
                                }
                        } else if (srv ||
-                                   (resolve_name(server, &rem_ip, 0x20))) {
-                                
+                                   (resolve_name(server, &rem_ss, 0x20))) {
+
                                 /* If we hadn't found the server, get one now */
                                 if (!srv) {
-                                        srv = smbc_server(context, True,
+                                        srv = smbc_server(frame, context, True,
                                                           server, "IPC$",
-                                                          workgroup,
-                                                          user, password);
+                                                          &workgroup,
+                                                          &user, &password);
                                 }
 
                                 if (!srv) {
@@ -2842,6 +3114,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                                                 SAFE_FREE(dir->fname);
                                                 SAFE_FREE(dir);
                                         }
+                                       TALLOC_FREE(frame);
                                         return NULL;
 
                                 }
@@ -2857,24 +3130,26 @@ smbc_opendir_ctx(SMBCCTX *context,
                                             (void *) dir) < 0 &&
                                     cli_RNetShareEnum(
                                             srv->cli,
-                                            list_fn, 
+                                            list_fn,
                                             (void *)dir) < 0) {
-                                                
+
                                         errno = cli_errno(srv->cli);
                                         if (dir) {
                                                 SAFE_FREE(dir->fname);
                                                 SAFE_FREE(dir);
                                         }
+                                       TALLOC_FREE(frame);
                                         return NULL;
 
                                 }
                         } else {
                                 /* Neither the workgroup nor server exists */
-                                errno = ECONNREFUSED;   
+                                errno = ECONNREFUSED;
                                 if (dir) {
                                         SAFE_FREE(dir->fname);
                                         SAFE_FREE(dir);
                                 }
+                               TALLOC_FREE(frame);
                                 return NULL;
                        }
 
@@ -2884,23 +3159,22 @@ smbc_opendir_ctx(SMBCCTX *context,
                          * The server and share are specified ... work from
                          * there ...
                          */
-                       pstring targetpath;
+                       char *targetpath;
                        struct cli_state *targetcli;
 
                        /* We connect to the server and list the directory */
                        dir->dir_type = SMBC_FILE_SHARE;
 
-                       srv = smbc_server(context, True, server, share,
-                                          workgroup, user, password);
+                       srv = smbc_server(frame, context, True, server, share,
+                                          &workgroup, &user, &password);
 
                        if (!srv) {
-
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
+                               TALLOC_FREE(frame);
                                return NULL;
-
                        }
 
                        dir->srv = srv;
@@ -2908,19 +3182,27 @@ smbc_opendir_ctx(SMBCCTX *context,
                        /* Now, list the files ... */
 
                         p = path + strlen(path);
-                       pstrcat(path, "\\*");
+                       path = talloc_asprintf_append(path, "\\*");
+                       if (!path) {
+                               if (dir) {
+                                       SAFE_FREE(dir->fname);
+                                       SAFE_FREE(dir);
+                               }
+                               TALLOC_FREE(frame);
+                               return NULL;
+                       }
 
-                       if (!cli_resolve_path("", srv->cli, path,
-                                              &targetcli, targetpath))
-                       {
+                       if (!cli_resolve_path(frame, "", srv->cli, path,
+                                              &targetcli, &targetpath)) {
                                d_printf("Could not resolve %s\n", path);
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
+                               TALLOC_FREE(frame);
                                return NULL;
                        }
-                       
+
                        if (cli_list(targetcli, targetpath,
                                      aDIR | aSYSTEM | aHIDDEN,
                                      dir_list_fn, (void *)dir) < 0) {
@@ -2957,23 +3239,26 @@ smbc_opendir_ctx(SMBCCTX *context,
                                  */
                                 cb = &context->callbacks;
                                 if (cli_is_error(targetcli) &&
-                                    cb->check_server_fn(context, srv)) {
-
-                                    /* ... then remove it. */
-                                    if (cb->remove_unused_server_fn(context,
-                                                                    srv)) { 
-                                        /*
-                                         * We could not remove the server
-                                         * completely, remove it from the
-                                         * cache so we will not get it
-                                         * again. It will be removed when the
-                                         * last file/dir is closed.
-                                         */
-                                        cb->remove_cached_srv_fn(context, srv);
-                                    }
+                                    (cb->check_server_fn)(context, srv)) {
+
+                                        /* ... then remove it. */
+                                        if ((cb->remove_unused_server_fn)(context,
+                                                                          srv)) { 
+                                                /*
+                                                 * We could not remove the
+                                                 * server completely, remove
+                                                 * it from the cache so we
+                                                 * will not get it again. It
+                                                 * will be removed when the
+                                                 * last file/dir is closed.
+                                                 */
+                                                (cb->remove_cached_srv_fn)(context,
+                                                                           srv);
+                                        }
                                 }
 
                                 errno = saved_errno;
+                               TALLOC_FREE(frame);
                                return NULL;
                        }
                }
@@ -2981,6 +3266,7 @@ smbc_opendir_ctx(SMBCCTX *context,
        }
 
        DLIST_ADD(context->internal->_files, dir);
+       TALLOC_FREE(frame);
        return dir;
 
 }
@@ -2993,20 +3279,19 @@ static int
 smbc_closedir_ctx(SMBCCTX *context,
                   SMBCFILE *dir)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
 
         if (!context || !context->internal ||
            !context->internal->_initialized) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
-
        }
 
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
-
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
-    
        }
 
        smbc_remove_dir(dir); /* Clean it up */
@@ -3019,6 +3304,7 @@ smbc_closedir_ctx(SMBCCTX *context,
                SAFE_FREE(dir);    /* Free the space too */
        }
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -3069,6 +3355,7 @@ smbc_readdir_ctx(SMBCCTX *context,
 {
         int maxlen;
        struct smbc_dirent *dirp, *dirent;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        /* Check that all is ok first ... */
 
@@ -3077,6 +3364,7 @@ smbc_readdir_ctx(SMBCCTX *context,
 
                errno = EINVAL;
                 DEBUG(0, ("Invalid context in smbc_readdir_ctx()\n"));
+               TALLOC_FREE(frame);
                return NULL;
 
        }
@@ -3085,6 +3373,7 @@ smbc_readdir_ctx(SMBCCTX *context,
 
                errno = EBADF;
                 DEBUG(0, ("Invalid dir in smbc_readdir_ctx()\n"));
+               TALLOC_FREE(frame);
                return NULL;
 
        }
@@ -3093,11 +3382,13 @@ smbc_readdir_ctx(SMBCCTX *context,
 
                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;
         }
 
@@ -3105,6 +3396,7 @@ smbc_readdir_ctx(SMBCCTX *context,
         if (!dirent) {
 
                 errno = ENOENT;
+               TALLOC_FREE(frame);
                 return NULL;
 
         }
@@ -3117,6 +3409,7 @@ smbc_readdir_ctx(SMBCCTX *context,
 
         dir->dir_next = dir->dir_next->next;
 
+       TALLOC_FREE(frame);
         return dirp;
 }
 
@@ -3135,6 +3428,7 @@ smbc_getdents_ctx(SMBCCTX *context,
         int maxlen;
        char *ndir = (char *)dirp;
        struct smbc_dir_list *dirlist;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        /* Check that all is ok first ... */
 
@@ -3142,6 +3436,7 @@ smbc_getdents_ctx(SMBCCTX *context,
            !context->internal->_initialized) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3149,6 +3444,7 @@ smbc_getdents_ctx(SMBCCTX *context,
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
 
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
     
        }
@@ -3156,6 +3452,7 @@ smbc_getdents_ctx(SMBCCTX *context,
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
 
                errno = ENOTDIR;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3172,6 +3469,7 @@ smbc_getdents_ctx(SMBCCTX *context,
                if (!dirlist->dirent) {
 
                        errno = ENOENT;  /* Bad error */
+                       TALLOC_FREE(frame);
                        return -1;
 
                }
@@ -3189,12 +3487,14 @@ smbc_getdents_ctx(SMBCCTX *context,
                        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;
 
                        }
@@ -3215,9 +3515,11 @@ smbc_getdents_ctx(SMBCCTX *context,
                dir->dir_next = dirlist = dirlist -> next;
        }
 
+       TALLOC_FREE(frame);
+
        if (rem == count)
                return 0;
-       else 
+       else
                return count - rem;
 
 }
@@ -3231,59 +3533,71 @@ smbc_mkdir_ctx(SMBCCTX *context,
                const char *fname,
                mode_t mode)
 {
-       SMBCSRV *srv;
-       fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-       pstring path, targetpath;
-       struct cli_state *targetcli;
-
-       if (!context || !context->internal || 
-           !context->internal->_initialized) {
+       SMBCSRV *srv = NULL;
+       char *server = NULL;
+        char *share = NULL;
+        char *user = NULL;
+        char *password = NULL;
+        char *workgroup = NULL;
+       char *path = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
+       if (!context || !context->internal ||
+           !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(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
-                return -1;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       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( "", srv->cli, path, &targetcli, targetpath))
-       {
+       if (!cli_resolve_path(frame, "", srv->cli, path,
+                               &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
@@ -3291,10 +3605,12 @@ smbc_mkdir_ctx(SMBCCTX *context,
        if (!cli_mkdir(targetcli, targetpath)) {
 
                errno = smbc_errno(context, targetcli);
+               TALLOC_FREE(frame);
                return -1;
 
        } 
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -3313,7 +3629,6 @@ rmdir_list_fn(const char *mnt,
 {
        if (strncmp(finfo->name, ".", 1) != 0 &&
             strncmp(finfo->name, "..", 2) != 0) {
-                
                smbc_rmdir_dirempty = False;
         }
 }
@@ -3326,61 +3641,71 @@ static int
 smbc_rmdir_ctx(SMBCCTX *context,
                const char *fname)
 {
-       SMBCSRV *srv;
-       fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-       pstring path;
-        pstring targetpath;
-       struct cli_state *targetcli;
-
-       if (!context || !context->internal || 
-           !context->internal->_initialized) {
+       SMBCSRV *srv = NULL;
+       char *server = NULL;
+        char *share = NULL;
+        char *user = NULL;
+        char *password = NULL;
+        char *workgroup = NULL;
+       char *path = NULL;
+        char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
+       if (!context || !context->internal ||
+           !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(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0))
-        {
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
-                return -1;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       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( "", srv->cli, path, &targetcli, targetpath))
-       {
+       if (!cli_resolve_path(frame, "", srv->cli, path,
+                               &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+               TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
@@ -3393,12 +3718,17 @@ smbc_rmdir_ctx(SMBCCTX *context,
                if (errno == EACCES) {  /* Check if the dir empty or not */
 
                         /* Local storage to avoid buffer overflows */
-                       pstring lpath; 
+                       char *lpath;
 
                        smbc_rmdir_dirempty = True;  /* Make this so ... */
 
-                       pstrcpy(lpath, targetpath);
-                       pstrcat(lpath, "\\*");
+                       lpath = talloc_asprintf(frame, "%s\\*",
+                                               targetpath);
+                       if (!lpath) {
+                               errno = ENOMEM;
+                               TALLOC_FREE(frame);
+                               return -1;
+                       }
 
                        if (cli_list(targetcli, lpath,
                                      aDIR | aSYSTEM | aHIDDEN,
@@ -3406,7 +3736,7 @@ smbc_rmdir_ctx(SMBCCTX *context,
 
                                /* Fix errno to ignore latest error ... */
                                DEBUG(5, ("smbc_rmdir: "
-                                          "cli_list returned an error: %d\n", 
+                                          "cli_list returned an error: %d\n",
                                          smbc_errno(context, targetcli)));
                                errno = EACCES;
 
@@ -3419,10 +3749,12 @@ smbc_rmdir_ctx(SMBCCTX *context,
 
                }
 
+               TALLOC_FREE(frame);
                return -1;
 
        } 
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -3435,12 +3767,13 @@ static off_t
 smbc_telldir_ctx(SMBCCTX *context,
                  SMBCFILE *dir)
 {
-       off_t ret_val; /* Squash warnings about cast */
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3448,6 +3781,7 @@ smbc_telldir_ctx(SMBCCTX *context,
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
 
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3455,16 +3789,23 @@ smbc_telldir_ctx(SMBCCTX *context,
        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
         */
-       ret_val = (off_t)(long)dir->dir_next;
-       return ret_val;
-
+       TALLOC_FREE(frame);
+        return (off_t)(long)dir->dir_next->dirent;
 }
 
 /*
@@ -3510,11 +3851,13 @@ smbc_lseekdir_ctx(SMBCCTX *context,
        long int l_offset = offset;  /* Handle problems of size */
        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 ||
            !context->internal->_initialized) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3522,6 +3865,7 @@ smbc_lseekdir_ctx(SMBCCTX *context,
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
 
                errno = ENOTDIR;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3531,24 +3875,30 @@ smbc_lseekdir_ctx(SMBCCTX *context,
        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 = smbc_check_dir_ent(dir->dir_list, dirent)) == NULL) {
-
                errno = EINVAL;   /* Bad entry */
+               TALLOC_FREE(frame);
                return -1;
-
        }
 
        dir->dir_next = list_ent;
 
-       return 0; 
-
+       TALLOC_FREE(frame);
+       return 0;
 }
 
 /*
@@ -3561,18 +3911,14 @@ smbc_fstatdir_ctx(SMBCCTX *context,
                   struct stat *st)
 {
 
-       if (!context || !context->internal || 
+       if (!context || !context->internal ||
            !context->internal->_initialized) {
-
                errno = EINVAL;
                return -1;
-
        }
 
        /* No code yet ... */
-
        return 0;
-
 }
 
 static int
@@ -3580,50 +3926,60 @@ smbc_chmod_ctx(SMBCCTX *context,
                const char *fname,
                mode_t newmode)
 {
-        SMBCSRV *srv;
-       fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-       pstring path;
+        SMBCSRV *srv = NULL;
+       char *server = NULL;
+        char *share = NULL;
+        char *user = NULL;
+        char *password = NULL;
+        char *workgroup = NULL;
+       char *path = NULL;
        uint16 mode;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !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));
 
-       if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
-                return -1;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       srv = smbc_server(frame, context, True,
+                          server, share, &workgroup, &user, &password);
 
        if (!srv) {
+               TALLOC_FREE(frame);
                return -1;  /* errno set by smbc_server */
        }
 
@@ -3636,9 +3992,11 @@ smbc_chmod_ctx(SMBCCTX *context,
 
        if (!cli_setatr(srv->cli, path, mode, 0)) {
                errno = smbc_errno(context, srv->cli);
+               TALLOC_FREE(frame);
                return -1;
        }
-       
+
+       TALLOC_FREE(frame);
         return 0;
 }
 
@@ -3647,31 +4005,30 @@ smbc_utimes_ctx(SMBCCTX *context,
                 const char *fname,
                 struct timeval *tbuf)
 {
-        SMBCSRV *srv;
-       fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-       pstring path;
+        SMBCSRV *srv = NULL;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
         time_t access_time;
         time_t write_time;
+       TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !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 {
@@ -3679,8 +4036,7 @@ smbc_utimes_ctx(SMBCCTX *context,
                 write_time = tbuf[1].tv_sec;
         }
 
-        if (DEBUGLVL(4)) 
-        {
+        if (DEBUGLVL(4)) {
                 char *p;
                 char atimebuf[32];
                 char mtimebuf[32];
@@ -3701,62 +4057,137 @@ smbc_utimes_ctx(SMBCCTX *context,
                         fname, atimebuf, mtimebuf);
         }
 
-       if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
-                return -1;
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       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;
 }
 
 
-/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
-   However NT4 gives a "The information may have been modified by a
-   computer running Windows NT 5.0" if denied ACEs do not appear before
-   allowed ACEs. */
+/*
+ * Sort ACEs according to the documentation at
+ * http://support.microsoft.com/kb/269175, at least as far as it defines the
+ * order.
+ */
 
 static int
 ace_compare(SEC_ACE *ace1,
             SEC_ACE *ace2)
 {
-       if (sec_ace_equal(ace1, ace2)) 
+        bool b1;
+        bool b2;
+
+        /* If the ACEs are equal, we have nothing more to do. */
+        if (sec_ace_equal(ace1, ace2)) {
                return 0;
+        }
+
+        /* Inherited follow non-inherited */
+        b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
+        b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
+        if (b1 != b2) {
+                return (b1 ? 1 : -1);
+        }
+
+        /*
+         * What shall we do with AUDITs and ALARMs?  It's undefined.  We'll
+         * sort them after DENY and ALLOW.
+         */
+        b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
+              ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
+              ace1->type != SEC_ACE_TYPE_ACCESS_DENIED &&
+              ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+        b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
+              ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
+              ace2->type != SEC_ACE_TYPE_ACCESS_DENIED &&
+              ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+        if (b1 != b2) {
+                return (b1 ? 1 : -1);
+        }
+
+        /* Allowed ACEs follow denied ACEs */
+        b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
+              ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
+        b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
+              ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
+        if (b1 != b2) {
+                return (b1 ? 1 : -1);
+        }
+
+        /*
+         * ACEs applying to an entity's object follow those applying to the
+         * entity itself
+         */
+        b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+              ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+        b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+              ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+        if (b1 != b2) {
+                return (b1 ? 1 : -1);
+        }
+
+        /*
+         * If we get this far, the ACEs are similar as far as the
+         * characteristics we typically care about (those defined by the
+         * referenced MS document).  We'll now sort by characteristics that
+         * just seems reasonable.
+         */
 
-       if (ace1->type != ace2->type) 
+       if (ace1->type != ace2->type) {
                return ace2->type - ace1->type;
+        }
 
-       if (sid_compare(&ace1->trustee, &ace2->trustee)) 
+       if (sid_compare(&ace1->trustee, &ace2->trustee)) {
                return sid_compare(&ace1->trustee, &ace2->trustee);
+        }
 
-       if (ace1->flags != ace2->flags) 
+       if (ace1->flags != ace2->flags) {
                return ace1->flags - ace2->flags;
+        }
 
-       if (ace1->access_mask != ace2->access_mask) 
+       if (ace1->access_mask != ace2->access_mask) {
                return ace1->access_mask - ace2->access_mask;
+        }
 
-       if (ace1->size != ace2->size) 
+       if (ace1->size != ace2->size) {
                return ace1->size - ace2->size;
+        }
 
        return memcmp(ace1, ace2, sizeof(SEC_ACE));
 }
@@ -3789,32 +4220,38 @@ static void
 convert_sid_to_string(struct cli_state *ipc_cli,
                       POLICY_HND *pol,
                       fstring str,
-                      BOOL numeric,
+                      bool numeric,
                       DOM_SID *sid)
 {
        char **domains = NULL;
        char **names = NULL;
        enum lsa_SidType *types = NULL;
        struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
-       sid_to_string(str, sid);
+       TALLOC_CTX *ctx;
+
+       sid_to_fstring(str, sid);
 
        if (numeric) {
                return;     /* no lookup desired */
        }
-       
+
        if (!pipe_hnd) {
                return;
        }
+
        /* Ask LSA to convert the sid to a name */
 
-       if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ipc_cli->mem_ctx,  
-                                                pol, 1, sid, &domains, 
+       ctx = talloc_stackframe();
+
+       if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx,
+                                                pol, 1, sid, &domains,
                                                 &names, &types)) ||
            !domains || !domains[0] || !names || !names[0]) {
+               TALLOC_FREE(ctx);
                return;
        }
 
+       TALLOC_FREE(ctx);
        /* Converted OK */
 
        slprintf(str, sizeof(fstring) - 1, "%s%s%s",
@@ -3823,16 +4260,17 @@ convert_sid_to_string(struct cli_state *ipc_cli,
 }
 
 /* convert a string to a SID, either numeric or username/group */
-static BOOL
+static bool
 convert_string_to_sid(struct cli_state *ipc_cli,
                       POLICY_HND *pol,
-                      BOOL numeric,
+                      bool numeric,
                       DOM_SID *sid,
                       const char *str)
 {
        enum lsa_SidType *types = NULL;
        DOM_SID *sids = NULL;
-       BOOL result = True;
+       bool result = True;
+       TALLOC_CTX *ctx = NULL;
        struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
 
        if (!pipe_hnd) {
@@ -3848,9 +4286,10 @@ convert_string_to_sid(struct cli_state *ipc_cli,
                 goto done;
         }
 
-       if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx, 
-                                                 pol, 1, &str, NULL, 1, &sids, 
-                                                 &types))) {
+       ctx = talloc_stackframe();
+       if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx,
+                                         pol, 1, &str, NULL, 1, &sids,
+                                         &types))) {
                result = False;
                goto done;
        }
@@ -3858,21 +4297,22 @@ convert_string_to_sid(struct cli_state *ipc_cli,
        sid_copy(sid, &sids[0]);
  done:
 
+       TALLOC_FREE(ctx);
        return result;
 }
 
 
 /* parse an ACE in the same format as print_ace() */
-static BOOL
+static bool
 parse_ace(struct cli_state *ipc_cli,
           POLICY_HND *pol,
           SEC_ACE *ace,
-          BOOL numeric,
+          bool numeric,
           char *str)
 {
        char *p;
        const char *cp;
-       fstring tok;
+       char *tok;
        unsigned int atype;
         unsigned int aflags;
         unsigned int amask;
@@ -3883,6 +4323,7 @@ parse_ace(struct cli_state *ipc_cli,
                 const char *perm;
                 uint32 mask;
         };
+       TALLOC_CTX *frame = talloc_stackframe();
 
         /* These values discovered by inspection */
         static const struct perm_value special_values[] = {
@@ -3905,7 +4346,10 @@ parse_ace(struct cli_state *ipc_cli,
 
        ZERO_STRUCTP(ace);
        p = strchr_m(str,':');
-       if (!p) return False;
+       if (!p) {
+               TALLOC_FREE(frame);
+               return False;
+       }
        *p = '\0';
        p++;
        /* Try to parse numeric form */
@@ -3918,12 +4362,14 @@ parse_ace(struct cli_state *ipc_cli,
        /* Try to parse text form */
 
        if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
-               return False;
+               TALLOC_FREE(frame);
+               return false;
        }
 
        cp = p;
-       if (!next_token(&cp, tok, "/", sizeof(fstring))) {
-               return False;
+       if (!next_token_talloc(frame, &cp, &tok, "/")) {
+               TALLOC_FREE(frame);
+               return false;
        }
 
        if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
@@ -3931,23 +4377,27 @@ parse_ace(struct cli_state *ipc_cli,
        } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) {
                atype = SEC_ACE_TYPE_ACCESS_DENIED;
        } else {
-               return False;
+               TALLOC_FREE(frame);
+               return false;
        }
 
        /* Only numeric form accepted for flags at present */
 
-       if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
+       if (!(next_token_talloc(frame, &cp, &tok, "/") &&
              sscanf(tok, "%i", &aflags))) {
-               return False;
+               TALLOC_FREE(frame);
+               return false;
        }
 
-       if (!next_token(&cp, tok, "/", sizeof(fstring))) {
-               return False;
+       if (!next_token_talloc(frame, &cp, &tok, "/")) {
+               TALLOC_FREE(frame);
+               return false;
        }
 
        if (strncmp(tok, "0x", 2) == 0) {
                if (sscanf(tok, "%i", &amask) != 1) {
-                       return False;
+                       TALLOC_FREE(frame);
+                       return false;
                }
                goto done;
        }
@@ -3962,7 +4412,7 @@ parse_ace(struct cli_state *ipc_cli,
        p = tok;
 
        while(*p) {
-               BOOL found = False;
+               bool found = False;
 
                for (v = special_values; v->perm; v++) {
                        if (v->perm[0] == *p) {
@@ -3971,22 +4421,27 @@ parse_ace(struct cli_state *ipc_cli,
                        }
                }
 
-               if (!found) return False;
+               if (!found) {
+                       TALLOC_FREE(frame);
+                       return false;
+               }
                p++;
        }
 
        if (*p) {
-               return False;
+               TALLOC_FREE(frame);
+               return false;
        }
 
  done:
        mask = amask;
        init_sec_ace(ace, &sid, atype, mask, aflags);
-       return True;
+       TALLOC_FREE(frame);
+       return true;
 }
 
 /* add an ACE to a list of ACEs in a SEC_ACL */
-static BOOL
+static bool
 add_ace(SEC_ACL **the_acl,
         SEC_ACE *ace,
         TALLOC_CTX *ctx)
@@ -4017,19 +4472,19 @@ static SEC_DESC *
 sec_desc_parse(TALLOC_CTX *ctx,
                struct cli_state *ipc_cli,
                POLICY_HND *pol,
-               BOOL numeric,
+               bool numeric,
                char *str)
 {
        const char *p = str;
-       fstring tok;
+       char *tok;
        SEC_DESC *ret = NULL;
        size_t sd_size;
-       DOM_SID *grp_sid=NULL;
+       DOM_SID *group_sid=NULL;
         DOM_SID *owner_sid=NULL;
        SEC_ACL *dacl=NULL;
        int revision=1;
 
-       while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
+       while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
 
                if (StrnCaseCmp(tok,"REVISION:", 9) == 0) {
                        revision = strtol(tok+9, NULL, 16);
@@ -4069,15 +4524,15 @@ sec_desc_parse(TALLOC_CTX *ctx,
                }
 
                if (StrnCaseCmp(tok,"GROUP:", 6) == 0) {
-                       if (grp_sid) {
+                       if (group_sid) {
                                DEBUG(5, ("GROUP specified more than once!\n"));
                                goto done;
                        }
-                       grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
-                       if (!grp_sid ||
+                       group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+                       if (!group_sid ||
                            !convert_string_to_sid(ipc_cli, pol,
                                                    numeric,
-                                                   grp_sid, tok+6)) {
+                                                   group_sid, tok+6)) {
                                DEBUG(5, ("Failed to parse group sid\n"));
                                goto done;
                        }
@@ -4085,15 +4540,15 @@ sec_desc_parse(TALLOC_CTX *ctx,
                }
 
                if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) {
-                       if (grp_sid) {
+                       if (group_sid) {
                                DEBUG(5, ("GROUP specified more than once!\n"));
                                goto done;
                        }
-                       grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
-                       if (!grp_sid ||
+                       group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+                       if (!group_sid ||
                            !convert_string_to_sid(ipc_cli, pol,
                                                    False,
-                                                   grp_sid, tok+6)) {
+                                                   group_sid, tok+6)) {
                                DEBUG(5, ("Failed to parse group sid\n"));
                                goto done;
                        }
@@ -4131,10 +4586,10 @@ sec_desc_parse(TALLOC_CTX *ctx,
        }
 
        ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, 
-                           owner_sid, grp_sid, NULL, dacl, &sd_size);
+                           owner_sid, group_sid, NULL, dacl, &sd_size);
 
   done:
-       SAFE_FREE(grp_sid);
+       SAFE_FREE(group_sid);
        SAFE_FREE(owner_sid);
 
        return ret;
@@ -4156,7 +4611,7 @@ dos_attr_query(SMBCCTX *context,
         uint16 mode = 0;
        SMB_INO_T inode = 0;
         DOS_ATTR_DESC *ret;
-    
+
         ret = TALLOC_P(ctx, DOS_ATTR_DESC);
         if (!ret) {
                 errno = ENOMEM;
@@ -4165,19 +4620,17 @@ dos_attr_query(SMBCCTX *context,
 
         /* Obtain the DOS attributes */
         if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename),
-                         &mode, &size, 
+                         &mode, &size,
                          &create_time_ts,
                          &access_time_ts,
                          &write_time_ts,
-                         &change_time_ts, 
+                         &change_time_ts,
                          &inode)) {
-        
                 errno = smbc_errno(context, srv->cli);
                 DEBUG(5, ("dos_attr_query Failed to query old attributes\n"));
                 return NULL;
-        
         }
-                
+
         ret->mode = mode;
         ret->size = size;
         ret->create_time = convert_timespec_to_time_t(create_time_ts);
@@ -4199,7 +4652,8 @@ dos_attr_parse(SMBCCTX *context,
 {
         int n;
         const char *p = str;
-       fstring tok;
+       char *tok = NULL;
+       TALLOC_CTX *frame = NULL;
         struct {
                 const char * create_time_attr;
                 const char * access_time_attr;
@@ -4232,10 +4686,18 @@ dos_attr_parse(SMBCCTX *context,
                 }
         }
 
-       while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
-
+       frame = talloc_stackframe();
+       while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) {
                if (StrnCaseCmp(tok, "MODE:", 5) == 0) {
-                       dad->mode = strtol(tok+5, NULL, 16);
+                        long request = strtol(tok+5, NULL, 16);
+                        if (request == 0) {
+                                dad->mode = (request |
+                                             (IS_DOS_DIR(dad->mode)
+                                              ? FILE_ATTRIBUTE_DIRECTORY
+                                              : FILE_ATTRIBUTE_NORMAL));
+                        } else {
+                                dad->mode = request;
+                        }
                        continue;
                }
 
@@ -4277,9 +4739,10 @@ dos_attr_parse(SMBCCTX *context,
                        continue;
                }
        }
+       TALLOC_FREE(frame);
 }
 
-/***************************************************** 
+/*****************************************************
  Retrieve the acls for a file.
 *******************************************************/
 
@@ -4297,25 +4760,25 @@ cacl_get(SMBCCTX *context,
        uint32 i;
         int n = 0;
         int n_used;
-        BOOL all;
-        BOOL all_nt;
-        BOOL all_nt_acls;
-        BOOL all_dos;
-        BOOL some_nt;
-        BOOL some_dos;
-        BOOL exclude_nt_revision = False;
-        BOOL exclude_nt_owner = False;
-        BOOL exclude_nt_group = False;
-        BOOL exclude_nt_acl = False;
-        BOOL exclude_dos_mode = False;
-        BOOL exclude_dos_size = False;
-        BOOL exclude_dos_create_time = False;
-        BOOL exclude_dos_access_time = False;
-        BOOL exclude_dos_write_time = False;
-        BOOL exclude_dos_change_time = False;
-        BOOL exclude_dos_inode = False;
-        BOOL numeric = True;
-        BOOL determine_size = (bufsize == 0);
+        bool all;
+        bool all_nt;
+        bool all_nt_acls;
+        bool all_dos;
+        bool some_nt;
+        bool some_dos;
+        bool exclude_nt_revision = False;
+        bool exclude_nt_owner = False;
+        bool exclude_nt_group = False;
+        bool exclude_nt_acl = False;
+        bool exclude_dos_mode = False;
+        bool exclude_dos_size = False;
+        bool exclude_dos_create_time = False;
+        bool exclude_dos_access_time = False;
+        bool exclude_dos_write_time = False;
+        bool exclude_dos_change_time = False;
+        bool exclude_dos_inode = False;
+        bool numeric = True;
+        bool determine_size = (bufsize == 0);
        int fnum = -1;
        SEC_DESC *sd;
        fstring sidstr;
@@ -4519,7 +4982,7 @@ cacl_get(SMBCCTX *context,
                                                      sd->revision);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4527,6 +4990,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_nt_owner) {
@@ -4574,6 +5038,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_nt_group) {
@@ -4619,6 +5084,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_nt_acl) {
@@ -4709,6 +5175,7 @@ cacl_get(SMBCCTX *context,
                                 buf += n;
                                 n_used += n;
                                 bufsize -= n;
+                                n = 0;
                         }
                 }
 
@@ -4727,10 +5194,10 @@ cacl_get(SMBCCTX *context,
                                  &write_time_ts,
                                  &change_time_ts,
                                  &ino)) {
-                        
+
                         errno = smbc_errno(context, srv->cli);
                         return -1;
-                        
+
                 }
 
                 create_time = convert_timespec_to_time_t(create_time_ts);
@@ -4775,7 +5242,7 @@ cacl_get(SMBCCTX *context,
                                                      "0x%x", mode);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4783,6 +5250,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_size) {
@@ -4819,7 +5287,7 @@ cacl_get(SMBCCTX *context,
                                                      (double)size);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4827,6 +5295,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_create_time &&
@@ -4861,7 +5330,7 @@ cacl_get(SMBCCTX *context,
                                                      "%lu", create_time);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4869,6 +5338,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_access_time) {
@@ -4902,7 +5372,7 @@ cacl_get(SMBCCTX *context,
                                                      "%lu", access_time);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4910,6 +5380,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_write_time) {
@@ -4943,7 +5414,7 @@ cacl_get(SMBCCTX *context,
                                                      "%lu", write_time);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4951,6 +5422,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_change_time) {
@@ -4984,7 +5456,7 @@ cacl_get(SMBCCTX *context,
                                                      "%lu", change_time);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4992,6 +5464,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_inode) {
@@ -5028,7 +5501,7 @@ cacl_get(SMBCCTX *context,
                                                      (double) ino);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -5036,6 +5509,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 /* Restore name pointer to its original value */
@@ -5050,8 +5524,7 @@ cacl_get(SMBCCTX *context,
        return n_used;
 }
 
-
-/***************************************************** 
+/*****************************************************
 set the ACLs on a file given an ascii description
 *******************************************************/
 static int
@@ -5068,13 +5541,13 @@ cacl_set(TALLOC_CTX *ctx,
         int err = 0;
        SEC_DESC *sd = NULL, *old;
         SEC_ACL *dacl = NULL;
-       DOM_SID *owner_sid = NULL; 
-       DOM_SID *grp_sid = NULL;
+       DOM_SID *owner_sid = NULL;
+       DOM_SID *group_sid = NULL;
        uint32 i, j;
        size_t sd_size;
        int ret = 0;
         char *p;
-        BOOL numeric = True;
+        bool numeric = True;
 
         /* the_acl will be null for REMOVE_ALL operations */
         if (the_acl) {
@@ -5130,15 +5603,12 @@ cacl_set(TALLOC_CTX *ctx,
        switch (mode) {
        case SMBC_XATTR_MODE_REMOVE_ALL:
                 old->dacl->num_aces = 0;
-                SAFE_FREE(old->dacl->aces);
-                SAFE_FREE(old->dacl);
-                old->dacl = NULL;
                 dacl = old->dacl;
                 break;
 
         case SMBC_XATTR_MODE_REMOVE:
                for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
-                       BOOL found = False;
+                       bool found = False;
 
                        for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
                                 if (sec_ace_equal(&sd->dacl->aces[i],
@@ -5149,11 +5619,6 @@ cacl_set(TALLOC_CTX *ctx,
                                                         old->dacl->aces[k+1];
                                        }
                                        old->dacl->num_aces--;
-                                       if (old->dacl->num_aces == 0) {
-                                               SAFE_FREE(old->dacl->aces);
-                                               SAFE_FREE(old->dacl);
-                                               old->dacl = NULL;
-                                       }
                                        found = True;
                                         dacl = old->dacl;
                                        break;
@@ -5170,7 +5635,7 @@ cacl_set(TALLOC_CTX *ctx,
 
        case SMBC_XATTR_MODE_ADD:
                for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
-                       BOOL found = False;
+                       bool found = False;
 
                        for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
                                if (sid_equal(&sd->dacl->aces[i].trustee,
@@ -5191,7 +5656,7 @@ cacl_set(TALLOC_CTX *ctx,
                                 ret = -1;
                                 goto failed;
                        }
-                        
+
                         for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
                                 add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
                         }
@@ -5202,7 +5667,7 @@ cacl_set(TALLOC_CTX *ctx,
        case SMBC_XATTR_MODE_SET:
                old = sd;
                 owner_sid = old->owner_sid;
-                grp_sid = old->group_sid;
+                group_sid = old->group_sid;
                 dacl = old->dacl;
                break;
 
@@ -5211,7 +5676,7 @@ cacl_set(TALLOC_CTX *ctx,
                 break;
 
         case SMBC_XATTR_MODE_CHGRP:
-                grp_sid = sd->group_sid;
+                group_sid = sd->group_sid;
                 break;
        }
 
@@ -5219,8 +5684,8 @@ cacl_set(TALLOC_CTX *ctx,
        sort_acl(old->dacl);
 
        /* Create new security descriptor and set it */
-       sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, 
-                          owner_sid, grp_sid, NULL, dacl, &sd_size);
+       sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE,
+                          owner_sid, group_sid, NULL, dacl, &sd_size);
 
        fnum = cli_nt_create(cli, filename,
                              WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS);
@@ -5245,7 +5710,7 @@ cacl_set(TALLOC_CTX *ctx,
         if (err != 0) {
                 errno = err;
         }
-        
+
        return ret;
 }
 
@@ -5260,78 +5725,79 @@ smbc_setxattr_ctx(SMBCCTX *context,
 {
         int ret;
         int ret2;
-        SMBCSRV *srv;
-        SMBCSRV *ipc_srv;
-       fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-       pstring path;
-        TALLOC_CTX *ctx;
-        POLICY_HND pol;
-        DOS_ATTR_DESC *dad;
+        SMBCSRV *srv = NULL;
+        SMBCSRV *ipc_srv = NULL;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
+        DOS_ATTR_DESC *dad = NULL;
         struct {
                 const char * create_time_attr;
                 const char * access_time_attr;
                 const char * write_time_attr;
                 const char * change_time_attr;
         } attr_strings;
+        TALLOC_CTX *frame = talloc_stackframe();
 
        if (!context || !context->internal ||
            !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_setxattr(%s, %s, %.*s)\n",
                   fname, name, (int) size, (const char*)value));
 
-       if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
-                return -1;
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-       if (user[0] == (char)0) fstrcpy(user, context->user);
+       if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-       srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+       srv = smbc_server(frame, context, True,
+                          server, share, &workgroup, &user, &password);
        if (!srv) {
+               TALLOC_FREE(frame);
                return -1;  /* errno set by smbc_server */
        }
 
         if (! srv->no_nt_session) {
-                ipc_srv = smbc_attr_server(context, server, share,
-                                           workgroup, user, password,
-                                           &pol);
+                ipc_srv = smbc_attr_server(frame, context, server, share,
+                                           &workgroup, &user, &password);
                 if (! ipc_srv) {
                         srv->no_nt_session = True;
                 }
         } else {
                 ipc_srv = NULL;
         }
-        
-        ctx = talloc_init("smbc_setxattr");
-        if (!ctx) {
-                errno = ENOMEM;
-                return -1;
-        }
 
         /*
          * Are they asking to set the entire set of known attributes?
@@ -5340,17 +5806,18 @@ smbc_setxattr_ctx(SMBCCTX *context,
             StrCaseCmp(name, "system.*+") == 0) {
                 /* Yup. */
                 char *namevalue =
-                        talloc_asprintf(ctx, "%s:%s",
+                        talloc_asprintf(talloc_tos(), "%s:%s",
                                         name+7, (const char *) value);
                 if (! namevalue) {
                         errno = ENOMEM;
                         ret = -1;
+                       TALLOC_FREE(frame);
                         return -1;
                 }
 
                 if (ipc_srv) {
-                        ret = cacl_set(ctx, srv->cli,
-                                       ipc_srv->cli, &pol, path,
+                        ret = cacl_set(talloc_tos(), srv->cli,
+                                       ipc_srv->cli, &ipc_srv->pol, path,
                                        namevalue,
                                        (*namevalue == '*'
                                         ? SMBC_XATTR_MODE_SET
@@ -5361,7 +5828,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
                 }
 
                 /* get a DOS Attribute Descriptor with current attributes */
-                dad = dos_attr_query(context, ctx, path, srv);
+                dad = dos_attr_query(context, talloc_tos(), path, srv);
                 if (dad) {
                         /* Overwrite old with new, using what was provided */
                         dos_attr_parse(context, dad, srv, namevalue);
@@ -5387,7 +5854,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
                         ret = 0;
                 }
 
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5403,7 +5870,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
 
                 /* Yup. */
                 char *namevalue =
-                        talloc_asprintf(ctx, "%s:%s",
+                        talloc_asprintf(talloc_tos(), "%s:%s",
                                         name+19, (const char *) value);
 
                 if (! ipc_srv) {
@@ -5413,15 +5880,15 @@ smbc_setxattr_ctx(SMBCCTX *context,
                         errno = ENOMEM;
                         ret = -1;
                 } else {
-                        ret = cacl_set(ctx, srv->cli,
-                                       ipc_srv->cli, &pol, path,
+                        ret = cacl_set(talloc_tos(), srv->cli,
+                                       ipc_srv->cli, &ipc_srv->pol, path,
                                        namevalue,
                                        (*namevalue == '*'
                                         ? SMBC_XATTR_MODE_SET
                                         : SMBC_XATTR_MODE_ADD),
                                        flags);
                 }
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5433,22 +5900,21 @@ smbc_setxattr_ctx(SMBCCTX *context,
 
                 /* Yup. */
                 char *namevalue =
-                        talloc_asprintf(ctx, "%s:%s",
+                        talloc_asprintf(talloc_tos(), "%s:%s",
                                         name+19, (const char *) value);
 
                 if (! ipc_srv) {
-                        
                         ret = -1; /* errno set by smbc_server() */
                 }
                 else if (! namevalue) {
                         errno = ENOMEM;
                         ret = -1;
                 } else {
-                        ret = cacl_set(ctx, srv->cli,
-                                       ipc_srv->cli, &pol, path,
+                        ret = cacl_set(talloc_tos(), srv->cli,
+                                       ipc_srv->cli, &ipc_srv->pol, path,
                                        namevalue, SMBC_XATTR_MODE_CHOWN, 0);
                 }
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5460,7 +5926,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
 
                 /* Yup. */
                 char *namevalue =
-                        talloc_asprintf(ctx, "%s:%s",
+                        talloc_asprintf(talloc_tos(), "%s:%s",
                                         name+19, (const char *) value);
 
                 if (! ipc_srv) {
@@ -5471,11 +5937,11 @@ smbc_setxattr_ctx(SMBCCTX *context,
                         errno = ENOMEM;
                         ret = -1;
                 } else {
-                        ret = cacl_set(ctx, srv->cli,
-                                       ipc_srv->cli, &pol, path,
-                                       namevalue, SMBC_XATTR_MODE_CHOWN, 0);
+                        ret = cacl_set(talloc_tos(), srv->cli,
+                                       ipc_srv->cli, &ipc_srv->pol, path,
+                                       namevalue, SMBC_XATTR_MODE_CHGRP, 0);
                 }
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5506,10 +5972,10 @@ smbc_setxattr_ctx(SMBCCTX *context,
             StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
 
                 /* get a DOS Attribute Descriptor with current attributes */
-                dad = dos_attr_query(context, ctx, path, srv);
+                dad = dos_attr_query(context, talloc_tos(), path, srv);
                 if (dad) {
                         char *namevalue =
-                                talloc_asprintf(ctx, "%s:%s",
+                                talloc_asprintf(talloc_tos(), "%s:%s",
                                                 name+16, (const char *) value);
                         if (! namevalue) {
                                 errno = ENOMEM;
@@ -5537,13 +6003,13 @@ smbc_setxattr_ctx(SMBCCTX *context,
                         ret = -1;
                 }
 
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
         /* Unsupported attribute name */
-        talloc_destroy(ctx);
         errno = EINVAL;
+       TALLOC_FREE(frame);
         return -1;
 }
 
@@ -5555,77 +6021,77 @@ smbc_getxattr_ctx(SMBCCTX *context,
                   size_t size)
 {
         int ret;
-        SMBCSRV *srv;
-        SMBCSRV *ipc_srv;
-        fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-        pstring path;
-        TALLOC_CTX *ctx;
-        POLICY_HND pol;
+        SMBCSRV *srv = NULL;
+        SMBCSRV *ipc_srv = NULL;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
         struct {
                 const char * create_time_attr;
                 const char * access_time_attr;
                 const char * write_time_attr;
                 const char * change_time_attr;
         } attr_strings;
-
+       TALLOC_CTX *frame = talloc_stackframe();
 
         if (!context || !context->internal ||
             !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_getxattr(%s, %s)\n", fname, name));
 
-        if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
-                return -1;
+        if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-        if (user[0] == (char)0) fstrcpy(user, context->user);
+        if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-        srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+        srv = smbc_server(frame, context, True,
+                          server, share, &workgroup, &user, &password);
         if (!srv) {
+               TALLOC_FREE(frame);
                 return -1;  /* errno set by smbc_server */
         }
 
         if (! srv->no_nt_session) {
-                ipc_srv = smbc_attr_server(context, server, share,
-                                           workgroup, user, password,
-                                           &pol);
+                ipc_srv = smbc_attr_server(frame, context, server, share,
+                                           &workgroup, &user, &password);
                 if (! ipc_srv) {
                         srv->no_nt_session = True;
                 }
         } else {
                 ipc_srv = NULL;
         }
-        
-        ctx = talloc_init("smbc:getxattr");
-        if (!ctx) {
-                errno = ENOMEM;
-                return -1;
-        }
 
         /* Determine whether to use old-style or new-style attribute names */
         if (context->internal->_full_time_names) {
@@ -5670,21 +6136,21 @@ smbc_getxattr_ctx(SMBCCTX *context,
             StrCaseCmp(name, "system.dos_attr.inode") == 0) {
 
                 /* Yup. */
-                ret = cacl_get(context, ctx, srv,
+                ret = cacl_get(context, talloc_tos(), srv,
                                ipc_srv == NULL ? NULL : ipc_srv->cli, 
-                               &pol, path,
+                               &ipc_srv->pol, path,
                                CONST_DISCARD(char *, name),
                                CONST_DISCARD(char *, value), size);
                 if (ret < 0 && errno == 0) {
                         errno = smbc_errno(context, srv->cli);
                 }
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
         /* Unsupported attribute name */
-        talloc_destroy(ctx);
         errno = EINVAL;
+       TALLOC_FREE(frame);
         return -1;
 }
 
@@ -5695,84 +6161,86 @@ smbc_removexattr_ctx(SMBCCTX *context,
                      const char *name)
 {
         int ret;
-        SMBCSRV *srv;
-        SMBCSRV *ipc_srv;
-        fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-        pstring path;
-        TALLOC_CTX *ctx;
-        POLICY_HND pol;
+        SMBCSRV *srv = NULL;
+        SMBCSRV *ipc_srv = NULL;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
         if (!context || !context->internal ||
             !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_removexattr(%s, %s)\n", fname, name));
 
-        if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
-                return -1;
+       if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-        if (user[0] == (char)0) fstrcpy(user, context->user);
+        if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-        srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+        srv = smbc_server(frame, context, True,
+                          server, share, &workgroup, &user, &password);
         if (!srv) {
+               TALLOC_FREE(frame);
                 return -1;  /* errno set by smbc_server */
         }
 
         if (! srv->no_nt_session) {
-                ipc_srv = smbc_attr_server(context, server, share,
-                                           workgroup, user, password,
-                                           &pol);
+                ipc_srv = smbc_attr_server(frame, context, server, share,
+                                           &workgroup, &user, &password);
                 if (! ipc_srv) {
                         srv->no_nt_session = True;
                 }
         } else {
                 ipc_srv = NULL;
         }
-        
+
         if (! ipc_srv) {
+               TALLOC_FREE(frame);
                 return -1; /* errno set by smbc_attr_server */
         }
 
-        ctx = talloc_init("smbc_removexattr");
-        if (!ctx) {
-                errno = ENOMEM;
-                return -1;
-        }
-
         /* Are they asking to set the entire ACL? */
         if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
             StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) {
 
                 /* Yup. */
-                ret = cacl_set(ctx, srv->cli,
-                               ipc_srv->cli, &pol, path,
+                ret = cacl_set(talloc_tos(), srv->cli,
+                               ipc_srv->cli, &ipc_srv->pol, path,
                                NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5789,16 +6257,16 @@ smbc_removexattr_ctx(SMBCCTX *context,
             StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
 
                 /* Yup. */
-                ret = cacl_set(ctx, srv->cli,
-                               ipc_srv->cli, &pol, path,
+                ret = cacl_set(talloc_tos(), srv->cli,
+                               ipc_srv->cli, &ipc_srv->pol, path,
                                name + 19, SMBC_XATTR_MODE_REMOVE, 0);
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
         /* Unsupported attribute name */
-        talloc_destroy(ctx);
         errno = EINVAL;
+       TALLOC_FREE(frame);
         return -1;
 }
 
@@ -5813,6 +6281,7 @@ smbc_listxattr_ctx(SMBCCTX *context,
          * the complete set of attribute names, always, rather than only those
          * attribute names which actually exist for a file.  Hmmm...
          */
+        size_t retsize;
         const char supported_old[] =
                 "system.*\0"
                 "system.*+\0"
@@ -5856,22 +6325,24 @@ smbc_listxattr_ctx(SMBCCTX *context,
 
         if (context->internal->_full_time_names) {
                 supported = supported_new;
+                retsize = sizeof(supported_new);
         } else {
                 supported = supported_old;
+                retsize = sizeof(supported_old);
         }
 
         if (size == 0) {
-                return sizeof(supported);
+                return retsize;
         }
 
-        if (sizeof(supported) > size) {
+        if (retsize > size) {
                 errno = ERANGE;
                 return -1;
         }
 
         /* this can't be strcpy() because there are embedded null characters */
-        memcpy(list, supported, sizeof(supported));
-        return sizeof(supported);
+        memcpy(list, supported, retsize);
+        return retsize;
 }
 
 
@@ -5883,45 +6354,47 @@ static SMBCFILE *
 smbc_open_print_job_ctx(SMBCCTX *context,
                         const char *fname)
 {
-        fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        pstring path;
-        
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *path = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
+
         if (!context || !context->internal ||
             !context->internal->_initialized) {
-
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return NULL;
-    
         }
 
         if (!fname) {
-
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return NULL;
-
         }
-  
+
         DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname));
 
-        if (smbc_parse_path(context, fname,
-                            NULL, 0,
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
+        if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               NULL,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return NULL;
         }
 
         /* What if the path is empty, or the file exists? */
 
-        return context->open(context, fname, O_WRONLY, 666);
-
+       TALLOC_FREE(frame);
+        return (context->open)(context, fname, O_WRONLY, 666);
 }
 
 /*
@@ -5943,11 +6416,13 @@ smbc_print_file_ctx(SMBCCTX *c_file,
         int saverr;
         int tot_bytes = 0;
         char buf[4096];
+       TALLOC_CTX *frame = talloc_stackframe();
 
         if (!c_file || !c_file->internal->_initialized || !c_print ||
             !c_print->internal->_initialized) {
 
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
 
         }
@@ -5955,39 +6430,40 @@ smbc_print_file_ctx(SMBCCTX *c_file,
         if (!fname && !printq) {
 
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
 
         }
 
         /* Try to open the file for reading ... */
 
-        if ((long)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) {
-                
+        if ((long)(fid1 = (c_file->open)(c_file, fname, O_RDONLY, 0666)) < 0) {
                 DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
+               TALLOC_FREE(frame);
                 return -1;  /* smbc_open sets errno */
-                
         }
 
         /* Now, try to open the printer file for writing */
 
-        if ((long)(fid2 = c_print->open_print_job(c_print, printq)) < 0) {
+        if ((long)(fid2 = (c_print->open_print_job)(c_print, printq)) < 0) {
 
                 saverr = errno;  /* Save errno */
-                c_file->close_fn(c_file, fid1);
+                (c_file->close_fn)(c_file, fid1);
                 errno = saverr;
+               TALLOC_FREE(frame);
                 return -1;
 
         }
 
-        while ((bytes = c_file->read(c_file, fid1, buf, sizeof(buf))) > 0) {
+        while ((bytes = (c_file->read)(c_file, fid1, buf, sizeof(buf))) > 0) {
 
                 tot_bytes += bytes;
 
-                if ((c_print->write(c_print, fid2, buf, bytes)) < 0) {
+                if (((c_print->write)(c_print, fid2, buf, bytes)) < 0) {
 
                         saverr = errno;
-                        c_file->close_fn(c_file, fid1);
-                        c_print->close_fn(c_print, fid2);
+                        (c_file->close_fn)(c_file, fid1);
+                        (c_print->close_fn)(c_print, fid2);
                         errno = saverr;
 
                 }
@@ -5996,16 +6472,18 @@ smbc_print_file_ctx(SMBCCTX *c_file,
 
         saverr = errno;
 
-        c_file->close_fn(c_file, fid1);  /* We have to close these anyway */
-        c_print->close_fn(c_print, fid2);
+        (c_file->close_fn)(c_file, fid1);  /* We have to close these anyway */
+        (c_print->close_fn)(c_print, fid2);
 
         if (bytes < 0) {
 
                 errno = saverr;
+               TALLOC_FREE(frame);
                 return -1;
 
         }
 
+       TALLOC_FREE(frame);
         return tot_bytes;
 
 }
@@ -6019,62 +6497,70 @@ smbc_list_print_jobs_ctx(SMBCCTX *context,
                          const char *fname,
                          smbc_list_print_job_fn fn)
 {
-        SMBCSRV *srv;
-        fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-        pstring path;
+       SMBCSRV *srv = NULL;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
 
         if (!context || !context->internal ||
             !context->internal->_initialized) {
-
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
-
         }
 
         if (!fname) {
-                
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
-
         }
-  
+
         DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
 
-        if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
-                return -1;
+        if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-        if (user[0] == (char)0) fstrcpy(user, context->user);
-        
-        srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+        if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-        if (!srv) {
+        srv = smbc_server(frame, context, True,
+                          server, share, &workgroup, &user, &password);
 
+        if (!srv) {
+               TALLOC_FREE(frame);
                 return -1;  /* errno set by smbc_server */
-
         }
 
         if (cli_print_queue(srv->cli,
                             (void (*)(struct print_job_info *))fn) < 0) {
-
                 errno = smbc_errno(context, srv->cli);
+               TALLOC_FREE(frame);
                 return -1;
-
         }
-        
+
+       TALLOC_FREE(frame);
         return 0;
 
 }
@@ -6088,51 +6574,61 @@ smbc_unlink_print_job_ctx(SMBCCTX *context,
                           const char *fname,
                           int id)
 {
-        SMBCSRV *srv;
-        fstring server;
-        fstring share;
-        fstring user;
-        fstring password;
-        fstring workgroup;
-        pstring path;
+       SMBCSRV *srv = NULL;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
         int err;
+       TALLOC_CTX *frame = talloc_stackframe();
 
         if (!context || !context->internal ||
             !context->internal->_initialized) {
-
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
-
         }
 
         if (!fname) {
-
                 errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
-
         }
-  
+
         DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
 
-        if (smbc_parse_path(context, fname,
-                            workgroup, sizeof(workgroup),
-                            server, sizeof(server),
-                            share, sizeof(share),
-                            path, sizeof(path),
-                            user, sizeof(user),
-                            password, sizeof(password),
-                            NULL, 0)) {
-                errno = EINVAL;
-                return -1;
+        if (smbc_parse_path(frame,
+                               context,
+                               fname,
+                               &workgroup,
+                               &server,
+                               &share,
+                               &path,
+                               &user,
+                               &password,
+                               NULL)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
         }
 
-        if (user[0] == (char)0) fstrcpy(user, context->user);
+        if (!user || user[0] == (char)0) {
+               user = talloc_strdup(frame, context->user);
+               if (!user) {
+                       errno = ENOMEM;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+       }
 
-        srv = smbc_server(context, True,
-                          server, share, workgroup, user, password);
+        srv = smbc_server(frame, context, True,
+                          server, share, &workgroup, &user, &password);
 
         if (!srv) {
 
+               TALLOC_FREE(frame);
                 return -1;  /* errno set by smbc_server */
 
         }
@@ -6143,16 +6639,18 @@ smbc_unlink_print_job_ctx(SMBCCTX *context,
                         errno = smbc_errno(context, srv->cli);
                 else if (err == ERRnosuchprintjob)
                         errno = EINVAL;
+               TALLOC_FREE(frame);
                 return -1;
 
         }
 
+       TALLOC_FREE(frame);
         return 0;
 
 }
 
 /*
- * Get a new empty handle to fill in with your own info 
+ * Get a new empty handle to fill in with your own info
  */
 SMBCCTX *
 smbc_new_context(void)
@@ -6176,7 +6674,6 @@ smbc_new_context(void)
 
         ZERO_STRUCTP(context->internal);
 
-        
         /* ADD REASONABLE DEFAULTS */
         context->debug            = 0;
         context->timeout          = 20000; /* 20 seconds */
@@ -6225,10 +6722,10 @@ smbc_new_context(void)
         return context;
 }
 
-/* 
+/*
  * Free a context
  *
- * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed 
+ * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed
  * and thus you'll be leaking memory if not handled properly.
  *
  */
@@ -6240,14 +6737,14 @@ smbc_free_context(SMBCCTX *context,
                 errno = EBADF;
                 return 1;
         }
-        
+
         if (shutdown_ctx) {
                 SMBCFILE * f;
                 DEBUG(1,("Performing aggressive shutdown.\n"));
-                
+
                 f = context->internal->_files;
                 while (f) {
-                        context->close_fn(context, f);
+                        (context->close_fn)(context, f);
                         f = f->next;
                 }
                 context->internal->_files = NULL;
@@ -6263,8 +6760,8 @@ smbc_free_context(SMBCCTX *context,
                                 DEBUG(1, ("Forced shutdown: %p (fd=%d)\n",
                                           s, s->cli->fd));
                                 cli_shutdown(s->cli);
-                                context->callbacks.remove_cached_srv_fn(context,
-                                                                        s);
+                                (context->callbacks.remove_cached_srv_fn)(context,
+                                                                          s);
                                 next = s->next;
                                 DLIST_REMOVE(context->internal->_servers, s);
                                 SAFE_FREE(s);
@@ -6274,8 +6771,8 @@ smbc_free_context(SMBCCTX *context,
                 }
         }
         else {
-                /* This is the polite way */    
-                if (context->callbacks.purge_cached_fn(context)) {
+                /* This is the polite way */
+                if ((context->callbacks.purge_cached_fn)(context)) {
                         DEBUG(1, ("Could not purge all servers, "
                                   "free_context failed.\n"));
                         errno = EBUSY;
@@ -6292,14 +6789,14 @@ smbc_free_context(SMBCCTX *context,
                                   "free_context failed.\n"));
                         errno = EBUSY;
                         return 1;
-                }               
+                }
         }
 
         /* Things we have to clean up */
         SAFE_FREE(context->workgroup);
         SAFE_FREE(context->netbios_name);
         SAFE_FREE(context->user);
-        
+
         DEBUG(3, ("Context %p succesfully freed\n", context));
         SAFE_FREE(context->internal);
         SAFE_FREE(context);
@@ -6322,9 +6819,10 @@ smbc_option_set(SMBCCTX *context,
         va_list ap;
         union {
                 int i;
-                BOOL b;
+                bool b;
                 smbc_get_auth_data_with_context_fn auth_fn;
                 void *v;
+               const char *s;
         } option_value;
 
         va_start(ap, option_name);
@@ -6333,7 +6831,7 @@ smbc_option_set(SMBCCTX *context,
                 /*
                  * Log to standard error instead of standard output.
                  */
-                option_value.b = (BOOL) va_arg(ap, int);
+                option_value.b = (bool) va_arg(ap, int);
                 context->internal->_debug_stderr = option_value.b;
 
         } else if (strcmp(option_name, "full_time_names") == 0) {
@@ -6345,7 +6843,7 @@ smbc_option_set(SMBCCTX *context,
                  * be CHANGE_TIME but was confused and sometimes referred to
                  * CREATE_TIME.)
                  */
-                option_value.b = (BOOL) va_arg(ap, int);
+                option_value.b = (bool) va_arg(ap, int);
                 context->internal->_full_time_names = option_value.b;
 
         } else if (strcmp(option_name, "open_share_mode") == 0) {
@@ -6373,6 +6871,19 @@ smbc_option_set(SMBCCTX *context,
                  */
                 option_value.v = va_arg(ap, void *);
                 context->internal->_user_data = option_value.v;
+        } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+                /*
+                 * Save an encoded value for encryption level.
+                 * 0 = off, 1 = attempt, 2 = required.
+                 */
+                option_value.s = va_arg(ap, const char *);
+               if (strcmp(option_value.s, "none") == 0) {
+                       context->internal->_smb_encryption_level = 0;
+               } else if (strcmp(option_value.s, "request") == 0) {
+                       context->internal->_smb_encryption_level = 1;
+               } else if (strcmp(option_value.s, "require") == 0) {
+                       context->internal->_smb_encryption_level = 2;
+               }
         }
 
         va_end(ap);
@@ -6422,6 +6933,35 @@ smbc_option_get(SMBCCTX *context,
                  * with smbc_option_get()
                  */
                 return context->internal->_user_data;
+        } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+               /*
+                * Return the current smb encrypt negotiate option as a string.
+                */
+               switch (context->internal->_smb_encryption_level) {
+               case 0:
+                       return (void *) "none";
+               case 1:
+                       return (void *) "request";
+               case 2:
+                       return (void *) "require";
+               }
+        } else if (strcmp(option_name, "smb_encrypt_on") == 0) {
+               /*
+                * Return the current smb encrypt status option as a bool.
+                * false = off, true = on. We don't know what server is
+                * being requested, so we only return true if all servers
+                * are using an encrypted connection.
+                */
+               SMBCSRV *s;
+               unsigned int num_servers = 0;
+
+               for (s = context->internal->_servers; s; s = s->next) {
+                       num_servers++;
+                       if (s->cli->trans_enc_state == NULL) {
+                               return (void *)false;
+                       }
+               }
+               return (void *) (bool) (num_servers > 0);
         }
 
         return NULL;
@@ -6429,7 +6969,7 @@ smbc_option_get(SMBCCTX *context,
 
 
 /*
- * Initialise the library etc 
+ * Initialise the library etc
  *
  * We accept a struct containing handle information.
  * valid values for info->debug from 0 to 100,
@@ -6438,7 +6978,6 @@ smbc_option_get(SMBCCTX *context,
 SMBCCTX *
 smbc_init_context(SMBCCTX *context)
 {
-        pstring conf;
         int pid;
         char *user = NULL;
         char *home = NULL;
@@ -6449,7 +6988,7 @@ smbc_init_context(SMBCCTX *context)
         }
 
         /* Do not initialise the same client twice */
-        if (context->internal->_initialized) { 
+        if (context->internal->_initialized) {
                 return 0;
         }
 
@@ -6468,11 +7007,12 @@ smbc_init_context(SMBCCTX *context)
                  * Do some library-wide intializations the first time we get
                  * called
                  */
-               BOOL conf_loaded = False;
+               bool conf_loaded = False;
+               TALLOC_CTX *frame = talloc_stackframe();
 
                 /* Set this to what the user wants */
                 DEBUGLEVEL = context->debug;
-                
+
                 load_case_tables();
 
                 setup_logging("libsmbclient", True);
@@ -6482,66 +7022,74 @@ smbc_init_context(SMBCCTX *context)
                 }
 
                 /* Here we would open the smb.conf file if needed ... */
-                
+
                 in_client = True; /* FIXME, make a param */
 
                 home = getenv("HOME");
                if (home) {
-                       slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
-                       if (lp_load(conf, True, False, False, True)) {
-                               conf_loaded = True;
-                       } else {
-                                DEBUG(5, ("Could not load config file: %s\n",
-                                          conf));
+                               char *conf = NULL;
+                       if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) {
+                               if (lp_load(conf, True, False, False, True)) {
+                                       conf_loaded = True;
+                               } else {
+                                       DEBUG(5, ("Could not load config file: %s\n",
+                                               conf));
+                               }
+                               SAFE_FREE(conf);
                        }
                        }
+
                if (!conf_loaded) {
                         /*
-                         * Well, if that failed, try the dyn_CONFIGFILE
+                         * Well, if that failed, try the get_dyn_CONFIGFILE
                          * Which points to the standard locn, and if that
                          * fails, silently ignore it and use the internal
                          * defaults ...
                          */
 
-                        if (!lp_load(dyn_CONFIGFILE, True, False, False, False)) {
+                        if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) {
                                 DEBUG(5, ("Could not load config file: %s\n",
-                                          dyn_CONFIGFILE));
+                                          get_dyn_CONFIGFILE()));
                         } else if (home) {
+                               char *conf;
                                 /*
                                  * We loaded the global config file.  Now lets
                                  * load user-specific modifications to the
                                  * global config.
                                  */
-                                slprintf(conf, sizeof(conf),
-                                         "%s/.smb/smb.conf.append", home);
-                                if (!lp_load(conf, True, False, False, False)) {
-                                        DEBUG(10,
-                                              ("Could not append config file: "
-                                               "%s\n",
-                                               conf));
-                                }
+                               if (asprintf(&conf,
+                                               "%s/.smb/smb.conf.append",
+                                               home) > 0) {
+                                       if (!lp_load(conf, True, False, False, False)) {
+                                               DEBUG(10,
+                                               ("Could not append config file: "
+                                               "%s\n",
+                                               conf));
+                                       }
+                                       SAFE_FREE(conf);
+                               }
                         }
                 }
 
                 load_interfaces();  /* Load the list of interfaces ... */
-                
+
                 reopen_logs();  /* Get logging working ... */
-        
-                /* 
-                 * Block SIGPIPE (from lib/util_sock.c: write())  
-                 * It is not needed and should not stop execution 
+
+                /*
+                 * Block SIGPIPE (from lib/util_sock.c: write())
+                 * It is not needed and should not stop execution
                  */
                 BlockSignals(True, SIGPIPE);
-                
+
                 /* Done with one-time initialisation */
-                smbc_initialized = 1; 
+                smbc_initialized = 1;
 
+               TALLOC_FREE(frame);
         }
-        
+
         if (!context->user) {
                 /*
-                 * FIXME: Is this the best way to get the user info? 
+                 * FIXME: Is this the best way to get the user info?
                  */
                 user = getenv("USER");
                 /* walk around as "guest" if no username can be found */
@@ -6587,17 +7135,17 @@ smbc_init_context(SMBCCTX *context)
         }
 
         DEBUG(1, ("Using workgroup %s.\n", context->workgroup));
-                                        
+
         /* shortest timeout is 1 second */
-        if (context->timeout > 0 && context->timeout < 1000) 
+        if (context->timeout > 0 && context->timeout < 1000)
                 context->timeout = 1000;
 
         /*
-         * FIXME: Should we check the function pointers here? 
+         * FIXME: Should we check the function pointers here?
          */
 
         context->internal->_initialized = True;
-        
+
         return context;
 }