Merge branch 'v3-2-test' of git://git.samba.org/samba into v3-2-test
[ira/wip.git] / source / libsmb / libsmbclient.c
index abeb66b3733169fbea28e0a3dd3bedf5399eaf95..fb04d143a588836226f1ad0d0991acc3464dbc28 100644 (file)
@@ -6,10 +6,11 @@
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
 #include "include/libsmb_internal.h"
 
+struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir);
+struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, 
+                                        struct smbc_dirent *dirent);
 
 /*
  * DOS Attribute values (used internally)
 typedef struct DOS_ATTR_DESC {
        int mode;
        SMB_OFF_T size;
-       time_t a_time;
-       time_t c_time;
-       time_t m_time;
+       time_t create_time;
+       time_t access_time;
+       time_t write_time;
+       time_t change_time;
        SMB_INO_T inode;
 } DOS_ATTR_DESC;
 
@@ -108,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 ? 
@@ -129,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.
@@ -138,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++];
 
-        p = temp;
-        while ( 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;
+
+                       /* 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;
 }
 
 /*
@@ -196,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";
 
@@ -223,7 +262,7 @@ smbc_urlencode(char * dest, char * src, int max_dest_len)
 
         *dest++ = '\0';
         max_dest_len--;
-        
+
         return max_dest_len;
 }
 
@@ -267,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);
@@ -310,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 */
@@ -322,31 +368,37 @@ 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);
+
+               if (wl > 16) {
+                       wl = 16;
+               }
 
-               strncpy(server, context->workgroup, 
-                       ((strlen(context->workgroup) < 16)
-                         ? strlen(context->workgroup)
-                         : 16));
-                server[server_len - 1] = '\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 ...
@@ -356,73 +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;
+               char *userinfo = NULL;
+               const char *u;
 
-               next_token_no_ltrim(&p, userinfo, "@", sizeof(fstring));
-
-               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;
-
        }
 
-        safe_strcpy(path, p, path_len - 1);
-
-       all_string_sub(path, "/", "\\", 0);
+        /*
+         * Prepend a leading slash if there's a file path, as required by
+         * NetApp filers.
+         */
+        if (*p != '\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;
 }
@@ -487,11 +544,11 @@ static int
 smbc_check_server(SMBCCTX * context,
                   SMBCSRV * server) 
 {
-       if ( send_keepalive(server->cli->fd) == False )
-               return 1;
+        socklen_t size;
+        struct sockaddr addr;
 
-       /* connection is ok */
-       return 0;
+        size = sizeof(addr);
+        return (getpeername(server->cli->fd, &addr, &size) == -1);
 }
 
 /* 
@@ -516,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;
                }
@@ -529,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
@@ -575,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;
@@ -614,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
@@ -622,26 +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;
-  
-       zero_ip(&ip);
+       NTSTATUS status;
+
+       zero_addr(&ss);
        ZERO_STRUCT(c);
 
        if (server[0] == 0) {
@@ -650,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...
@@ -669,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;
                         }
 
@@ -705,7 +804,7 @@ smbc_server(SMBCCTX *context,
                         }
                 }
         }
-        
+
         /* If we have a connection... */
         if (srv) {
 
@@ -719,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) {
@@ -760,17 +863,19 @@ smbc_server(SMBCCTX *context,
 
         c->port = port_try_first;
 
-       if (!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;
 
-                if (!cli_connect(c, server_n, &ip)) {
-                        cli_shutdown(c);
-                        errno = ETIMEDOUT;
-                        return NULL;
-                }
-       }
+                status = cli_connect(c, server_n, &ss);
+               if (!NT_STATUS_IS_OK(status)) {
+                       cli_shutdown(c);
+                       errno = ETIMEDOUT;
+                       return NULL;
+               }
+       }
 
        if (!cli_session_request(c, &calling, &called)) {
                cli_shutdown(c);
@@ -783,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;
                                }
@@ -803,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;
@@ -837,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.
@@ -866,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;
@@ -875,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);
@@ -887,7 +1021,7 @@ smbc_server(SMBCCTX *context,
        if (!srv) {
                return NULL;
        }
-  
+
        SAFE_FREE(srv);
        return NULL;
 }
@@ -897,15 +1031,17 @@ 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,
+               POLICY_HND *pol)
 {
-        struct in_addr ip;
+        int flags;
+        struct sockaddr_storage ss;
        struct cli_state *ipc_cli;
        struct rpc_pipe_client *pipe_hnd;
         NTSTATUS nt_status;
@@ -916,36 +1052,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;
+                       }
                 }
-        
-                zero_ip(&ip);
+
+                flags = 0;
+                if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
+                        flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+                }
+
+                zero_addr(&ss);
                 nt_status = cli_full_connection(&ipc_cli,
-                                                global_myname(), server, 
-                                                &ip, 0, "IPC$", "?????",  
-                                                username, workgroup,
-                                                password, 0,
-                                                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)));
@@ -953,6 +1088,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;
@@ -980,14 +1139,14 @@ smbc_attr_server(SMBCCTX *context,
                          * 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, 
+                                talloc_tos(),
+                                True,
                                 GENERIC_EXECUTE_ACCESS,
                                 pol);
-        
+
                         if (!NT_STATUS_IS_OK(nt_status)) {
                                 errno = smbc_errno(context, ipc_srv->cli);
                                 cli_shutdown(ipc_srv->cli);
@@ -998,11 +1157,11 @@ smbc_attr_server(SMBCCTX *context,
                 /* 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;
@@ -1028,18 +1187,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;
 
        }
@@ -1047,76 +1208,76 @@ 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 ( targetcli->dfsroot )
-               {
-                       pstring temppath;
-                       pstrcpy(temppath, targetpath);
-                       cli_dfs_make_full_path( targetpath, targetcli->desthost, targetcli->share, temppath);
-               }
-               
-               if ((fd = cli_open(targetcli, targetpath, flags, DENY_NONE)) < 0) {
+
+               if ((fd = cli_open(targetcli, targetpath, flags,
+                                   context->internal->_share_mode)) < 0) {
 
                        /* Handle the error ... */
 
                        SAFE_FREE(file);
                        errno = smbc_errno(context, targetcli);
+                       TALLOC_FREE(frame);
                        return NULL;
 
                }
@@ -1157,10 +1318,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;
 
        }
@@ -1171,13 +1334,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;
 
 }
@@ -1216,9 +1381,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:
@@ -1233,8 +1400,8 @@ smbc_read_ctx(SMBCCTX *context,
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
-
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -1242,8 +1409,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;
 
        }
@@ -1253,39 +1420,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;
 
        }
@@ -1294,6 +1465,7 @@ smbc_read_ctx(SMBCCTX *context,
 
        DEBUG(4, ("  --> %d\n", ret));
 
+       TALLOC_FREE(frame);
        return ret;  /* Success, ret bytes of data ... */
 
 }
@@ -1310,32 +1482,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;
 
        }
@@ -1343,42 +1516,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 ...
  */
@@ -1387,51 +1563,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);*/
@@ -1447,8 +1626,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;
 
        }
@@ -1456,6 +1635,7 @@ smbc_close_ctx(SMBCCTX *context,
        DLIST_REMOVE(context->internal->_files, file);
        SAFE_FREE(file->fname);
        SAFE_FREE(file);
+       TALLOC_FREE(frame);
 
        return 0;
 }
