r6156: Fixes bug #2543. Properly cache anonmous username when reverting to anonymous...
[samba.git] / source / libsmb / libsmbclient.c
index 441ca96478bab4eefd76c1d50948c754aad515a0..3e8e604ab11488380f78c07e12aa8e66e7bd970e 100644 (file)
@@ -80,6 +80,9 @@ static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) {
        return False;
 }
 
+static int smbc_close_ctx(SMBCCTX *context, SMBCFILE *file);
+static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence);
+
 extern BOOL in_client;
 
 /*
@@ -555,6 +558,7 @@ SMBCSRV *smbc_server(SMBCCTX *context,
        int tried_reverse = 0;
         int port_try_first;
         int port_try_next;
+        const char *username_used;
   
        zero_ip(&ip);
        ZERO_STRUCT(c);
@@ -709,16 +713,26 @@ SMBCSRV *smbc_server(SMBCCTX *context,
                return NULL;
        }
 
-       if (!cli_session_setup(&c, username, 
+        username_used = username;
+
+       if (!cli_session_setup(&c, username_used, 
                               password, strlen(password),
                               password, strlen(password),
-                              workgroup) &&
-                       /* Try an anonymous login if it failed and this was allowed by flags. */
-                       ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) ||
-                       !cli_session_setup(&c, "", "", 1,"", 0, workgroup))) {
-               cli_shutdown(&c);
-               errno = EPERM;
-               return NULL;
+                              workgroup)) {
+                
+                /* Failed.  Try an anonymous login, if allowed by flags. */
+                username_used = "";
+
+                if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) ||
+                     !cli_session_setup(&c, username_used,
+                                        password, 1,
+                                        password, 0,
+                                        workgroup)) {
+
+                        cli_shutdown(&c);
+                        errno = EPERM;
+                        return NULL;
+                }
        }
 
        DEBUG(4,(" session setup ok\n"));