@@ -1464,76 +1644,105 @@ 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, 
-            time_t *c_time,
-            time_t *a_time,
-            time_t *m_time,
+            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 ( targetcli->dfsroot )
-       {
-               pstring temppath;
-               pstrcpy(temppath, targetpath);
-               cli_dfs_make_full_path(targetpath, targetcli->desthost,
-                                       targetcli->share, temppath);
-       }
-  
+
        if (!srv->no_pathinfo2 &&
             cli_qpathinfo2(targetcli, targetpath,
-                           NULL, a_time, m_time, c_time, size, mode, ino)) {
-            return True;
+                           create_time_ts,
+                           access_time_ts,
+                           write_time_ts,
+                           change_time_ts,
+                           size, mode, ino)) {
+               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;
         }
 
-       if (cli_getatr(targetcli, targetpath, mode, size, m_time)) {
-                if (m_time != NULL) {
-                        if (a_time != NULL) *a_time = *m_time;
-                        if (c_time != NULL) *c_time = *m_time;
+       if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) {
+
+                struct timespec w_time_ts;
+
+                w_time_ts = convert_time_t_to_timespec(write_time);
+
+                if (write_time_ts != NULL) {
+                       *write_time_ts = w_time_ts;
+                }
+
+                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;
 
 }
@@ -1548,13 +1757,17 @@ 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 c_time, time_t a_time, time_t m_time,
+            time_t create_time,
+            time_t access_time,
+            time_t write_time,
+            time_t change_time,
             uint16 mode)
 {
         int fd;
         int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
         /*
          * First, try setpathinfo (if qpathinfo succeeded), for it is the
@@ -1563,7 +1776,12 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
          * attributes manipulated.
          */
         if (srv->no_pathinfo ||
-            ! cli_setpathinfo(srv->cli, path, c_time, a_time, m_time, mode)) {
+            ! cli_setpathinfo(srv->cli, path,
+                              create_time,
+                              access_time,
+                              write_time,
+                              change_time,
+                              mode)) {
 
                 /*
                  * setpathinfo is not supported; go to plan B. 
@@ -1582,45 +1800,18 @@ 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;
                 }
 
-                /*
-                 * Get the creat time of the file (if it wasn't provided).
-                 * We'll need it in the set call
-                 */
-                if (c_time == 0) {
-                        ret = cli_getattrE(srv->cli, fd,
-                                           NULL, NULL,
-                                           &c_time, NULL, NULL);
-                } else {
-                        ret = True;
-                }
-                    
-                /* If we got create time, set times */
-                if (ret) {
-                        /* Some OS versions don't support create time */
-                        if (c_time == 0 || c_time == -1) {
-                                c_time = time(NULL);
-                        }
+                /* Set the new attributes */
+                ret = cli_setattrE(srv->cli, fd,
+                                   change_time,
+                                   access_time,
+                                   write_time);
 
-                        /*
-                         * For sanity sake, since there is no POSIX function
-                         * to set the create time of a file, if the existing
-                         * create time is greater than either of access time
-                         * or modification time, set create time to the
-                         * smallest of those.  This ensure that the create
-                         * time of a file is never greater than its last
-                         * access or modification time.
-                         */
-                        if (c_time > a_time) c_time = a_time;
-                        if (c_time > m_time) c_time = m_time;
-                        
-                        /* Set the new attributes */
-                        ret = cli_setattrE(srv->cli, fd,
-                                           c_time, a_time, m_time);
-                        cli_close(srv->cli, fd);
-                }
+                /* Close the file */
+                cli_close(srv->cli, fd);
 
                 /*
                  * Unfortunately, setattrE() doesn't have a provision for
@@ -1634,10 +1825,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;
 }
 
@@ -1649,53 +1842,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);*/
@@ -1709,15 +1915,22 @@ smbc_unlink_ctx(SMBCCTX *context,
                        int saverr = errno;
                        SMB_OFF_T size = 0;
                        uint16 mode = 0;
-                       time_t m_time = 0, a_time = 0, c_time = 0;
+                       struct timespec write_time_ts;
+                        struct timespec access_time_ts;
+                        struct timespec change_time_ts;
                        SMB_INO_T ino = 0;
 
                        if (!smbc_getatr(context, srv, path, &mode, &size,
-                                        &c_time, &a_time, &m_time, &ino)) {
+                                        NULL,
+                                         &access_time_ts,
+                                         &write_time_ts,
+                                         &change_time_ts,
+                                         &ino)) {
 
                                /* Hmmm, bad error ... What? */
 
                                errno = smbc_errno(context, targetcli);
+                               TALLOC_FREE(frame);
                                return -1;
 
                        }
@@ -1731,10 +1944,12 @@ smbc_unlink_ctx(SMBCCTX *context,
                        }
                }
 
+               TALLOC_FREE(frame);
                return -1;
 
        }
 
+       TALLOC_FREE(frame);
        return 0;  /* Success ... */
 
 }
@@ -1749,103 +1964,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;
        }
 
@@ -1857,13 +2097,14 @@ smbc_rename_ctx(SMBCCTX *ocontext,
                    !cli_rename(targetcli1, targetpath1, targetpath2)) {
 
                        errno = eno;
+                       TALLOC_FREE(frame);
                        return -1;
 
                }
        }
 
+       TALLOC_FREE(frame);
        return 0; /* Success */
-
 }
 
 /*
@@ -1877,21 +2118,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;
 
        }
@@ -1899,6 +2142,7 @@ smbc_lseek_ctx(SMBCCTX *context,
        if (!file->file) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;      /* Can't lseek a dir ... */
 
        }
@@ -1914,36 +2158,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;
@@ -1957,6 +2204,7 @@ smbc_lseek_ctx(SMBCCTX *context,
 
        }
 
+       TALLOC_FREE(frame);
        return file->offset;
 
 }
@@ -1969,7 +2217,6 @@ static ino_t
 smbc_inode(SMBCCTX *context,
            const char *name)
 {
-
        if (!context || !context->internal ||
            !context->internal->_initialized) {
 
@@ -1995,6 +2242,7 @@ smbc_setup_stat(SMBCCTX *context,
                 SMB_OFF_T size,
                 int mode)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        
        st->st_mode = 0;
 
@@ -2029,6 +2277,7 @@ smbc_setup_stat(SMBCCTX *context,
                st->st_ino = smbc_inode(context, fname);
        }
        
+       TALLOC_FREE(frame);
        return True;  /* FIXME: Is this needed ? */
 
 }
@@ -2042,75 +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;
-       time_t m_time = 0;
-        time_t a_time = 0;
-        time_t c_time = 0;
+       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, 
-                        &c_time, &a_time, &m_time, &ino)) {
-
+       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);
 
-       st->st_atime = a_time;
-       st->st_ctime = c_time;
-       st->st_mtime = m_time;
+       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;
 
 }
@@ -2124,82 +2388,96 @@ smbc_fstat_ctx(SMBCCTX *context,
                SMBCFILE *file,
                struct stat *st)
 {
-       time_t c_time;
-        time_t a_time;
-        time_t m_time;
+       struct timespec change_time_ts;
+        struct timespec access_time_ts;
+        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);*/
 
        if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size,