@@ -750,7 +764,7 @@ SMBCSRV *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, workgroup, username_used)) {
                int saved_errno = errno;
                DEBUG(3, (" Failed to add server to cache\n"));
                errno = saved_errno;
@@ -968,6 +982,37 @@ static SMBCFILE *smbc_open_ctx(SMBCCTX *context, const char *fname, int flags, m
                file->file    = True;
 
                DLIST_ADD(context->internal->_files, file);
+
+                /*
+                 * If the file was opened in O_APPEND mode, all write
+                 * operations should be appended to the file.  To do that,
+                 * though, using this protocol, would require a getattrE()
+                 * call for each and every write, to determine where the end
+                 * of the file is. (There does not appear to be an append flag
+                 * in the protocol.)  Rather than add all of that overhead of
+                 * retrieving the current end-of-file offset prior to each
+                 * write operation, we'll assume that most append operations
+                 * will continuously write, so we'll just set the offset to
+                 * the end of the file now and hope that's adequate.
+                 *
+                 * Note to self: If this proves inadequate, and O_APPEND
+                 * should, in some cases, be forced for each write, add a
+                 * field in the context options structure, for
+                 * "strict_append_mode" which would select between the current
+                 * behavior (if FALSE) or issuing a getattrE() prior to each
+                 * write and forcing the write to the end of the file (if
+                 * TRUE).  Adding that capability will likely require adding
+                 * an "append" flag into the _SMBCFILE structure to track
+                 * whether a file was opened in O_APPEND mode.  -- djl
+                 */
+                if (flags & O_APPEND) {
+                        if (smbc_lseek_ctx(context, file, 0, SEEK_END) < 0) {
+                                (void) smbc_close_ctx(context, file);
+                                errno = ENXIO;
+                                return NULL;
+                        }
+                }
+
                return file;
 
        }
@@ -1017,6 +1062,17 @@ static ssize_t smbc_read_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t
 {
        int ret;
 
+        /*
+         * offset:
+         *
+         * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
+         * appears to pass file->offset (which is type off_t) differently than
+         * a local variable of type off_t.  Using local variable "offset" in
+         * the call to cli_read() instead of file->offset fixes a problem
+         * retrieving data at an offset greater than 4GB.
+         */
+        off_t offset = file->offset;
+
        if (!context || !context->internal ||
            !context->internal->_initialized) {
 
@@ -1043,7 +1099,7 @@ static ssize_t smbc_read_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t
 
        }
 
-       ret = cli_read(&file->srv->cli, file->cli_fd, buf, file->offset, count);
+       ret = cli_read(&file->srv->cli, file->cli_fd, buf, offset, count);
 
        if (ret < 0) {
 
@@ -1067,6 +1123,7 @@ static ssize_t smbc_read_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t
 static ssize_t smbc_write_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t count)
 {
        int ret;
+        off_t offset = file->offset; /* See "offset" comment in smbc_read_ctx() */
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
@@ -1092,7 +1149,7 @@ static ssize_t smbc_write_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_
 
        }
 
-       ret = cli_write(&file->srv->cli, file->cli_fd, 0, buf, file->offset, count);
+       ret = cli_write(&file->srv->cli, file->cli_fd, 0, buf, offset, count);
 
        if (ret <= 0) {
 
@@ -1165,7 +1222,7 @@ static int smbc_close_ctx(SMBCCTX *context, SMBCFILE *file)
  * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
  */
 static BOOL smbc_getatr(SMBCCTX * context, SMBCSRV *srv, char *path, 
-                uint16 *mode, size_t *size, 
+                uint16 *mode, SMB_OFF_T *size, 
                 time_t *c_time, time_t *a_time, time_t *m_time,
                 SMB_INO_T *ino)
 {
@@ -1272,7 +1329,7 @@ static int smbc_unlink_ctx(SMBCCTX *context, const char *fname)
                if (errno == EACCES) { /* Check if the file is a directory */
 
                        int saverr = errno;
-                       size_t size = 0;
+                       SMB_OFF_T size = 0;
                        uint16 mode = 0;
                        time_t m_time = 0, a_time = 0, c_time = 0;
                        SMB_INO_T ino = 0;
@@ -1396,7 +1453,7 @@ static int smbc_rename_ctx(SMBCCTX *ocontext, const char *oname,
 
 static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence)
 {
-       size_t size;
+       SMB_OFF_T size;
 
        if (!context || !context->internal ||
            !context->internal->_initialized) {
@@ -1482,7 +1539,8 @@ ino_t smbc_inode(SMBCCTX *context, const char *name)
  */
 
 static
-int smbc_setup_stat(SMBCCTX *context, struct stat *st, char *fname, size_t size, int mode)
+int smbc_setup_stat(SMBCCTX *context, struct stat *st, char *fname,
+                    SMB_OFF_T size, int mode)
 {
        
        st->st_mode = 0;
@@ -1532,7 +1590,7 @@ static int smbc_stat_ctx(SMBCCTX *context, const char *fname, struct stat *st)
        fstring server, share, user, password, workgroup;
        pstring path;
        time_t m_time = 0, a_time = 0, c_time = 0;
-       size_t size = 0;
+       SMB_OFF_T size = 0;
        uint16 mode = 0;
        SMB_INO_T ino = 0;
 
@@ -1602,7 +1660,7 @@ static int smbc_stat_ctx(SMBCCTX *context, const char *fname, struct stat *st)
 static int smbc_fstat_ctx(SMBCCTX *context, SMBCFILE *file, struct stat *st)
 {
        time_t c_time, a_time, m_time;
-       size_t size;
+       SMB_OFF_T size;
        uint16 mode;
        SMB_INO_T ino = 0;
 
@@ -1629,15 +1687,12 @@ static int smbc_fstat_ctx(SMBCCTX *context, SMBCFILE *file, struct stat *st)
 
        if (!cli_qfileinfo(&file->srv->cli, file->cli_fd,
                           &mode, &size, &c_time, &a_time, &m_time, NULL, &ino)) {
-           SMB_BIG_UINT b_size = size;
            if (!cli_getattrE(&file->srv->cli, file->cli_fd,
-                         &mode, &b_size, &c_time, &a_time, &m_time)) {
+                         &mode, &size, &c_time, &a_time, &m_time)) {
 
                errno = EINVAL;
                return -1;
-           } else
-               size = b_size;
-
+           }
        }
 
        st->st_ino = ino;
@@ -1960,7 +2015,7 @@ static SMBCFILE *smbc_opendir_ctx(SMBCCTX *context, const char *fname)
                 }
 
                 for (i = 0; i < count && i < max_lmb_count; i++) {
-                        DEBUG(99, ("Found master browser %s\n", inet_ntoa(ip_list[i].ip)));
+                        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 
@@ -1983,12 +2038,7 @@ static SMBCFILE *smbc_opendir_ctx(SMBCCTX *context, const char *fname)
                         srv = smbc_server(context, server,
                                           "IPC$", workgroup, user, password);
                         if (!srv) {
-                                
-                                if (dir) {
-                                        SAFE_FREE(dir->fname);
-                                        SAFE_FREE(dir);
-                                }
-                                return NULL;
+                                continue;
                         }
                 
                         dir->srv = srv;
@@ -1999,13 +2049,7 @@ static SMBCFILE *smbc_opendir_ctx(SMBCCTX *context, const char *fname)
                         if (!cli_NetServerEnum(&srv->cli, workgroup, SV_TYPE_DOMAIN_ENUM, list_unique_wg_fn,
                                                (void *)dir)) {
                                 
-                                if (dir) {
-                                        SAFE_FREE(dir->fname);
-                                        SAFE_FREE(dir);
-                                }
-                                
-                                return NULL;
-                                
+                                continue;
                         }
                 }
         } else { 
@@ -3233,7 +3277,7 @@ static DOS_ATTR_DESC *dos_attr_query(SMBCCTX *context,
                                      SMBCSRV *srv)
 {
         time_t m_time = 0, a_time = 0, c_time = 0;
-        size_t size = 0;
+        SMB_OFF_T size = 0;
         uint16 mode = 0;
        SMB_INO_T inode = 0;
         DOS_ATTR_DESC *ret;
@@ -3245,7 +3289,8 @@ static DOS_ATTR_DESC *dos_attr_query(SMBCCTX *context,
         }
 
         /* Obtain the DOS attributes */
-        if (!smbc_getatr(context, srv, filename, &mode, &size, 
+        if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename),
+                         &mode, &size, 
                          &c_time, &a_time, &m_time, &inode)) {
         
                 errno = smbc_errno(context, &srv->cli);
@@ -3314,42 +3359,124 @@ retrieve the acls for a file
 *******************************************************/
 static int cacl_get(SMBCCTX *context, TALLOC_CTX *ctx, SMBCSRV *srv,
                     struct cli_state *ipc_cli, POLICY_HND *pol,
-                    char *filename, char *name, char *buf, int bufsize)
+                    char *filename, char *attr_name, char *buf, int bufsize)
 {
        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);
        int fnum = -1;
        SEC_DESC *sd;
        fstring sidstr;
+        fstring name_sandbox;
+        char *name;
+        char *pExclude;
         char *p;
        time_t m_time = 0, a_time = 0, c_time = 0;
-       size_t size = 0;
+       SMB_OFF_T size = 0;
        uint16 mode = 0;
        SMB_INO_T ino = 0;
         struct cli_state *cli = &srv->cli;
 
+        /* Copy name so we can strip off exclusions (if any are specified) */
+        strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1);
+
+        /* Ensure name is null terminated */
+        name_sandbox[sizeof(name_sandbox) - 1] = '\0';
+
+        /* Play in the sandbox */
+        name = name_sandbox;
+
+        /* If there are any exclusions, point to them and mask them from name */
+        if ((pExclude = strchr(name, '!')) != NULL)
+        {
+                *pExclude++ = '\0';
+        }
+
         all = (StrnCaseCmp(name, "system.*", 8) == 0);
         all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0);
+        all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0);
         all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0);
         some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0);
         some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0);
         numeric = (* (name + strlen(name) - 1) != '+');
 