-                           NULL, &a_time, &m_time, &c_time, &ino)) {
-           if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size,
-                              &c_time, &a_time, &m_time)) {
+                           NULL,
+                           &access_time_ts,
+                           &write_time_ts,
+                           &change_time_ts,
+                           &ino)) {
 
-               errno = EINVAL;
-               return -1;
-           }
+               time_t change_time, access_time, write_time;
+
+               if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size,
+                               &change_time, &access_time, &write_time)) {
+
+                       errno = EINVAL;
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+
+               change_time_ts = convert_time_t_to_timespec(change_time);
+               access_time_ts = convert_time_t_to_timespec(access_time);
+               write_time_ts = convert_time_t_to_timespec(write_time);
        }
 
        st->st_ino = ino;
 
        smbc_setup_stat(context, st, file->fname, size, mode);
 
-       st->st_atime = a_time;
-       st->st_ctime = c_time;
-       st->st_mtime = m_time;
+       set_atimespec(st, access_time_ts);
+       set_ctimespec(st, change_time_ts);
+       set_mtimespec(st, write_time_ts);
        st->st_dev = file->srv->dev;
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -2367,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:
@@ -2446,7 +2723,6 @@ net_share_enum_rpc(struct cli_state *cli,
        SRV_SHARE_INFO_CTR ctr;
        fstring name = "";
         fstring comment = "";
-        void *mem_ctx;
        struct rpc_pipe_client *pipe_hnd;
         NTSTATUS nt_status;
 
@@ -2457,18 +2733,10 @@ 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; 
-        }
-
         /* Issue the NetShareEnum RPC call and retrieve the response */
        init_enum_hnd(&enum_hnd, 0);
        result = rpccli_srvsvc_net_share_enum(pipe_hnd,
-                                              mem_ctx,
+                                              talloc_tos(),
                                               info_level,
                                               &ctr,
                                               preferred_len,
@@ -2502,9 +2770,6 @@ 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 W_ERROR_IS_OK(result) ? 0 : -1;
 }
@@ -2515,19 +2780,23 @@ static SMBCFILE *
 smbc_opendir_ctx(SMBCCTX *context,
                  const char *fname)
 {
-       fstring server, share, user, password, options;
-       pstring workgroup;
-       pstring path;
+        int saved_errno;
+       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 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;
 
        }
@@ -2535,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;
        }
 
@@ -2559,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);
@@ -2590,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) {
 
@@ -2599,6 +2878,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                                SAFE_FREE(dir->fname);
                                SAFE_FREE(dir);
                        }
+                       TALLOC_FREE(frame);
                        return NULL;
                }
 
@@ -2607,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
@@ -2620,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));
 
@@ -2662,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,
@@ -2684,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
@@ -2698,8 +3012,9 @@ smbc_opendir_ctx(SMBCCTX *context,
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
+                               TALLOC_FREE(frame);
                                return NULL;
-       
+
                        }
 
                        /*
@@ -2716,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
@@ -2725,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;
 
@@ -2736,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 "
@@ -2746,6 +3061,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                                                SAFE_FREE(dir);
                                        }
                                        errno = EPERM;
+                                       TALLOC_FREE(frame);
                                        return NULL;
 
                                }
@@ -2754,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;
 
                                }
@@ -2778,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) {
@@ -2796,6 +3114,7 @@ smbc_opendir_ctx(SMBCCTX *context,
                                                 SAFE_FREE(dir->fname);
                                                 SAFE_FREE(dir);
                                         }
+                                       TALLOC_FREE(frame);
                                         return NULL;
 
                                 }
@@ -2811,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;
                        }
 
@@ -2838,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;
@@ -2862,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) {
@@ -2883,9 +3211,9 @@ smbc_opendir_ctx(SMBCCTX *context,
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
-                               errno = smbc_errno(context, targetcli);
+                               saved_errno = smbc_errno(context, targetcli);
 
-                                if (errno == EINVAL) {
+                                if (saved_errno == EINVAL) {
                                     /*
                                      * See if they asked to opendir something
                                      * other than a directory.  If so, the
@@ -2896,23 +3224,49 @@ smbc_opendir_ctx(SMBCCTX *context,
 
                                     if (smbc_getatr(context, srv, path,
                                                     &mode, NULL,
-                                                    NULL, NULL, NULL,
+                                                    NULL, NULL, NULL, NULL,
                                                     NULL) &&
                                         ! IS_DOS_DIR(mode)) {
 
                                         /* It is.  Correct the error value */
-                                        errno = ENOTDIR;
+                                        saved_errno = ENOTDIR;
                                     }
                                 }
 
-                               return NULL;
+                                /*
+                                 * If there was an error and the server is no
+                                 * good any more...
+                                 */
+                                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);
+                                        }
+                                }
 
+                                errno = saved_errno;
+                               TALLOC_FREE(frame);
+                               return NULL;
                        }
                }
 
        }
 
        DLIST_ADD(context->internal->_files, dir);
+       TALLOC_FREE(frame);
        return dir;
 
 }
@@ -2925,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 */
@@ -2951,6 +3304,7 @@ smbc_closedir_ctx(SMBCCTX *context,
                SAFE_FREE(dir);    /* Free the space too */
        }
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -3001,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 ... */
 
@@ -3009,6 +3364,7 @@ smbc_readdir_ctx(SMBCCTX *context,
 
                errno = EINVAL;
                 DEBUG(0, ("Invalid context in smbc_readdir_ctx()\n"));
+               TALLOC_FREE(frame);
                return NULL;
 
        }
@@ -3017,6 +3373,7 @@ smbc_readdir_ctx(SMBCCTX *context,
 
                errno = EBADF;
                 DEBUG(0, ("Invalid dir in smbc_readdir_ctx()\n"));
+               TALLOC_FREE(frame);
                return NULL;
 
        }
@@ -3025,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;
         }
 
@@ -3037,6 +3396,7 @@ smbc_readdir_ctx(SMBCCTX *context,
         if (!dirent) {
 
                 errno = ENOENT;
+               TALLOC_FREE(frame);
                 return NULL;
 
         }
@@ -3049,6 +3409,7 @@ smbc_readdir_ctx(SMBCCTX *context,
 
         dir->dir_next = dir->dir_next->next;
 
+       TALLOC_FREE(frame);
         return dirp;
 }
 
@@ -3067,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 ... */
 
@@ -3074,6 +3436,7 @@ smbc_getdents_ctx(SMBCCTX *context,
            !context->internal->_initialized) {
 
                errno = EINVAL;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3081,6 +3444,7 @@ smbc_getdents_ctx(SMBCCTX *context,
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
 
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
     
        }
@@ -3088,6 +3452,7 @@ smbc_getdents_ctx(SMBCCTX *context,
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
 
                errno = ENOTDIR;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3104,6 +3469,7 @@ smbc_getdents_ctx(SMBCCTX *context,
                if (!dirlist->dirent) {
 
                        errno = ENOENT;  /* Bad error */
+                       TALLOC_FREE(frame);
                        return -1;
 
                }
@@ -3121,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;
 
                        }
@@ -3147,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;
 
 }
@@ -3163,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);*/
@@ -3223,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;
 
 }
@@ -3245,7 +3629,6 @@ rmdir_list_fn(const char *mnt,
 {
        if (strncmp(finfo->name, ".", 1) != 0 &&
             strncmp(finfo->name, "..", 2) != 0) {
-                
                smbc_rmdir_dirempty = False;
         }
 }
@@ -3258,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);*/
@@ -3325,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,
@@ -3338,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;
 
@@ -3351,10 +3749,12 @@ smbc_rmdir_ctx(SMBCCTX *context,
 
                }
 