+        /* Look for exclusions from "all" requests */
+        if (all || all_nt || all_dos) {
+
+                /* Exclusions are delimited by '!' */
+                for (; pExclude != NULL; pExclude = (p == NULL ? NULL : p + 1)) {
+
+                /* Find end of this exclusion name */
+                if ((p = strchr(pExclude, '!')) != NULL)
+                {
+                    *p = '\0';
+                }
+
+                /* Which exclusion name is this? */
+                if (StrCaseCmp(pExclude, "nt_sec_desc.revision") == 0) {
+                    exclude_nt_revision = True;
+                }
+                else if (StrCaseCmp(pExclude, "nt_sec_desc.owner") == 0) {
+                    exclude_nt_owner = True;
+                }
+                else if (StrCaseCmp(pExclude, "nt_sec_desc.group") == 0) {
+                    exclude_nt_group = True;
+                }
+                else if (StrCaseCmp(pExclude, "nt_sec_desc.acl") == 0) {
+                    exclude_nt_acl = True;
+                }
+                else if (StrCaseCmp(pExclude, "dos_attr.mode") == 0) {
+                    exclude_dos_mode = True;
+                }
+                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 (StrCaseCmp(pExclude, "dos_attr.a_time") == 0) {
+                    exclude_dos_atime = True;
+                }
+                else if (StrCaseCmp(pExclude, "dos_attr.m_time") == 0) {
+                    exclude_dos_mtime = True;
+                }
+                else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) {
+                    exclude_dos_inode = True;
+                }
+                else {
+                    DEBUG(5, ("cacl_get received unknown exclusion: %s\n",
+                              pExclude));
+                    errno = ENOATTR;
+                    return -1;
+                }
+            }
+        }
+
         n_used = 0;
 
         /*
          * If we are (possibly) talking to an NT or new system and some NT
          * attributes have been requested...
          */
-        if (ipc_cli && (all || some_nt)) {
+        if (ipc_cli && (all || some_nt || all_nt_acls)) {
                 /* Point to the portion after "system.nt_sec_desc." */
                 name += 19;     /* if (all) this will be invalid but unused */
 
@@ -3374,139 +3501,105 @@ static int cacl_get(SMBCCTX *context, TALLOC_CTX *ctx, SMBCSRV *srv,
 
                 cli_close(cli, fnum);
 
-                if (all || all_nt) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    "REVISION:%d",
-                                                    sd->revision);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                if (! exclude_nt_revision) {
+                        if (all || all_nt) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx,
+                                                            "REVISION:%d",
+                                                            sd->revision);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     "REVISION:%d", sd->revision);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             "REVISION:%d", sd->revision);
-                        }
-                } else if (StrCaseCmp(name, "revision") == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, "%d", sd->revision);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrCaseCmp(name, "revision") == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, "%d",
+                                                            sd->revision);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize, "%d",
+                                                     sd->revision);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize, "%d", sd->revision);
                         }
-                }
         
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
-                }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
-
-                /* Get owner and group sid */
-
-                if (sd->owner_sid) {
-                        convert_sid_to_string(ipc_cli, pol,
-                                              sidstr, numeric, sd->owner_sid);
-                } else {
-                        fstrcpy(sidstr, "");
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
 
-                if (all || all_nt) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, ",OWNER:%s", sidstr);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
-                                }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             ",OWNER:%s", sidstr);
-                        }
-                } else if (StrnCaseCmp(name, "owner", 5) == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, "%s", sidstr);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
-                                }
-                                n = strlen(p);
+                if (! exclude_nt_owner) {
+                        /* Get owner and group sid */
+                        if (sd->owner_sid) {
+                                convert_sid_to_string(ipc_cli, pol,
+                                                      sidstr,
+                                                      numeric,
+                                                      sd->owner_sid);
                         } else {
-                                n = snprintf(buf, bufsize, "%s", sidstr);
+                                fstrcpy(sidstr, "");
                         }
-                }
-
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
-                }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
 