+               TALLOC_FREE(frame);
                return -1;
 
        } 
 
+       TALLOC_FREE(frame);
        return 0;
 
 }
@@ -3367,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;
 
        }
@@ -3380,6 +3781,7 @@ smbc_telldir_ctx(SMBCCTX *context,
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
 
                errno = EBADF;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3387,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;
 }
 
 /*
@@ -3442,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;
 
        }
@@ -3454,6 +3865,7 @@ smbc_lseekdir_ctx(SMBCCTX *context,
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
 
                errno = ENOTDIR;
+               TALLOC_FREE(frame);
                return -1;
 
        }
@@ -3463,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;
 }
 
 /*
@@ -3493,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
@@ -3512,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 */
        }
 
@@ -3568,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;
 }
 
@@ -3579,51 +4005,49 @@ 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;
-        time_t a_time;
-        time_t m_time;
+        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) {
-                a_time = m_time = time(NULL);
+                access_time = write_time = time(NULL);
         } else {
-                a_time = tbuf[0].tv_sec;
-                m_time = tbuf[1].tv_sec;
+                access_time = tbuf[0].tv_sec;
+                write_time = tbuf[1].tv_sec;
         }
 
-        if (DEBUGLVL(4)) 
-        {
+        if (DEBUGLVL(4)) {
                 char *p;
                 char atimebuf[32];
                 char mtimebuf[32];
 
-                strncpy(atimebuf, ctime(&a_time), sizeof(atimebuf) - 1);
+                strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
                 atimebuf[sizeof(atimebuf) - 1] = '\0';
                 if ((p = strchr(atimebuf, '\n')) != NULL) {
                         *p = '\0';
                 }
 
-                strncpy(mtimebuf, ctime(&m_time), sizeof(mtimebuf) - 1);
+                strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
                 mtimebuf[sizeof(mtimebuf) - 1] = '\0';
                 if ((p = strchr(mtimebuf, '\n')) != NULL) {
                         *p = '\0';
@@ -3633,61 +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, a_time, m_time, 0)) {
+        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->info.mask != ace2->info.mask) 
-               return ace1->info.mask - ace2->info.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));
 }
@@ -3699,14 +4199,14 @@ sort_acl(SEC_ACL *the_acl)
        uint32 i;
        if (!the_acl) return;
 
-       qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]),
+       qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]),
               QSORT_CAST ace_compare);
 
        for (i=1;i<the_acl->num_aces;) {
-               if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) {
+               if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
                        int j;
                        for (j=i; j<the_acl->num_aces-1; j++) {
-                               the_acl->ace[j] = the_acl->ace[j+1];
+                               the_acl->aces[j] = the_acl->aces[j+1];
                        }
                        the_acl->num_aces--;
                } else {
@@ -3720,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 SID_NAME_USE *types = 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",
@@ -3754,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 SID_NAME_USE *types = NULL;
+       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) {
@@ -3779,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, &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;
        }
@@ -3789,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;
@@ -3814,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[] = {
@@ -3836,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 */
@@ -3849,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) {
@@ -3862,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;
        }
@@ -3893,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) {
@@ -3902,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.mask = amask;
+       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)
@@ -3933,7 +4457,7 @@ add_ace(SEC_ACL **the_acl,
        if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) {
                return False;
        }
-       memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE));
+       memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
        memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
        newacl = make_sec_acl(ctx, (*the_acl)->revision,
                               1+(*the_acl)->num_aces, aces);
@@ -3948,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);
@@ -4000,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;
                        }
@@ -4016,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;
                        }
@@ -4062,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;
@@ -4079,12 +4603,15 @@ dos_attr_query(SMBCCTX *context,
                const char *filename,
                SMBCSRV *srv)
 {
-        time_t m_time = 0, a_time = 0, c_time = 0;
+        struct timespec create_time_ts;
+        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 inode = 0;
         DOS_ATTR_DESC *ret;
-    
+
         ret = TALLOC_P(ctx, DOS_ATTR_DESC);
         if (!ret) {
                 errno = ENOMEM;
@@ -4093,20 +4620,23 @@ dos_attr_query(SMBCCTX *context,
 
         /* Obtain the DOS attributes */
         if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename),
-                         &mode, &size, 
-                         &c_time, &a_time, &m_time, &inode)) {
-        
+                         &mode, &size,
+                         &create_time_ts,
+                         &access_time_ts,
+                         &write_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->a_time = a_time;
-        ret->c_time = c_time;
-        ret->m_time = m_time;
+        ret->create_time = convert_timespec_to_time_t(create_time_ts);
+        ret->access_time = convert_timespec_to_time_t(access_time_ts);
+        ret->write_time = convert_timespec_to_time_t(write_time_ts);
+        ret->change_time = convert_timespec_to_time_t(change_time_ts);
         ret->inode = inode;
 
         return ret;
@@ -4120,11 +4650,44 @@ dos_attr_parse(SMBCCTX *context,
                SMBCSRV *srv,
                char *str)
 {
-       const char *p = str;
-       fstring tok;
+        int n;
+        const char *p = str;
+       char *tok = NULL;
+       TALLOC_CTX *frame = NULL;
+        struct {
+                const char * create_time_attr;
+                const char * access_time_attr;
+                const char * write_time_attr;
+                const char * change_time_attr;
+        } attr_strings;
+
+        /* Determine whether to use old-style or new-style attribute names */
+        if (context->internal->_full_time_names) {
+                /* new-style names */
+                attr_strings.create_time_attr = "CREATE_TIME";
+                attr_strings.access_time_attr = "ACCESS_TIME";
+                attr_strings.write_time_attr = "WRITE_TIME";
+                attr_strings.change_time_attr = "CHANGE_TIME";
+        } else {
+                /* old-style names */
+                attr_strings.create_time_attr = NULL;
+                attr_strings.access_time_attr = "A_TIME";
+                attr_strings.write_time_attr = "M_TIME";
+                attr_strings.change_time_attr = "C_TIME";
+        }
 
-       while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
+        /* if this is to set the entire ACL... */
+        if (*str == '*') {
+                /* ... then increment past the first colon if there is one */
+                if ((p = strchr(str, ':')) != NULL) {
+                        ++p;
+                } else {
+                        p = str;
+                }
+        }
 
+       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);
                        continue;
@@ -4135,29 +4698,43 @@ dos_attr_parse(SMBCCTX *context,
                        continue;
                }
 
-               if (StrnCaseCmp(tok, "A_TIME:", 7) == 0) {
-                        dad->a_time = (time_t)strtol(tok+7, NULL, 10);
+                n = strlen(attr_strings.access_time_attr);
+                if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) {
+                        dad->access_time = (time_t)strtol(tok+n+1, NULL, 10);
                        continue;
                }
 
-               if (StrnCaseCmp(tok, "C_TIME:", 7) == 0) {
-                        dad->c_time = (time_t)strtol(tok+7, NULL, 10);
+                n = strlen(attr_strings.change_time_attr);
+                if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) {
+                        dad->change_time = (time_t)strtol(tok+n+1, NULL, 10);
                        continue;
                }
 
-               if (StrnCaseCmp(tok, "M_TIME:", 7) == 0) {
-                        dad->m_time = (time_t)strtol(tok+7, NULL, 10);
+                n = strlen(attr_strings.write_time_attr);
+                if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) {
+                        dad->write_time = (time_t)strtol(tok+n+1, NULL, 10);
                        continue;
                }
 
+               if (attr_strings.create_time_attr != NULL) {
+                       n = strlen(attr_strings.create_time_attr);
+                       if (StrnCaseCmp(tok, attr_strings.create_time_attr,
+                                       n) == 0) {
+                               dad->create_time = (time_t)strtol(tok+n+1,
+                                                                 NULL, 10);
+                               continue;
+                       }
+               }
+
                if (StrnCaseCmp(tok, "INODE:", 6) == 0) {
                         dad->inode = (SMB_INO_T)atof(tok+6);
                        continue;
                }
        }