-                if (sd->grp_sid) {
-                        convert_sid_to_string(ipc_cli, pol,
-                                              sidstr, numeric, sd->grp_sid);
-                } else {
-                        fstrcpy(sidstr, "");
-                }
-
-                if (all || all_nt) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, ",GROUP:%s", sidstr);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        if (all || all_nt) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, ",OWNER:%s",
+                                                            sidstr);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     ",OWNER:%s", sidstr);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             ",GROUP:%s", sidstr);
-                        }
-                } else if (StrnCaseCmp(name, "group", 5) == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, "%s", sidstr);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrnCaseCmp(name, "owner", 5) == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, "%s", sidstr);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize, "%s",
+                                                     sidstr);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize, "%s", sidstr);
                         }
-                }
 
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
-
-                /* Add aces to value buffer  */
-                for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
 
-                        SEC_ACE *ace = &sd->dacl->ace[i];
-                        convert_sid_to_string(ipc_cli, pol,
-                                              sidstr, numeric, &ace->trustee);
+                if (! exclude_nt_group) {
+                        if (sd->grp_sid) {
+                                convert_sid_to_string(ipc_cli, pol,
+                                                      sidstr, numeric,
+                                                      sd->grp_sid);
+                        } else {
+                                fstrcpy(sidstr, "");
+                        }
 
                         if (all || all_nt) {
                                 if (determine_size) {
-                                        p = talloc_asprintf(ctx, 
-                                                            ",ACL:"
-                                                            "%s:%d/%d/0x%08x", 
-                                                            sidstr,
-                                                            ace->type,
-                                                            ace->flags,
-                                                            ace->info.mask);
+                                        p = talloc_asprintf(ctx, ",GROUP:%s",
+                                                            sidstr);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
@@ -3514,36 +3607,22 @@ static int cacl_get(SMBCCTX *context, TALLOC_CTX *ctx, SMBCSRV *srv,
                                         n = strlen(p);
                                 } else {
                                         n = snprintf(buf, bufsize,
-                                                     ",ACL:%s:%d/%d/0x%08x", 
-                                                     sidstr,
-                                                     ace->type,
-                                                     ace->flags,
-                                                     ace->info.mask);
+                                                     ",GROUP:%s", sidstr);
                                 }
-                        } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
-                                    StrCaseCmp(name + 3, sidstr) == 0) ||
-                                   (StrnCaseCmp(name, "acl+", 4) == 0 &&
-                                    StrCaseCmp(name + 4, sidstr) == 0)) {
+                        } else if (StrnCaseCmp(name, "group", 5) == 0) {
                                 if (determine_size) {
-                                        p = talloc_asprintf(ctx, 
-                                                            "%d/%d/0x%08x", 
-                                                            ace->type,
-                                                            ace->flags,
-                                                            ace->info.mask);
+                                        p = talloc_asprintf(ctx, "%s", sidstr);
                                         if (!p) {
                                                 errno = ENOMEM;
                                                 return -1;
                                         }
                                         n = strlen(p);
                                 } else {
-                                        n = snprintf(buf, bufsize,
-                                                     "%d/%d/0x%08x", 
-                                                     ace->type,
-                                                     ace->flags,
-                                                     ace->info.mask);
+                                        n = snprintf(buf, bufsize, "%s", sidstr);
                                 }
                         }