+       TALLOC_FREE(frame);
 }
 
-/***************************************************** 
+/*****************************************************
  Retrieve the acls for a file.
 *******************************************************/
 
@@ -4175,24 +4752,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_ctime = False;
-        BOOL exclude_dos_atime = False;
-        BOOL exclude_dos_mtime = 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;
@@ -4200,11 +4778,55 @@ cacl_get(SMBCCTX *context,
         char *name;
         char *pExclude;
         char *p;
-       time_t m_time = 0, a_time = 0, c_time = 0;
+        struct timespec create_time_ts;
+       struct timespec write_time_ts;
+        struct timespec access_time_ts;
+        struct timespec change_time_ts;
+       time_t create_time = (time_t)0;
+       time_t write_time = (time_t)0;
+        time_t access_time = (time_t)0;
+        time_t change_time = (time_t)0;
        SMB_OFF_T size = 0;
        uint16 mode = 0;
        SMB_INO_T ino = 0;
         struct cli_state *cli = srv->cli;
+        struct {
+                const char * create_time_attr;
+                const char * access_time_attr;
+                const char * write_time_attr;
+                const char * change_time_attr;
+        } attr_strings;
+        struct {
+                const char * create_time_attr;
+                const char * access_time_attr;
+                const char * write_time_attr;
+                const char * change_time_attr;
+        } excl_attr_strings;
+
+        /* Determine whether to use old-style or new-style attribute names */
+        if (context->internal->_full_time_names) {
+                /* new-style names */
+                attr_strings.create_time_attr = "CREATE_TIME";
+                attr_strings.access_time_attr = "ACCESS_TIME";
+                attr_strings.write_time_attr = "WRITE_TIME";
+                attr_strings.change_time_attr = "CHANGE_TIME";
+
+                excl_attr_strings.create_time_attr = "CREATE_TIME";
+                excl_attr_strings.access_time_attr = "ACCESS_TIME";
+                excl_attr_strings.write_time_attr = "WRITE_TIME";
+                excl_attr_strings.change_time_attr = "CHANGE_TIME";
+        } else {
+                /* old-style names */
+                attr_strings.create_time_attr = NULL;
+                attr_strings.access_time_attr = "A_TIME";
+                attr_strings.write_time_attr = "M_TIME";
+                attr_strings.change_time_attr = "C_TIME";
+
+                excl_attr_strings.create_time_attr = NULL;
+                excl_attr_strings.access_time_attr = "dos_attr.A_TIME";
+                excl_attr_strings.write_time_attr = "dos_attr.M_TIME";
+                excl_attr_strings.change_time_attr = "dos_attr.C_TIME";
+        }
 
         /* Copy name so we can strip off exclusions (if any are specified) */
         strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1);
@@ -4262,14 +4884,22 @@ cacl_get(SMBCCTX *context,
                 else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) {
                     exclude_dos_size = True;
                 }
-                else if (StrCaseCmp(pExclude, "dos_attr.c_time") == 0) {
-                    exclude_dos_ctime = True;
+                else if (excl_attr_strings.create_time_attr != NULL &&
+                         StrCaseCmp(pExclude,
+                                    excl_attr_strings.change_time_attr) == 0) {
+                    exclude_dos_create_time = True;
+                }
+                else if (StrCaseCmp(pExclude,
+                                    excl_attr_strings.access_time_attr) == 0) {
+                    exclude_dos_access_time = True;
                 }
-                else if (StrCaseCmp(pExclude, "dos_attr.a_time") == 0) {
-                    exclude_dos_atime = True;
+                else if (StrCaseCmp(pExclude,
+                                    excl_attr_strings.write_time_attr) == 0) {
+                    exclude_dos_write_time = True;
                 }
-                else if (StrCaseCmp(pExclude, "dos_attr.m_time") == 0) {
-                    exclude_dos_mtime = True;
+                else if (StrCaseCmp(pExclude,
+                                    excl_attr_strings.change_time_attr) == 0) {
+                    exclude_dos_change_time = True;
                 }
                 else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) {
                     exclude_dos_inode = True;
@@ -4344,7 +4974,7 @@ cacl_get(SMBCCTX *context,
                                                      sd->revision);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4352,6 +4982,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_nt_owner) {
@@ -4374,7 +5005,7 @@ cacl_get(SMBCCTX *context,
                                                 return -1;
                                         }
                                         n = strlen(p);
-                                } else {
+                                } else if (sidstr[0] != '\0') {
                                         n = snprintf(buf, bufsize,
                                                      ",OWNER:%s", sidstr);
                                 }
@@ -4399,13 +5030,14 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_nt_group) {
-                        if (sd->grp_sid) {
+                        if (sd->group_sid) {
                                 convert_sid_to_string(ipc_cli, pol,
                                                       sidstr, numeric,
-                                                      sd->grp_sid);
+                                                      sd->group_sid);
                         } else {
                                 fstrcpy(sidstr, "");
                         }
@@ -4419,7 +5051,7 @@ cacl_get(SMBCCTX *context,
                                                 return -1;
                                         }
                                         n = strlen(p);
-                                } else {
+                                } else if (sidstr[0] != '\0') {
                                         n = snprintf(buf, bufsize,
                                                      ",GROUP:%s", sidstr);
                                 }
@@ -4444,13 +5076,14 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_nt_acl) {
                         /* Add aces to value buffer  */
                         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
 
-                                SEC_ACE *ace = &sd->dacl->ace[i];
+                                SEC_ACE *ace = &sd->dacl->aces[i];
                                 convert_sid_to_string(ipc_cli, pol,
                                                       sidstr, numeric,
                                                       &ace->trustee);
@@ -4464,7 +5097,7 @@ cacl_get(SMBCCTX *context,
                                                         sidstr,
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                                 if (!p) {
                                                         errno = ENOMEM;
                                                         return -1;
@@ -4477,7 +5110,7 @@ cacl_get(SMBCCTX *context,
                                                         sidstr,
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                         }
                                 } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
                                             StrCaseCmp(name+3, sidstr) == 0) ||
@@ -4489,7 +5122,7 @@ cacl_get(SMBCCTX *context,
                                                         "%d/%d/0x%08x", 
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                                 if (!p) {
                                                         errno = ENOMEM;
                                                         return -1;
@@ -4500,7 +5133,7 @@ cacl_get(SMBCCTX *context,
                                                              "%d/%d/0x%08x", 
                                                              ace->type,
                                                              ace->flags,
-                                                             ace->info.mask);
+                                                             ace->access_mask);
                                         }
                                 } else if (all_nt_acls) {
                                         if (determine_size) {
@@ -4511,7 +5144,7 @@ cacl_get(SMBCCTX *context,
                                                         sidstr,
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                                 if (!p) {
                                                         errno = ENOMEM;
                                                         return -1;
@@ -4524,16 +5157,17 @@ cacl_get(SMBCCTX *context,
                                                              sidstr,
                                                              ace->type,
                                                              ace->flags,
-                                                             ace->info.mask);
+                                                             ace->access_mask);
                                         }
                                 }
-                                if (n > bufsize) {
+                                if (!determine_size && n > bufsize) {
                                         errno = ERANGE;
                                         return -1;
                                 }
                                 buf += n;
                                 n_used += n;
                                 bufsize -= n;
+                                n = 0;
                         }
                 }
 
@@ -4547,13 +5181,22 @@ cacl_get(SMBCCTX *context,
 
                 /* Obtain the DOS attributes */
                 if (!smbc_getatr(context, srv, filename, &mode, &size, 
-                                 &c_time, &a_time, &m_time, &ino)) {
-                        
+                                 &create_time_ts,
+                                 &access_time_ts,
+                                 &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);
+                access_time = convert_timespec_to_time_t(access_time_ts);
+                write_time = convert_timespec_to_time_t(write_time_ts);
+                change_time = convert_timespec_to_time_t(change_time_ts);
+
                 if (! exclude_dos_mode) {
                         if (all || all_dos) {
                                 if (determine_size) {
@@ -4591,7 +5234,7 @@ cacl_get(SMBCCTX *context,
                                                      "0x%x", mode);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4599,6 +5242,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_size) {
@@ -4635,7 +5279,7 @@ cacl_get(SMBCCTX *context,
                                                      (double)size);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4643,14 +5287,17 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
-                if (! exclude_dos_ctime) {
+                if (! exclude_dos_create_time &&
+                    attr_strings.create_time_attr != NULL) {
                         if (all || all_dos) {
                                 if (determine_size) {
                                         p = talloc_asprintf(ctx,
-                                                            ",C_TIME:%lu",
-                                                            c_time);
+                                                            ",%s:%lu",
+                                                            attr_strings.create_time_attr,
+                                                            create_time);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
@@ -4658,11 +5305,13 @@ cacl_get(SMBCCTX *context,
                                         n = strlen(p);
                                 } else {
                                         n = snprintf(buf, bufsize,
-                                                     ",C_TIME:%lu", c_time);
+                                                     ",%s:%lu",
+                                                     attr_strings.create_time_attr,
+                                                     create_time);
                                 }
-                        } else if (StrCaseCmp(name, "c_time") == 0) {
+                        } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) {
                                 if (determine_size) {
-                                        p = talloc_asprintf(ctx, "%lu", c_time);
+                                        p = talloc_asprintf(ctx, "%lu", create_time);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
@@ -4670,10 +5319,10 @@ cacl_get(SMBCCTX *context,
                                         n = strlen(p);
                                 } else {
                                         n = snprintf(buf, bufsize,
-                                                     "%lu", c_time);
+                                                     "%lu", create_time);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4681,14 +5330,16 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
-                if (! exclude_dos_atime) {
+                if (! exclude_dos_access_time) {
                         if (all || all_dos) {
                                 if (determine_size) {
                                         p = talloc_asprintf(ctx,
-                                                            ",A_TIME:%lu",
-                                                            a_time);
+                                                            ",%s:%lu",
+                                                            attr_strings.access_time_attr,
+                                                            access_time);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
@@ -4696,11 +5347,13 @@ cacl_get(SMBCCTX *context,
                                         n = strlen(p);
                                 } else {
                                         n = snprintf(buf, bufsize,
-                                                     ",A_TIME:%lu", a_time);
+                                                     ",%s:%lu",
+                                                     attr_strings.access_time_attr,
+                                                     access_time);
                                 }
-                        } else if (StrCaseCmp(name, "a_time") == 0) {
+                        } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) {
                                 if (determine_size) {
-                                        p = talloc_asprintf(ctx, "%lu", a_time);
+                                        p = talloc_asprintf(ctx, "%lu", access_time);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
@@ -4708,10 +5361,10 @@ cacl_get(SMBCCTX *context,
                                         n = strlen(p);
                                 } else {
                                         n = snprintf(buf, bufsize,
-                                                     "%lu", a_time);
+                                                     "%lu", access_time);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4719,14 +5372,16 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
-                if (! exclude_dos_mtime) {
+                if (! exclude_dos_write_time) {
                         if (all || all_dos) {
                                 if (determine_size) {
                                         p = talloc_asprintf(ctx,
-                                                            ",M_TIME:%lu",
-                                                            m_time);
+                                                            ",%s:%lu",
+                                                            attr_strings.write_time_attr,
+                                                            write_time);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
@@ -4734,11 +5389,13 @@ cacl_get(SMBCCTX *context,
                                         n = strlen(p);
                                 } else {
                                         n = snprintf(buf, bufsize,
-                                                     ",M_TIME:%lu", m_time);
+                                                     ",%s:%lu",
+                                                     attr_strings.write_time_attr,
+                                                     write_time);
                                 }
-                        } else if (StrCaseCmp(name, "m_time") == 0) {
+                        } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) {
                                 if (determine_size) {
-                                        p = talloc_asprintf(ctx, "%lu", m_time);
+                                        p = talloc_asprintf(ctx, "%lu", write_time);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
@@ -4746,10 +5403,52 @@ cacl_get(SMBCCTX *context,
                                         n = strlen(p);
                                 } else {
                                         n = snprintf(buf, bufsize,
-                                                     "%lu", m_time);
+                                                     "%lu", write_time);
                                 }
                         }
-        
+
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
+                        n = 0;
+                }
+
+                if (! exclude_dos_change_time) {
+                        if (all || all_dos) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx,
+                                                            ",%s:%lu",
+                                                            attr_strings.change_time_attr,
+                                                            change_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     ",%s:%lu",
+                                                     attr_strings.change_time_attr,
+                                                     change_time);
+                                }
+                        } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, "%lu", change_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     "%lu", change_time);
+                                }
+                        }
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4757,6 +5456,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 if (! exclude_dos_inode) {
@@ -4793,7 +5493,7 @@ cacl_get(SMBCCTX *context,
                                                      (double) ino);
                                 }
                         }
-        
+
                         if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
@@ -4801,6 +5501,7 @@ cacl_get(SMBCCTX *context,
                         buf += n;
                         n_used += n;
                         bufsize -= n;
+                        n = 0;
                 }
 
                 /* Restore name pointer to its original value */
@@ -4815,8 +5516,7 @@ cacl_get(SMBCCTX *context,
        return n_used;
 }
 
-
-/***************************************************** 
+/*****************************************************
 set the ACLs on a file given an ascii description
 *******************************************************/
 static int
@@ -4833,13 +5533,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) {
@@ -4895,30 +5595,22 @@ cacl_set(TALLOC_CTX *ctx,
        switch (mode) {
        case SMBC_XATTR_MODE_REMOVE_ALL:
                 old->dacl->num_aces = 0;
-                SAFE_FREE(old->dacl->ace);
-                SAFE_FREE(old->dacl);
-                old->off_dacl = 0;
                 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->ace[i],
-                                                  &old->dacl->ace[j])) {
+                                if (sec_ace_equal(&sd->dacl->aces[i],
+                                                  &old->dacl->aces[j])) {
                                        uint32 k;
                                        for (k=j; k<old->dacl->num_aces-1;k++) {
-                                               old->dacl->ace[k] =
-                                                        old->dacl->ace[k+1];
+                                               old->dacl->aces[k] =
+                                                        old->dacl->aces[k+1];
                                        }
                                        old->dacl->num_aces--;
-                                       if (old->dacl->num_aces == 0) {
-                                               SAFE_FREE(old->dacl->ace);
-                                               SAFE_FREE(old->dacl);
-                                               old->off_dacl = 0;
-                                       }
                                        found = True;
                                         dacl = old->dacl;
                                        break;
@@ -4935,17 +5627,17 @@ 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->ace[i].trustee,
-                                             &old->dacl->ace[j].trustee)) {
+                               if (sid_equal(&sd->dacl->aces[i].trustee,
+                                             &old->dacl->aces[j].trustee)) {
                                         if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
                                                 err = EEXIST;
                                                 ret = -1;
                                                 goto failed;
                                         }
-                                        old->dacl->ace[j] = sd->dacl->ace[i];
+                                        old->dacl->aces[j] = sd->dacl->aces[i];
                                         ret = -1;
                                        found = True;
                                }
@@ -4956,9 +5648,9 @@ 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->ace[i], ctx);
+                                add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
                         }
                }
                 dacl = old->dacl;