-                        if (n > bufsize) {
+
+                        if (!determine_size && n > bufsize) {
                                 errno = ERANGE;
                                 return -1;
                         }
@@ -3552,6 +3631,97 @@ static int cacl_get(SMBCCTX *context, TALLOC_CTX *ctx, SMBCSRV *srv,
                         bufsize -= n;
                 }
 
+                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];
+                                convert_sid_to_string(ipc_cli, pol,
+                                                      sidstr, numeric,
+                                                      &ace->trustee);
+
+                                if (all || all_nt) {
+                                        if (determine_size) {
+                                                p = talloc_asprintf(
+                                                        ctx, 
+                                                        ",ACL:"
+                                                        "%s:%d/%d/0x%08x", 
+                                                        sidstr,
+                                                        ace->type,
+                                                        ace->flags,
+                                                        ace->info.mask);
+                                                if (!p) {
+                                                        errno = ENOMEM;
+                                                        return -1;
+                                                }
+                                                n = strlen(p);
+                                        } else {
+                                                n = snprintf(
+                                                        buf, bufsize,
+                                                        ",ACL:%s:%d/%d/0x%08x", 
+                                                        sidstr,
+                                                        ace->type,
+                                                        ace->flags,
+                                                        ace->info.mask);
+                                        }
+                                } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
+                                            StrCaseCmp(name + 3, sidstr) == 0) ||
+                                           (StrnCaseCmp(name, "acl+", 4) == 0 &&
+                                            StrCaseCmp(name + 4, sidstr) == 0)) {
+                                        if (determine_size) {
+                                                p = talloc_asprintf(
+                                                        ctx, 
+                                                        "%d/%d/0x%08x", 
+                                                        ace->type,
+                                                        ace->flags,
+                                                        ace->info.mask);
+                                                if (!p) {
+                                                        errno = ENOMEM;
+                                                        return -1;
+                                                }
+                                                n = strlen(p);
+                                        } else {
+                                                n = snprintf(buf, bufsize,
+                                                             "%d/%d/0x%08x", 
+                                                             ace->type,
+                                                             ace->flags,
+                                                             ace->info.mask);
+                                        }
+                                } else if (all_nt_acls) {
+                                        if (determine_size) {
+                                                p = talloc_asprintf(
+                                                        ctx, 
+                                                        "%s%s:%d/%d/0x%08x",
+                                                        i ? "," : "",
+                                                        sidstr,
+                                                        ace->type,
+                                                        ace->flags,
+                                                        ace->info.mask);
+                                                if (!p) {
+                                                        errno = ENOMEM;
+                                                        return -1;
+                                                }
+                                                n = strlen(p);
+                                        } else {
+                                                n = snprintf(buf, bufsize,
+                                                             "%s%s:%d/%d/0x%08x",
+                                                             i ? "," : "",
+                                                             sidstr,
+                                                             ace->type,
+                                                             ace->flags,
+                                                             ace->info.mask);
+                                        }
+                                }
+                                if (n > bufsize) {
+                                        errno = ERANGE;
+                                        return -1;
+                                }
+                                buf += n;
+                                n_used += n;
+                                bufsize -= n;
+                        }
+                }
+
                 /* Restore name pointer to its original value */
                 name -= 19;
         }
@@ -3569,231 +3739,250 @@ static int cacl_get(SMBCCTX *context, TALLOC_CTX *ctx, SMBCSRV *srv,
                         
                 }
                 
-                if (all || all_dos) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    "%sMODE:0x%x",
-                                                    (ipc_cli &&
-                                                     (all || some_nt)
-                                                     ? ","
-                                                     : ""),
-                                                    mode);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                if (! exclude_dos_mode) {
+                        if (all || all_dos) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx,
+                                                            "%sMODE:0x%x",
+                                                            (ipc_cli &&
+                                                             (all || some_nt)
+                                                             ? ","
+                                                             : ""),
+                                                            mode);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     "%sMODE:0x%x",
+                                                     (ipc_cli &&
+                                                      (all || some_nt)
+                                                      ? ","
+                                                      : ""),
+                                                     mode);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             "%sMODE:0x%x",
-                                             (ipc_cli &&
-                                              (all || some_nt)
-                                              ? ","
-                                              : ""),
-                                             mode);
-                        }
-                } else if (StrCaseCmp(name, "mode") == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, "0x%x", mode);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrCaseCmp(name, "mode") == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, "0x%x", mode);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize, "0x%x", mode);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize, "0x%x", mode);
                         }
-                }
         
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
-
-                if (all || all_dos) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    ",SIZE:%llu",
-                                                    (unsigned long long) size);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+
+                if (! exclude_dos_size) {
+                        if (all || all_dos) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(
+                                                ctx,
+                                                ",SIZE:%llu",
+                                                (unsigned long long) size);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     ",SIZE:%llu",
+                                                     (unsigned long long) size);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             ",SIZE:%llu",
-                                             (unsigned long long) size);
-                        }
-                } else if (StrCaseCmp(name, "size") == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    "%llu",
-                                                    (unsigned long long) size);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrCaseCmp(name, "size") == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(
+                                                ctx,
+                                                "%llu",
+                                                (unsigned long long) size);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     "%llu",
+                                                     (unsigned long long) size);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             "%llu",
-                                             (unsigned long long) size);
                         }
-                }
         
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
-
-                if (all || all_dos) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    ",C_TIME:%lu", c_time);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+
+                if (! exclude_dos_ctime) {
+                        if (all || all_dos) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx,
+                                                            ",C_TIME:%lu",
+                                                            c_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     ",C_TIME:%lu", c_time);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             ",C_TIME:%lu", c_time);
-                        }
-                } else if (StrCaseCmp(name, "c_time") == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, "%lu", c_time);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrCaseCmp(name, "c_time") == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, "%lu", c_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize, "%lu", c_time);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize, "%lu", c_time);
                         }
-                }
         
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
-
-                if (all || all_dos) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    ",A_TIME:%lu", a_time);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+
+                if (! exclude_dos_atime) {
+                        if (all || all_dos) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx,
+                                                            ",A_TIME:%lu",
+                                                            a_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     ",A_TIME:%lu", a_time);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             ",A_TIME:%lu", a_time);
-                        }
-                } else if (StrCaseCmp(name, "a_time") == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, "%lu", a_time);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrCaseCmp(name, "a_time") == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, "%lu", a_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize, "%lu", a_time);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize, "%lu", a_time);
                         }
-                }
         
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
-
-                if (all || all_dos) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    ",M_TIME:%lu", m_time);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+
+                if (! exclude_dos_mtime) {
+                        if (all || all_dos) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx,
+                                                            ",M_TIME:%lu",
+                                                            m_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     ",M_TIME:%lu", m_time);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             ",M_TIME:%lu", m_time);
-                        }
-                } else if (StrCaseCmp(name, "m_time") == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx, "%lu", m_time);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrCaseCmp(name, "m_time") == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(ctx, "%lu", m_time);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize, "%lu", m_time);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize, "%lu", m_time);
                         }