@@ -4967,7 +5659,7 @@ cacl_set(TALLOC_CTX *ctx,
        case SMBC_XATTR_MODE_SET:
                old = sd;
                 owner_sid = old->owner_sid;
-                grp_sid = old->grp_sid;
+                group_sid = old->group_sid;
                 dacl = old->dacl;
                break;
 
@@ -4976,7 +5668,7 @@ cacl_set(TALLOC_CTX *ctx,
                 break;
 
         case SMBC_XATTR_MODE_CHGRP:
-                grp_sid = sd->grp_sid;
+                group_sid = sd->group_sid;
                 break;
        }
 
@@ -4984,8 +5676,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);
@@ -5010,7 +5702,7 @@ cacl_set(TALLOC_CTX *ctx,
         if (err != 0) {
                 errno = err;
         }
-        
+
        return ret;
 }
 
@@ -5025,70 +5717,81 @@ 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;
+        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;
         POLICY_HND pol;
-        DOS_ATTR_DESC *dad;
+        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,
+                ipc_srv = smbc_attr_server(frame, context, server, share,
+                                           &workgroup, &user, &password,
                                            &pol);
-                srv->no_nt_session = True;
+                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?
@@ -5097,16 +5800,17 @@ 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,
+                        ret = cacl_set(talloc_tos(), srv->cli,
                                        ipc_srv->cli, &pol, path,
                                        namevalue,
                                        (*namevalue == '*'
@@ -5118,16 +5822,17 @@ 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);
 
                         /* Set the new DOS attributes */
                         if (! smbc_setatr(context, srv, path,
-                                          dad->c_time,
-                                          dad->a_time,
-                                          dad->m_time,
+                                          dad->create_time,
+                                          dad->access_time,
+                                          dad->write_time,
+                                          dad->change_time,
                                           dad->mode)) {
 
                                 /* cause failure if NT failed too */
@@ -5143,7 +5848,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
                         ret = 0;
                 }
 
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5159,7 +5864,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) {
@@ -5169,7 +5874,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
                         errno = ENOMEM;
                         ret = -1;
                 } else {
-                        ret = cacl_set(ctx, srv->cli,
+                        ret = cacl_set(talloc_tos(), srv->cli,
                                        ipc_srv->cli, &pol, path,
                                        namevalue,
                                        (*namevalue == '*'
@@ -5177,7 +5882,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
                                         : SMBC_XATTR_MODE_ADD),
                                        flags);
                 }
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5189,22 +5894,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,
+                        ret = cacl_set(talloc_tos(), srv->cli,
                                        ipc_srv->cli, &pol, path,
                                        namevalue, SMBC_XATTR_MODE_CHOWN, 0);
                 }
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5216,7 +5920,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) {
@@ -5227,28 +5931,45 @@ smbc_setxattr_ctx(SMBCCTX *context,
                         errno = ENOMEM;
                         ret = -1;
                 } else {
-                        ret = cacl_set(ctx, srv->cli,
+                        ret = cacl_set(talloc_tos(), srv->cli,
                                        ipc_srv->cli, &pol, path,
                                        namevalue, SMBC_XATTR_MODE_CHOWN, 0);
                 }
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
+        /* Determine whether to use old-style or new-style attribute names */
+        if (context->internal->_full_time_names) {
+                /* new-style names */
+                attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
+                attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
+                attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
+                attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
+        } else {
+                /* old-style names */
+                attr_strings.create_time_attr = NULL;
+                attr_strings.access_time_attr = "system.dos_attr.A_TIME";
+                attr_strings.write_time_attr = "system.dos_attr.M_TIME";
+                attr_strings.change_time_attr = "system.dos_attr.C_TIME";
+        }
+
         /*
          * Are they asking to set a DOS attribute?
          */
         if (StrCaseCmp(name, "system.dos_attr.*") == 0 ||
             StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
-            StrCaseCmp(name, "system.dos_attr.c_time") == 0 ||
-            StrCaseCmp(name, "system.dos_attr.a_time") == 0 ||
-            StrCaseCmp(name, "system.dos_attr.m_time") == 0) {
+            (attr_strings.create_time_attr != NULL &&
+             StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
+            StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
+            StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
+            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;
@@ -5259,9 +5980,10 @@ smbc_setxattr_ctx(SMBCCTX *context,
 
                                 /* Set the new DOS attributes */
                                 ret2 = smbc_setatr(context, srv, path,
-                                                   dad->c_time,
-                                                   dad->a_time,
-                                                   dad->m_time,
+                                                   dad->create_time,
+                                                   dad->access_time,
+                                                   dad->write_time,
+                                                   dad->change_time,
                                                    dad->mode);
 
                                 /* ret2 has True (success) / False (failure) */
@@ -5275,13 +5997,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;
 }
 
@@ -5293,58 +6015,72 @@ 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;
+        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;
         POLICY_HND pol;
-
+        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,
+                ipc_srv = smbc_attr_server(frame, context, server, share,
+                                           &workgroup, &user, &password,
                                            &pol);
                 if (! ipc_srv) {
                         srv->no_nt_session = True;
@@ -5352,11 +6088,20 @@ smbc_getxattr_ctx(SMBCCTX *context,
         } 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) {
+                /* new-style names */
+                attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
+                attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
+                attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
+                attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
+        } else {
+                /* old-style names */
+                attr_strings.create_time_attr = NULL;
+                attr_strings.access_time_attr = "system.dos_attr.A_TIME";
+                attr_strings.write_time_attr = "system.dos_attr.M_TIME";
+                attr_strings.change_time_attr = "system.dos_attr.C_TIME";
         }
 
         /* Are they requesting a supported attribute? */
@@ -5379,13 +6124,15 @@ smbc_getxattr_ctx(SMBCCTX *context,
             StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 ||
             StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
             StrCaseCmp(name, "system.dos_attr.size") == 0 ||
-            StrCaseCmp(name, "system.dos_attr.c_time") == 0 ||
-            StrCaseCmp(name, "system.dos_attr.a_time") == 0 ||
-            StrCaseCmp(name, "system.dos_attr.m_time") == 0 ||
+            (attr_strings.create_time_attr != NULL &&
+             StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
+            StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
+            StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
+            StrCaseCmp(name, attr_strings.change_time_attr) == 0 ||
             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,
                                CONST_DISCARD(char *, name),
@@ -5393,13 +6140,13 @@ smbc_getxattr_ctx(SMBCCTX *context,
                 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;
 }
 
@@ -5410,82 +6157,88 @@ 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;
+        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;
         POLICY_HND pol;
+       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,
+                ipc_srv = smbc_attr_server(frame, context, server, share,
+                                           &workgroup, &user, &password,
                                            &pol);
-                srv->no_nt_session = True;
+                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,
+                ret = cacl_set(talloc_tos(), srv->cli,
                                ipc_srv->cli, &pol, path,
                                NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
-                talloc_destroy(ctx);
+               TALLOC_FREE(frame);
                 return ret;
         }
 
@@ -5502,16 +6255,16 @@ smbc_removexattr_ctx(SMBCCTX *context,
             StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
 
                 /* Yup. */
-                ret = cacl_set(ctx, srv->cli,
+                ret = cacl_set(talloc_tos(), srv->cli,
                                ipc_srv->cli, &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;
 }
 
@@ -5526,7 +6279,8 @@ 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...
          */
-        const char supported[] =
+        size_t retsize;
+        const char supported_old[] =
                 "system.*\0"
                 "system.*+\0"
                 "system.nt_sec_desc.revision\0"
@@ -5545,19 +6299,48 @@ smbc_listxattr_ctx(SMBCCTX *context,
                 "system.dos_attr.a_time\0"
                 "system.dos_attr.m_time\0"
                 ;
+        const char supported_new[] =
+                "system.*\0"
+                "system.*+\0"
+                "system.nt_sec_desc.revision\0"
+                "system.nt_sec_desc.owner\0"
+                "system.nt_sec_desc.owner+\0"
+                "system.nt_sec_desc.group\0"
+                "system.nt_sec_desc.group+\0"
+                "system.nt_sec_desc.acl.*\0"
+                "system.nt_sec_desc.acl\0"
+                "system.nt_sec_desc.acl+\0"
+                "system.nt_sec_desc.*\0"
+                "system.nt_sec_desc.*+\0"
+                "system.dos_attr.*\0"
+                "system.dos_attr.mode\0"
+                "system.dos_attr.create_time\0"
+                "system.dos_attr.access_time\0"
+                "system.dos_attr.write_time\0"
+                "system.dos_attr.change_time\0"
+                ;
+        const char * supported;
+
+        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;
 }
 
 
@@ -5569,45 +6352,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);
 }
 
 /*
@@ -5629,11 +6414,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;
 
         }
@@ -5641,39 +6428,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;
 
                 }
@@ -5682,16 +6470,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;
 
 }
@@ -5705,62 +6495,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;
 
 }
@@ -5774,51 +6572,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 */
 
         }
@@ -5829,16 +6637,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)
@@ -5862,7 +6672,6 @@ smbc_new_context(void)
 
         ZERO_STRUCTP(context->internal);
 
-        
         /* ADD REASONABLE DEFAULTS */
         context->debug            = 0;
         context->timeout          = 20000; /* 20 seconds */
@@ -5870,6 +6679,8 @@ smbc_new_context(void)
        context->options.browse_max_lmb_count      = 3;    /* # LMBs to query */
        context->options.urlencode_readdir_entries = False;/* backward compat */
        context->options.one_share_per_server      = False;/* backward compat */
+        context->internal->_share_mode             = SMBC_SHAREMODE_DENY_NONE;
+                                /* backward compat */
 
         context->open                              = smbc_open_ctx;
         context->creat                             = smbc_creat_ctx;
@@ -5909,10 +6720,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.
  *
  */
@@ -5924,14 +6735,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;
@@ -5947,8 +6758,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);
@@ -5958,8 +6769,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;
@@ -5976,14 +6787,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);
@@ -6005,9 +6816,11 @@ smbc_option_set(SMBCCTX *context,
 {
         va_list ap;
         union {
-                BOOL b;
+                int i;
+                bool b;
                 smbc_get_auth_data_with_context_fn auth_fn;
                 void *v;
+               const char *s;
         } option_value;
 
         va_start(ap, option_name);
@@ -6016,27 +6829,29 @@ 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, "debug_to_stderr") == 0) {
+        } else if (strcmp(option_name, "full_time_names") == 0) {
                 /*
-                 * Log to standard error instead of standard output.
-                 *
-                 * This function used to take a third parameter,
-                 * void *option_value.  Since it was a void* and we needed to
-                 * pass a boolean, a boolean value was cast to void* to be
-                 * passed in.  Now that we're using a va_list to retrieve the
-                 * parameters, the casting kludge is unnecessary.
-                 *
-                 * WARNING: DO NOT USE THIS OPTION.
-                 * This option is retained for backward compatibility.  New
-                 * applications should use "debug_to_stderr" and properly pass
-                 * in a boolean (int) value.
+                 * Use new-style time attribute names, e.g. WRITE_TIME rather
+                 * than the old-style names such as M_TIME.  This allows also
+                 * setting/getting CREATE_TIME which was previously
+                 * unimplemented.  (Note that the old C_TIME was supposed to
+                 * be CHANGE_TIME but was confused and sometimes referred to
+                 * CREATE_TIME.)
                  */
-                option_value.v = va_arg(ap, void *);
-                context->internal->_debug_stderr =
-                        (option_value.v == NULL ? False : True);
+                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) {
+                /*
+                 * The share mode to use for files opened with
+                 * smbc_open_ctx().  The default is SMBC_SHAREMODE_DENY_NONE.
+                 */
+                option_value.i = va_arg(ap, int);
+                context->internal->_share_mode =
+                        (smbc_share_mode) option_value.i;
 
         } else if (strcmp(option_name, "auth_function") == 0) {
                 /*
@@ -6054,6 +6869,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);
@@ -6076,6 +6904,21 @@ smbc_option_get(SMBCCTX *context,
 #else
                return (void *) context->internal->_debug_stderr;
 #endif
+        } else if (strcmp(option_name, "full_time_names") == 0) {
+                /*
+                 * Use new-style time attribute names, e.g. WRITE_TIME rather
+                 * than the old-style names such as M_TIME.  This allows also
+                 * setting/getting CREATE_TIME which was previously
+                 * unimplemented.  (Note that the old C_TIME was supposed to
+                 * be CHANGE_TIME but was confused and sometimes referred to
+                 * CREATE_TIME.)
+                 */
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+               return (void *) (intptr_t) context->internal->_full_time_names;
+#else
+               return (void *) context->internal->_full_time_names;
+#endif
+
         } else if (strcmp(option_name, "auth_function") == 0) {
                 /*
                  * Use the new-style authentication function which includes
@@ -6088,6 +6931,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;
@@ -6095,7 +6967,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,
@@ -6104,7 +6976,6 @@ smbc_option_get(SMBCCTX *context,
 SMBCCTX *
 smbc_init_context(SMBCCTX *context)
 {
-        pstring conf;
         int pid;
         char *user = NULL;
         char *home = NULL;
@@ -6115,7 +6986,7 @@ smbc_init_context(SMBCCTX *context)
         }
 
         /* Do not initialise the same client twice */
-        if (context->internal->_initialized) { 
+        if (context->internal->_initialized) {
                 return 0;
         }
 
@@ -6134,11 +7005,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);
@@ -6148,66 +7020,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 */
@@ -6253,17 +7133,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;
 }