-                }
         
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
-
-                if (all || all_dos) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    ",INODE:%llu",
-                                                    (unsigned long long) ino);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+
+                if (! exclude_dos_inode) {
+                        if (all || all_dos) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(
+                                                ctx,
+                                                ",INODE:%llu",
+                                                (unsigned long long) ino);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     ",INODE:%llu",
+                                                     (unsigned long long) ino);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             ",INODE:%llu",
-                                             (unsigned long long) ino);
-                        }
-                } else if (StrCaseCmp(name, "inode") == 0) {
-                        if (determine_size) {
-                                p = talloc_asprintf(ctx,
-                                                    "%llu",
-                                                    (unsigned long long) ino);
-                                if (!p) {
-                                        errno = ENOMEM;
-                                        return -1;
+                        } else if (StrCaseCmp(name, "inode") == 0) {
+                                if (determine_size) {
+                                        p = talloc_asprintf(
+                                                ctx,
+                                                "%llu",
+                                                (unsigned long long) ino);
+                                        if (!p) {
+                                                errno = ENOMEM;
+                                                return -1;
+                                        }
+                                        n = strlen(p);
+                                } else {
+                                        n = snprintf(buf, bufsize,
+                                                     "%llu",
+                                                     (unsigned long long) ino);
                                 }
-                                n = strlen(p);
-                        } else {
-                                n = snprintf(buf, bufsize,
-                                             "%llu",
-                                             (unsigned long long) ino);
                         }
-                }
         
-                if (!determine_size && n > bufsize) {
-                        errno = ERANGE;
-                        return -1;
+                        if (!determine_size && n > bufsize) {
+                                errno = ERANGE;
+                                return -1;
+                        }
+                        buf += n;
+                        n_used += n;
+                        bufsize -= n;
                 }
-                buf += n;
-                n_used += n;
-                bufsize -= n;
 
                 /* Restore name pointer to its original value */
                 name -= 16;
@@ -3840,7 +4029,8 @@ static int cacl_set(TALLOC_CTX *ctx, struct cli_state *cli,
                         the_acl = p + 1;
                 }
 
-                sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, the_acl);
+                sd = sec_desc_parse(ctx, ipc_cli, pol, numeric,
+                                    CONST_DISCARD(char *, the_acl));
 
                 if (!sd) {
                         errno = EINVAL;
@@ -4094,7 +4284,6 @@ int smbc_setxattr_ctx(SMBCCTX *context,
                         dos_attr_parse(context, dad, srv, namevalue);
 
                         /* Set the new DOS attributes */
-#warning "Should try Set Path Info first, but it's not yet implemented"
 #if 0                           /* not yet implemented */
                         if (! cli_setpathinfo(&srv->cli, path,
                                               dad->c_time,
@@ -4233,7 +4422,6 @@ int smbc_setxattr_ctx(SMBCCTX *context,
                                 dos_attr_parse(context, dad, srv, namevalue);
 
                                 /* Set the new DOS attributes */
-#warning "Should try Set Path Info first, but it's not yet implemented"
 #if 0                           /* not yet implemented */
                                 ret2 = cli_setpathinfo(&srv->cli, path,
                                                        dad->c_time,
@@ -4349,9 +4537,13 @@ int smbc_getxattr_ctx(SMBCCTX *context,
 
         /* Are they requesting a supported attribute? */
         if (StrCaseCmp(name, "system.*") == 0 ||
+            StrnCaseCmp(name, "system.*!", 9) == 0 ||
             StrCaseCmp(name, "system.*+") == 0 ||
+            StrnCaseCmp(name, "system.*+!", 10) == 0 ||
             StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
+            StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 ||
             StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
+            StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 ||
             StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
             StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
             StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
@@ -4360,6 +4552,7 @@ int smbc_getxattr_ctx(SMBCCTX *context,
             StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
             StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 ||
             StrCaseCmp(name, "system.dos_attr.*") == 0 ||
+            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 ||
@@ -4370,7 +4563,9 @@ int smbc_getxattr_ctx(SMBCCTX *context,
                 /* Yup. */
                 ret = cacl_get(context, ctx, srv,
                                ipc_srv == NULL ? NULL : &ipc_srv->cli, 
-                               &pol, path, name, (const char *) value, size);
+                               &pol, path,
+                               CONST_DISCARD(char *, name),
+                               CONST_DISCARD(char *, value), size);
                 if (ret < 0 && errno == 0) {
                         errno = smbc_errno(context, &srv->cli);
                 }
@@ -4509,6 +4704,7 @@ int smbc_listxattr_ctx(SMBCCTX *context,
                 "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"
@@ -4984,10 +5180,25 @@ SMBCCTX * smbc_init_context(SMBCCTX * context)
                          * defaults ...
                          */
 
-                   if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
-                      DEBUG(5, ("Could not load either config file: %s or %s\n",
-                             conf, dyn_CONFIGFILE));
-                   }
+                        if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
+                                DEBUG(5, ("Could not load either config file: "
+                                          "%s or %s\n",
+                                          conf, dyn_CONFIGFILE));
+                        } else {
+                                /*
+                                 * 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)) {
+                                        DEBUG(10,
+                                              ("Could not append config file: "
+                                               "%s\n",
+                                               conf));
+                                }
+                        }
                 }
 
                 reopen_logs();  /* Get logging working ... */