Merge branch 'master' of ssh://git.samba.org/data/git/samba into singlelib
authorJelmer Vernooij <jelmer@samba.org>
Wed, 17 Sep 2008 12:34:54 +0000 (14:34 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Wed, 17 Sep 2008 12:34:54 +0000 (14:34 +0200)
19 files changed:
source3/Makefile.in
source3/configure.in
source3/include/ads.h
source3/include/nss_info.h
source3/libads/ldap_schema.c
source3/modules/vfs_acl_xattr.c [new file with mode: 0644]
source3/winbindd/idmap_ad.c
source3/winbindd/idmap_hash/idmap_hash.c [new file with mode: 0644]
source3/winbindd/idmap_hash/idmap_hash.h [new file with mode: 0644]
source3/winbindd/idmap_hash/mapfile.c [new file with mode: 0644]
source3/winbindd/nss_info.c
source3/winbindd/nss_info_template.c
source3/winbindd/winbindd_cache.c
source3/winbindd/winbindd_group.c
source3/winbindd/winbindd_pam.c
source3/winbindd/winbindd_proto.h
source3/winbindd/winbindd_rpc.c
source3/winbindd/winbindd_user.c
source3/winbindd/winbindd_util.c

index 032efd53a3a259e45f4362be1e5640c0005d2df4..1b0624a304869380d4c0dbe2eb0e93e11982873c 100644 (file)
@@ -618,6 +618,7 @@ VFS_TSMSM_OBJ = modules/vfs_tsmsm.o
 VFS_FILEID_OBJ = modules/vfs_fileid.o
 VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o
 VFS_SYNCOPS_OBJ = modules/vfs_syncops.o
+VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
@@ -979,6 +980,10 @@ IDMAP_OBJ     = winbindd/idmap.o winbindd/idmap_util.o @IDMAP_STATIC@
 
 NSS_INFO_OBJ = winbindd/nss_info.o @NSS_INFO_STATIC@
 
+IDMAP_HASH_OBJ = \
+               winbindd/idmap_hash/idmap_hash.o \
+               winbindd/idmap_hash/mapfile.o
+
 WINBINDD_OBJ1 = \
                winbindd/winbindd.o       \
                winbindd/winbindd_user.o  \
@@ -2208,6 +2213,10 @@ bin/ad.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_ad.o
        @echo "Building plugin $@"
        @$(SHLD_MODULE) winbindd/idmap_ad.o
 
+bin/hash.@SHLIBEXT@: $(BINARY_PREREQS) $(IDMAP_HASH_OBJ)
+       @echo "Building plugin $@"
+       @$(SHLD_MODULE) $(IDMAP_HASH_OBJ)
+
 bin/tdb2.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_tdb2.o
        @echo "Building plugin $@"
        @$(SHLD_MODULE) winbindd/idmap_tdb2.o
@@ -2375,6 +2384,10 @@ bin/aio_fork.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_FORK_OBJ)
        @echo "Building plugin $@"
        @$(SHLD_MODULE) $(VFS_AIO_FORK_OBJ)
 
+bin/acl_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ACL_XATTR_OBJ)
+       @echo "Building plugin $@"
+       @$(SHLD_MODULE) $(VFS_ACL_XATTR_OBJ)
+
 bin/registry.@SHLIBEXT@: $(BINARY_PREREQS) libgpo/gpext/registry.o
        @echo "Building plugin $@"
        @$(SHLD_MODULE) libgpo/gpext/registry.o
index 294092e7214a9cbd79c79529dda78aa6fd9e354c..92dbf6de2d62f211c674e1a8a16f03069a107d87 100644 (file)
@@ -6057,6 +6057,7 @@ SMB_MODULE(idmap_passdb, winbindd/idmap_passdb.o, "bin/passdb.$SHLIBEXT", IDMAP)
 SMB_MODULE(idmap_nss, winbindd/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP)
 SMB_MODULE(idmap_rid, winbindd/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
 SMB_MODULE(idmap_ad, winbindd/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_hash, \$(IDMAP_HASH_OBJ), "bin/hash.$SHLIBEXT", IDMAP)
 SMB_SUBSYSTEM(IDMAP, winbindd/idmap.o)
 
 SMB_MODULE(nss_info_template, winbindd/nss_info_template.o, "bin/template.$SHLIBEXT", NSS_INFO)
index 97faf0b6eb4515b9bc02e73284fe8531d456f09a..b72d25094025156108c6815f62c44c8a0b141867 100644 (file)
@@ -133,6 +133,7 @@ struct posix_schema {
        char *posix_uidnumber_attr;
        char *posix_gidnumber_attr;
        char *posix_gecos_attr;
+       char *posix_uid_attr;
 };
 
 
@@ -179,6 +180,7 @@ typedef void **ADS_MODLIST;
 #define ADS_ATTR_SFU_HOMEDIR_OID       "1.2.840.113556.1.6.18.1.344"
 #define ADS_ATTR_SFU_SHELL_OID                 "1.2.840.113556.1.6.18.1.312"
 #define ADS_ATTR_SFU_GECOS_OID                 "1.2.840.113556.1.6.18.1.337"
+#define ADS_ATTR_SFU_UID_OID            "1.2.840.113556.1.6.18.1.309"
 
 /* ldap attribute oids (Services for Unix 2.0) */
 #define ADS_ATTR_SFU20_UIDNUMBER_OID   "1.2.840.113556.1.4.7000.187.70"
@@ -186,6 +188,8 @@ typedef void **ADS_MODLIST;
 #define ADS_ATTR_SFU20_HOMEDIR_OID     "1.2.840.113556.1.4.7000.187.106"
 #define ADS_ATTR_SFU20_SHELL_OID       "1.2.840.113556.1.4.7000.187.72"
 #define ADS_ATTR_SFU20_GECOS_OID       "1.2.840.113556.1.4.7000.187.97"
+#define ADS_ATTR_SFU20_UID_OID          "1.2.840.113556.1.4.7000.187.102"
+
 
 /* ldap attribute oids (RFC2307) */
 #define ADS_ATTR_RFC2307_UIDNUMBER_OID "1.3.6.1.1.1.1.0"
@@ -193,6 +197,7 @@ typedef void **ADS_MODLIST;
 #define ADS_ATTR_RFC2307_HOMEDIR_OID   "1.3.6.1.1.1.1.3"
 #define ADS_ATTR_RFC2307_SHELL_OID     "1.3.6.1.1.1.1.4"
 #define ADS_ATTR_RFC2307_GECOS_OID     "1.3.6.1.1.1.1.2"
+#define ADS_ATTR_RFC2307_UID_OID        "0.9.2342.19200300.100.1.1"
 
 /* ldap bitwise searches */
 #define ADS_LDAP_MATCHING_RULE_BIT_AND "1.2.840.113556.1.4.803"
index 1ff9ebcd55945b91ca75c90a6b353883fedf25af..e756136b76ab062af280794c04aee0c6e79e8d3c 100644 (file)
@@ -66,6 +66,10 @@ struct nss_info_methods {
                                  TALLOC_CTX *ctx, 
                                  ADS_STRUCT *ads, LDAPMessage *msg,
                                  char **homedir, char **shell, char **gecos, gid_t *p_gid);
+       NTSTATUS (*map_to_alias)( TALLOC_CTX *mem_ctx, const char *domain,
+                                 const char *name, char **alias );
+       NTSTATUS (*map_from_alias)( TALLOC_CTX *mem_ctx, const char *domain,
+                                   const char *alias, char **name );
        NTSTATUS (*close_fn)( void );
 };
 
@@ -84,6 +88,12 @@ NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
                        char **homedir, char **shell, char **gecos,
                        gid_t *p_gid);
 
+NTSTATUS nss_map_to_alias( TALLOC_CTX *mem_ctx, const char *domain,
+                          const char *name, char **alias );
+
+NTSTATUS nss_map_from_alias( TALLOC_CTX *mem_ctx, const char *domain,
+                            const char *alias, char **name );
+
 NTSTATUS nss_close( const char *parameters );
 
 #endif /* _IDMAP_NSS_H_ */
index ff41ccc8614a7319d237219baf95aa3244e42df8..b5d2d35889e17d5c4402bdcee995c7c90de8ad14 100644 (file)
@@ -246,19 +246,22 @@ ADS_STATUS ads_check_posix_schema_mapping(TALLOC_CTX *mem_ctx,
                                        ADS_ATTR_SFU_GIDNUMBER_OID,
                                        ADS_ATTR_SFU_HOMEDIR_OID,
                                        ADS_ATTR_SFU_SHELL_OID,
-                                       ADS_ATTR_SFU_GECOS_OID};
+                                       ADS_ATTR_SFU_GECOS_OID,
+                                       ADS_ATTR_SFU_UID_OID };
 
        const char *oids_sfu20[] = {    ADS_ATTR_SFU20_UIDNUMBER_OID,
                                        ADS_ATTR_SFU20_GIDNUMBER_OID,
                                        ADS_ATTR_SFU20_HOMEDIR_OID,
                                        ADS_ATTR_SFU20_SHELL_OID,
-                                       ADS_ATTR_SFU20_GECOS_OID};
+                                       ADS_ATTR_SFU20_GECOS_OID,
+                                       ADS_ATTR_SFU20_UID_OID };
 
        const char *oids_rfc2307[] = {  ADS_ATTR_RFC2307_UIDNUMBER_OID,
                                        ADS_ATTR_RFC2307_GIDNUMBER_OID,
                                        ADS_ATTR_RFC2307_HOMEDIR_OID,
                                        ADS_ATTR_RFC2307_SHELL_OID,
-                                       ADS_ATTR_RFC2307_GECOS_OID };
+                                       ADS_ATTR_RFC2307_GECOS_OID,
+                                       ADS_ATTR_RFC2307_UID_OID };
 
        DEBUG(10,("ads_check_posix_schema_mapping for schema mode: %d\n", map_type));
 
@@ -359,6 +362,12 @@ ADS_STATUS ads_check_posix_schema_mapping(TALLOC_CTX *mem_ctx,
                    strequal(ADS_ATTR_SFU20_GECOS_OID, oids_out[i])) {
                        schema->posix_gecos_attr = talloc_strdup(schema, names_out[i]);
                }
+
+               if (strequal(ADS_ATTR_RFC2307_UID_OID, oids_out[i]) ||
+                   strequal(ADS_ATTR_SFU_UID_OID, oids_out[i]) ||
+                   strequal(ADS_ATTR_SFU20_UID_OID, oids_out[i])) {
+                       schema->posix_uid_attr = talloc_strdup(schema, names_out[i]);
+               }
        }
 
        if (!schema->posix_uidnumber_attr ||
diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c
new file mode 100644 (file)
index 0000000..31ffe34
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Store Windows ACLs in xattrs.
+ *
+ * Copyright (C) Volker Lendecke, 2008
+ * Copyright (C) Jeremy Allison, 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/xattr.h"
+#include "librpc/gen_ndr/ndr_xattr.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
+                               const struct timespec cts,
+                               uint32 security_info,
+                               struct security_descriptor **ppdesc)
+{
+       TALLOC_CTX *ctx = talloc_tos();
+       struct xattr_NTACL xacl;
+       enum ndr_err_code ndr_err;
+       size_t sd_size;
+       struct timespec ts;
+
+       ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
+                       (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
+
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
+                       ndr_errstr(ndr_err)));
+               return ndr_map_error2ntstatus(ndr_err);;
+       }
+
+       if (xacl.version != 2) {
+               return NT_STATUS_REVISION_MISMATCH;
+       }
+
+       /*
+        * Check that the ctime timestamp is ealier
+        * than the stored timestamp.
+        */
+
+       ts = nt_time_to_unix_timespec(&xacl.info.sd_ts->last_changed);
+
+       if (timespec_compare(&cts, &ts) > 0) {
+               DEBUG(5, ("parse_acl_blob: stored ACL out of date.\n"));
+               return NT_STATUS_EA_CORRUPT_ERROR;
+       }
+
+       *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+                       (security_info & OWNER_SECURITY_INFORMATION)
+                       ? xacl.info.sd_ts->sd->owner_sid : NULL,
+                       (security_info & GROUP_SECURITY_INFORMATION)
+                       ? xacl.info.sd_ts->sd->group_sid : NULL,
+                       (security_info & SACL_SECURITY_INFORMATION)
+                       ? xacl.info.sd_ts->sd->sacl : NULL,
+                       (security_info & DACL_SECURITY_INFORMATION)
+                       ? xacl.info.sd_ts->sd->dacl : NULL,
+                       &sd_size);
+
+       TALLOC_FREE(xacl.info.sd);
+
+       return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
+}
+
+static NTSTATUS get_acl_blob(vfs_handle_struct *handle,
+                       TALLOC_CTX *ctx,
+                       files_struct *fsp,
+                       const char *name,
+                       DATA_BLOB *pblob)
+{
+       size_t size = 1024;
+       uint8_t *val = NULL;
+       uint8_t *tmp;
+       ssize_t sizeret;
+       int saved_errno;
+
+       ZERO_STRUCTP(pblob);
+
+  again:
+
+       tmp = TALLOC_REALLOC_ARRAY(ctx, val, uint8_t, size);
+       if (tmp == NULL) {
+               TALLOC_FREE(val);
+               return NT_STATUS_NO_MEMORY;
+       }
+       val = tmp;
+
+       become_root();
+       if (fsp) {
+               sizeret = SMB_VFS_FGETXATTR(fsp, XATTR_NTACL_NAME, val, size);
+       } else {
+               sizeret = SMB_VFS_GETXATTR(handle->conn, name,
+                                       XATTR_NTACL_NAME, val, size);
+       }
+       if (sizeret == -1) {
+               saved_errno = errno;
+       }
+       unbecome_root();
+
+       /* Max ACL size is 65536 bytes. */
+       if (sizeret == -1) {
+               errno = saved_errno;
+               if ((errno == ERANGE) && (size != 65536)) {
+                       /* Too small, try again. */
+                       size = 65536;
+                       goto again;
+               }
+
+               /* Real error - exit here. */
+               TALLOC_FREE(val);
+               return map_nt_error_from_unix(errno);
+       }
+
+       pblob->data = val;
+       pblob->length = sizeret;
+       return NT_STATUS_OK;
+}
+
+static int mkdir_acl_xattr(vfs_handle_struct *handle,  const char *path, mode_t mode)
+{
+       return SMB_VFS_NEXT_MKDIR(handle, path, mode);
+}
+
+static int rmdir_acl_xattr(vfs_handle_struct *handle,  const char *path)
+{
+       return SMB_VFS_NEXT_RMDIR(handle, path);
+}
+
+static int open_acl_xattr(vfs_handle_struct *handle,  const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+       return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+}
+
+static int unlink_acl_xattr(vfs_handle_struct *handle,  const char *fname)
+{
+       return SMB_VFS_NEXT_UNLINK(handle, fname);
+}
+
+static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle,
+                                       files_struct *fsp,
+                                       const char *name,
+                                       uint32 security_info,
+                                       SEC_DESC **ppdesc)
+{
+       TALLOC_CTX *ctx = talloc_tos();
+       DATA_BLOB blob;
+       SMB_STRUCT_STAT sbuf;
+       NTSTATUS status;
+
+       if (fsp && name == NULL) {
+               name = fsp->fsp_name;
+       }
+
+       DEBUG(10, ("get_nt_acl_xattr_internal: name=%s\n", name));
+
+       status = get_acl_blob(ctx, handle, fsp, name, &blob);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
+               return status;
+       }
+
+       if (fsp && fsp->fh->fd != -1) {
+               if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+       } else {
+               if (SMB_VFS_STAT(handle->conn, name, &sbuf) == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+       }
+
+       status = parse_acl_blob(&blob, get_ctimespec(&sbuf),
+                       security_info, ppdesc);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("parse_acl_blob returned %s\n",
+                               nt_errstr(status)));
+               return status;
+       }
+
+       TALLOC_FREE(blob.data);
+       return status;
+}
+
+static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
+        uint32 security_info, SEC_DESC **ppdesc)
+{
+       NTSTATUS status = get_nt_acl_xattr_internal(handle, fsp,
+                               NULL, security_info, ppdesc);
+       if (NT_STATUS_IS_OK(status)) {
+               return NT_STATUS_OK;
+       }
+       return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp,
+                       security_info, ppdesc);
+}
+
+static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle,
+        const char *name, uint32 security_info, SEC_DESC **ppdesc)
+{
+       NTSTATUS status = get_nt_acl_xattr_internal(handle, NULL,
+                               name, security_info, ppdesc);
+       if (NT_STATUS_IS_OK(status)) {
+               return NT_STATUS_OK;
+       }
+       return SMB_VFS_NEXT_GET_NT_ACL(handle, name,
+                       security_info, ppdesc);
+}
+
+static NTSTATUS create_acl_blob(SEC_DESC *psd, DATA_BLOB *pblob)
+{
+       struct xattr_NTACL xacl;
+       enum ndr_err_code ndr_err;
+       TALLOC_CTX *ctx = talloc_tos();
+       struct timespec curr = timespec_current();
+
+       /* Horrid hack as setting an xattr changes the ctime
+        * on Linux. This gives a race of 1 second during
+        * which we would not see a POSIX ACL set.
+        */
+       curr.tv_sec += 1;
+
+       xacl.version = 2;
+       xacl.info.sd_ts->sd = psd;
+       unix_timespec_to_nt_time(&xacl.info.sd_ts->last_changed, curr);
+
+       ndr_err = ndr_push_struct_blob(
+                       pblob, ctx, &xacl,
+                       (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
+
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
+                       ndr_errstr(ndr_err)));
+               return ndr_map_error2ntstatus(ndr_err);;
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS store_acl_blob(files_struct *fsp,
+                               DATA_BLOB *pblob)
+{
+       int ret;
+       int saved_errno;
+
+       become_root();
+       ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME,
+                       pblob->data, pblob->length, 0);
+       if (ret) {
+               saved_errno = errno;
+       }
+       unbecome_root();
+       if (ret) {
+               errno = saved_errno;
+               DEBUG(5, ("store_acl_blob: fsetxattr failed for file %s "
+                       "with error %s\n",
+                       fsp->fsp_name,
+                       strerror(errno) ));
+               return map_nt_error_from_unix(errno);
+       }
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
+        uint32 security_info_sent, SEC_DESC *psd)
+{
+       NTSTATUS status;
+       DATA_BLOB blob;
+
+       status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       create_acl_blob(psd, &blob);
+       store_acl_blob(fsp, &blob);
+
+       return NT_STATUS_OK;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple skel_op_tuples[] =
+{
+       {SMB_VFS_OP(mkdir_acl_xattr), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
+       {SMB_VFS_OP(rmdir_acl_xattr), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
+       {SMB_VFS_OP(open_acl_xattr),  SMB_VFS_OP_OPEN,  SMB_VFS_LAYER_TRANSPARENT},
+       {SMB_VFS_OP(unlink_acl_xattr),SMB_VFS_OP_UNLINK,SMB_VFS_LAYER_TRANSPARENT},
+
+        /* NT File ACL operations */
+
+       {SMB_VFS_OP(fget_nt_acl_xattr),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
+       {SMB_VFS_OP(get_nt_acl_xattr), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
+       {SMB_VFS_OP(fset_nt_acl_xattr),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
+
+        {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_acl_xattr_init(void)
+{
+       return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr", skel_op_tuples);
+}
index d7c87497a925827ee0b88e1ef8ab714dd4a0f7e2..8144d876d4061a4083ad96693e33877f0176c730 100644 (file)
@@ -818,6 +818,159 @@ done:
        return nt_status;
 }
 
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
+                                   const char *domain,
+                                   const char *name,
+                                   char **alias)
+{
+       ADS_STRUCT *ads_internal = NULL;
+       const char *attrs[] = {NULL, /* attr_uid */
+                              NULL };
+       char *filter = NULL;
+       LDAPMessage *msg = NULL;
+       ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+
+       /* Check incoming parameters */
+
+       if ( !domain || !name || !*alias) {
+               nt_status = NT_STATUS_INVALID_PARAMETER;
+               goto done;
+       }
+
+       /* Only do query if we are online */
+
+       if (idmap_is_offline()) {
+               nt_status = NT_STATUS_FILE_IS_OFFLINE;
+               goto done;
+       }
+
+       ads_internal = ad_idmap_cached_connection();
+
+       if (!ads_internal || !ad_schema) {
+               nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               goto done;
+       }
+
+       attrs[0] = ad_schema->posix_uid_attr;
+
+       filter = talloc_asprintf(mem_ctx,
+                                "(sAMAccountName=%s)",
+                                name);
+       if (!filter) {
+               nt_status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       ads_status = ads_search_retry(ads_internal, &msg, filter, attrs);
+       if (!ADS_ERR_OK(ads_status)) {
+               nt_status = ads_ntstatus(ads_status);
+               goto done;
+       }
+
+       *alias = ads_pull_string(ads_internal, mem_ctx, msg, ad_schema->posix_uid_attr );
+
+       if (!*alias) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       nt_status = NT_STATUS_OK;
+
+done:
+       if (filter) {
+               talloc_destroy(filter);
+       }
+       if (msg) {
+               ads_msgfree(ads_internal, msg);
+       }
+
+       return nt_status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
+                                            const char *domain,
+                                            const char *alias,
+                                            char **name )
+{
+       ADS_STRUCT *ads_internal = NULL;
+       const char *attrs[] = {"sAMAccountName",
+                              NULL };
+       char *filter = NULL;
+       LDAPMessage *msg = NULL;
+       ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       char *username;
+
+       /* Check incoming parameters */
+
+       if ( !alias || !name) {
+               nt_status = NT_STATUS_INVALID_PARAMETER;
+               goto done;
+       }
+
+       /* Only do query if we are online */
+
+       if (idmap_is_offline()) {
+               nt_status = NT_STATUS_FILE_IS_OFFLINE;
+               goto done;
+       }
+
+       ads_internal = ad_idmap_cached_connection();
+
+       if (!ads_internal || !ad_schema) {
+               nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               goto done;
+       }
+
+       filter = talloc_asprintf(mem_ctx,
+                                "(%s=%s)",
+                                ad_schema->posix_uid_attr,
+                                alias);
+       if (!filter) {
+               nt_status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       ads_status = ads_search_retry(ads_internal, &msg, filter, attrs);
+       if (!ADS_ERR_OK(ads_status)) {
+               nt_status = ads_ntstatus(ads_status);
+               goto done;
+       }
+
+       username = ads_pull_string(ads_internal, mem_ctx, msg,
+                                  "sAMAccountName");
+       if (!username) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       *name = talloc_asprintf(mem_ctx, "%s\\%s",
+                               lp_workgroup(),
+                               username);
+       if (!*name) {
+               nt_status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       nt_status = NT_STATUS_OK;
+
+done:
+       if (filter) {
+               talloc_destroy(filter);
+       }
+       if (msg) {
+               ads_msgfree(ads_internal, msg);
+       }
+
+       return nt_status;
+}
+
+
 /************************************************************************
  ***********************************************************************/
 
@@ -843,21 +996,27 @@ static struct idmap_methods ad_methods = {
    function which sets the intended schema model to use */
   
 static struct nss_info_methods nss_rfc2307_methods = {
-       .init         = nss_rfc2307_init,
-       .get_nss_info = nss_ad_get_info,
-       .close_fn     = nss_ad_close
+       .init           = nss_rfc2307_init,
+       .get_nss_info   = nss_ad_get_info,
+       .map_to_alias   = nss_ad_map_to_alias,
+       .map_from_alias = nss_ad_map_from_alias,
+       .close_fn       = nss_ad_close
 };
 
 static struct nss_info_methods nss_sfu_methods = {
-       .init         = nss_sfu_init,
-       .get_nss_info = nss_ad_get_info,
-       .close_fn     = nss_ad_close
+       .init           = nss_sfu_init,
+       .get_nss_info   = nss_ad_get_info,
+       .map_to_alias   = nss_ad_map_to_alias,
+       .map_from_alias = nss_ad_map_from_alias,
+       .close_fn       = nss_ad_close
 };
 
 static struct nss_info_methods nss_sfu20_methods = {
-       .init         = nss_sfu20_init,
-       .get_nss_info = nss_ad_get_info,
-       .close_fn     = nss_ad_close
+       .init           = nss_sfu20_init,
+       .get_nss_info   = nss_ad_get_info,
+       .map_to_alias   = nss_ad_map_to_alias,
+       .map_from_alias = nss_ad_map_from_alias,
+       .close_fn       = nss_ad_close
 };
 
 
diff --git a/source3/winbindd/idmap_hash/idmap_hash.c b/source3/winbindd/idmap_hash/idmap_hash.c
new file mode 100644 (file)
index 0000000..a050f99
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ *  idmap_hash.c
+ *
+ * Copyright (C) Gerald Carter  <jerry@samba.org>      2007 - 2008
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "includes.h"
+#include "winbindd/winbindd.h"
+#include "idmap_hash.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+struct sid_hash_table {
+       DOM_SID *sid;
+};
+
+struct sid_hash_table *hashed_domains = NULL;
+
+/*********************************************************************
+ Hash a domain SID (S-1-5-12-aaa-bbb-ccc) to a 12bit number
+ ********************************************************************/
+
+static uint32_t hash_domain_sid(const DOM_SID *sid)
+{
+       uint32_t hash;
+
+       if (sid->num_auths != 4)
+               return 0;
+
+       /* XOR the last three subauths */
+
+       hash = ((sid->sub_auths[1] ^ sid->sub_auths[2]) ^ sid->sub_auths[3]);
+
+       /* Take all 32-bits into account when generating the 12-bit
+          hash value */
+       hash = (((hash & 0xFFF00000) >> 20)
+               + ((hash & 0x000FFF00) >> 8)
+               + (hash & 0x000000FF)) & 0x0000FFF;
+
+       /* return a 12-bit hash value */
+
+       return hash;
+}
+
+/*********************************************************************
+ Hash a Relative ID to a 20 bit number
+ ********************************************************************/
+
+static uint32_t hash_rid(uint32_t rid)
+{
+       /* 20 bits for the rid which allows us to support
+          the first 100K users/groups in a domain */
+
+       return (rid & 0x0007FFFF);
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static uint32_t combine_hashes(uint32_t h_domain,
+                              uint32_t h_rid)
+{
+       uint32_t return_id = 0;
+
+       /* shift the hash_domain 19 bits to the left and OR with the
+          hash_rid */
+
+       return_id = ((h_domain<<19) | h_rid);
+
+       return return_id;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static void separate_hashes(uint32_t id,
+                           uint32_t *h_domain,
+                           uint32_t *h_rid)
+{
+       *h_rid = id & 0x0007FFFF;
+       *h_domain = (id & 0x7FF80000) >> 19;
+
+       return;
+}
+
+
+/*********************************************************************
+ ********************************************************************/
+
+static NTSTATUS be_init(struct idmap_domain *dom,
+                       const char *params)
+{
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       struct winbindd_tdc_domain *dom_list = NULL;
+       size_t num_domains = 0;
+       int i;
+
+       /* If the domain SID hash talbe has been initialized, assume
+          that we completed this function previously */
+
+       if ( hashed_domains ) {
+               nt_status = NT_STATUS_OK;
+               goto done;
+       }
+
+       if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
+               nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+               BAIL_ON_NTSTATUS_ERROR(nt_status);
+       }
+
+       /* Create the hash table of domain SIDs */
+
+       hashed_domains = TALLOC_ZERO_ARRAY(NULL, struct sid_hash_table, 4096);
+       BAIL_ON_PTR_NT_ERROR(hashed_domains, nt_status);
+
+       /* create the hash table of domain SIDs */
+
+       for (i=0; i<num_domains; i++) {
+               uint32_t hash;
+
+               if (is_null_sid(&dom_list[i].sid))
+                       continue;
+               if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
+                       continue;
+
+               DEBUG(5,("hash:be_init() Adding %s (%s) -> %d\n",
+                        dom_list[i].domain_name,
+                        sid_string_dbg(&dom_list[i].sid),
+                        hash));
+
+               hashed_domains[hash].sid = talloc(hashed_domains, DOM_SID);
+               sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
+       }
+
+done:
+       return nt_status;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
+                               struct id_map **ids)
+{
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       int i;
+
+       nt_status = be_init(dom, NULL);
+       BAIL_ON_NTSTATUS_ERROR(nt_status);
+
+       if (!ids) {
+               nt_status = NT_STATUS_INVALID_PARAMETER;
+               BAIL_ON_NTSTATUS_ERROR(nt_status);
+       }
+
+       for (i=0; ids[i]; i++) {
+               uint32_t h_domain, h_rid;
+
+               ids[i]->status = ID_UNMAPPED;
+
+               separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
+
+               /* Make sure the caller allocated memor for us */
+
+               if (!ids[i]->sid) {
+                       nt_status = NT_STATUS_INVALID_PARAMETER;
+                       BAIL_ON_NTSTATUS_ERROR(nt_status);
+               }
+
+               /* If the domain hash doesn't find a SID in the table,
+                  skip it */
+
+               if (!hashed_domains[h_domain].sid)
+                       continue;
+
+               sid_copy(ids[i]->sid, hashed_domains[h_domain].sid);
+               sid_append_rid(ids[i]->sid, h_rid);
+               ids[i]->status = ID_MAPPED;
+       }
+
+done:
+       return nt_status;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
+                               struct id_map **ids)
+{
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       int i;
+
+       nt_status = be_init(dom, NULL);
+       BAIL_ON_NTSTATUS_ERROR(nt_status);
+
+       if (!ids) {
+               nt_status = NT_STATUS_INVALID_PARAMETER;
+               BAIL_ON_NTSTATUS_ERROR(nt_status);
+       }
+
+       for (i=0; ids[i]; i++) {
+               DOM_SID sid;
+               uint32_t rid;
+               uint32_t h_domain, h_rid;
+
+               ids[i]->status = ID_UNMAPPED;
+
+               sid_copy(&sid, ids[i]->sid);
+               sid_split_rid(&sid, &rid);
+
+               h_domain = hash_domain_sid(&sid);
+               h_rid = hash_rid(rid);
+
+               /* Check that both hashes are non-zero*/
+
+               if (h_domain && h_rid) {
+                       ids[i]->xid.id = combine_hashes(h_domain, h_rid);
+                       ids[i]->status = ID_MAPPED;
+               }
+       }
+
+done:
+       return nt_status;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static NTSTATUS be_close(struct idmap_domain *dom)
+{
+       if (hashed_domains)
+               talloc_free(hashed_domains);
+
+       return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
+{
+       return be_init(NULL, NULL);
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_hash_get_info(struct nss_domain_entry *e,
+                                   const DOM_SID *sid,
+                                   TALLOC_CTX *ctx,
+                                   ADS_STRUCT *ads,
+                                   LDAPMessage *msg,
+                                   char **homedir,
+                                   char **shell,
+                                   char **gecos,
+                                   gid_t *p_gid )
+{
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+
+       nt_status = nss_hash_init(e);
+       BAIL_ON_NTSTATUS_ERROR(nt_status);
+
+       if (!homedir || !shell || !gecos) {
+               nt_status = NT_STATUS_INVALID_PARAMETER;
+               BAIL_ON_NTSTATUS_ERROR(nt_status);
+       }
+
+       *homedir = talloc_strdup(ctx, lp_template_homedir());
+       BAIL_ON_PTR_NT_ERROR(*homedir, nt_status);
+
+       *shell   = talloc_strdup(ctx, lp_template_shell());
+       BAIL_ON_PTR_NT_ERROR(*shell, nt_status);
+
+       *gecos   = NULL;
+
+       /* Initialize the gid so that the upper layer fills
+          in the proper Windows primary group */
+
+       if (*p_gid) {
+               *p_gid = (gid_t)-1;
+       }
+
+done:
+       return nt_status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx,
+                                       const char *domain,
+                                       const char *name,
+                                       char **alias)
+{
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       const char *value;
+
+       value = talloc_asprintf(mem_ctx, "%s\\%s", domain, name);
+       BAIL_ON_PTR_NT_ERROR(value, nt_status);
+
+       nt_status = mapfile_lookup_key(mem_ctx, value, alias);
+       BAIL_ON_NTSTATUS_ERROR(nt_status);
+
+done:
+       return nt_status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx,
+                                         const char *domain,
+                                         const char *alias,
+                                         char **name)
+{
+       return mapfile_lookup_value(mem_ctx, alias, name);
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_hash_close(void)
+{
+       return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Dispatch Tables for IDMap and NssInfo Methods
+********************************************************************/
+
+static struct idmap_methods hash_idmap_methods = {
+       .init            = be_init,
+       .unixids_to_sids = unixids_to_sids,
+       .sids_to_unixids = sids_to_unixids,
+       .close_fn        = be_close
+};
+
+static struct nss_info_methods hash_nss_methods = {
+       .init           = nss_hash_init,
+       .get_nss_info   = nss_hash_get_info,
+       .map_to_alias   = nss_hash_map_to_alias,
+       .map_from_alias = nss_hash_map_from_alias,
+       .close_fn       = nss_hash_close
+};
+
+/**********************************************************************
+ Register with the idmap and idmap_nss subsystems. We have to protect
+ against the idmap and nss_info interfaces being in a half-registered
+ state.
+ **********************************************************************/
+
+NTSTATUS idmap_hash_init(void)
+{
+       static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
+       static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
+
+       if ( !NT_STATUS_IS_OK(idmap_status) ) {
+               idmap_status =  smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
+                                                  "hash", &hash_idmap_methods);
+
+               if ( !NT_STATUS_IS_OK(idmap_status) ) {
+                       DEBUG(0,("Failed to register hash idmap plugin.\n"));
+                       return idmap_status;
+               }
+       }
+
+       if ( !NT_STATUS_IS_OK(nss_status) ) {
+               nss_status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
+                                                   "hash", &hash_nss_methods);
+               if ( !NT_STATUS_IS_OK(nss_status) ) {
+                       DEBUG(0,("Failed to register hash idmap nss plugin.\n"));
+                       return nss_status;
+               }
+       }
+
+       return NT_STATUS_OK;
+}
diff --git a/source3/winbindd/idmap_hash/idmap_hash.h b/source3/winbindd/idmap_hash/idmap_hash.h
new file mode 100644 (file)
index 0000000..621520e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  lwopen.h
+ *
+ *  Copyright (C) Gerald Carter  <jerry@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _LWOPEN_H
+#define _LWOPEN_H
+
+#define BAIL_ON_NTSTATUS_ERROR(x)         \
+       do {                               \
+               if (!NT_STATUS_IS_OK(x)) { \
+                       DEBUG(10,("Failed! (%s)\n", nt_errstr(x)));     \
+                       goto done;         \
+               }                          \
+       }                                  \
+       while (0);                         \
+
+#define BAIL_ON_PTR_NT_ERROR(p, x)                     \
+       do {                                            \
+               if ((p) == NULL ) {                     \
+                       DEBUG(10,("NULL pointer!\n"));  \
+                       x = NT_STATUS_NO_MEMORY;        \
+                       goto done;                      \
+               } else {                                \
+                       x = NT_STATUS_OK;               \
+               }                                       \
+       } while (0);
+
+#define PRINT_NTSTATUS_ERROR(x, hdr, level)                            \
+       do {                                                            \
+               if (!NT_STATUS_IS_OK(x)) {                              \
+                       DEBUG(level,("Likewise Open ("hdr"): %s\n", nt_errstr(x))); \
+               }                                                       \
+       } while(0);
+
+
+NTSTATUS mapfile_lookup_key(TALLOC_CTX *ctx,
+                           const char *value,
+                           char **key);
+
+NTSTATUS mapfile_lookup_value(TALLOC_CTX *ctx,
+                             const char *key,
+                             char **value);
+
+#endif /* _LWOPEN_H */
diff --git a/source3/winbindd/idmap_hash/mapfile.c b/source3/winbindd/idmap_hash/mapfile.c
new file mode 100644 (file)
index 0000000..5ab1142
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *  mapfile.c
+ *
+ *  Copyright (C) Gerald Carter  <jerry@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "includes.h"
+#include "winbindd/winbindd.h"
+#include "idmap_hash.h"
+#include <stdio.h>
+
+XFILE *lw_map_file = NULL;
+
+/*********************************************************************
+ ********************************************************************/
+
+static bool mapfile_open(void)
+{
+       const char *mapfile_name = NULL;
+
+       /* If we have an open handle, just reset it */
+
+       if (lw_map_file) {
+               return (x_tseek(lw_map_file, 0, SEEK_SET) == 0);
+       }
+
+       mapfile_name = lp_parm_const_string(-1, "idmap_hash", "name_map", NULL);
+       if (!mapfile_name) {
+               return false;
+       }
+
+       lw_map_file = x_fopen(mapfile_name, O_RDONLY, 0);
+       if (!lw_map_file) {
+               DEBUG(0,("can't open idmap_hash:name_map (%s). Error %s\n",
+                        mapfile_name, strerror(errno) ));
+               return false;
+       }
+
+       return true;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static bool mapfile_read_line(fstring key, fstring value)
+{
+       char buffer[1024];
+       char *p;
+       int len;
+
+       if (!lw_map_file)
+               return false;
+
+       if ((p = x_fgets(buffer, sizeof(buffer)-1, lw_map_file)) == NULL) {
+               return false;
+       }
+
+       /* Strip newlines and carriage returns */
+
+       len = strlen_m(buffer) - 1;
+       while ((buffer[len] == '\n') || (buffer[len] == '\r')) {
+               buffer[len--] = '\0';
+       }
+
+
+       if ((p = strchr_m(buffer, '=')) == NULL ) {
+               DEBUG(0,("idmap_hash: Bad line in name_map (%s)\n", buffer));
+               return false;
+       }
+
+       *p = '\0';
+       p++;
+
+       fstrcpy(key, buffer);
+       fstrcpy(value, p);
+
+       /* Eat whitespace */
+
+       if (!trim_char(key, ' ', ' '))
+               return false;
+
+       if (!trim_char(value, ' ', ' '))
+               return false;
+
+       return true;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static bool mapfile_close(void)
+{
+       int ret = 0;
+       if (lw_map_file) {
+               ret = x_fclose(lw_map_file);
+               lw_map_file = NULL;
+       }
+
+       return (ret == 0);
+}
+
+
+/*********************************************************************
+ ********************************************************************/
+
+NTSTATUS mapfile_lookup_key(TALLOC_CTX *ctx, const char *value, char **key)
+{
+       fstring r_key, r_value;
+       NTSTATUS ret = NT_STATUS_NOT_FOUND;
+
+       if (!mapfile_open())
+               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+
+       while (mapfile_read_line(r_key, r_value))
+       {
+               if (strequal(r_value, value)) {
+                       ret = NT_STATUS_OK;
+
+                       /* We're done once finishing this block */
+                       *key = talloc_strdup(ctx, r_key);
+                       if (!*key) {
+                               ret = NT_STATUS_NO_MEMORY;
+                       }
+                       break;
+               }
+       }
+
+       mapfile_close();
+
+       return ret;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+NTSTATUS mapfile_lookup_value(TALLOC_CTX *ctx, const char *key, char **value)
+{
+       fstring r_key, r_value;
+       NTSTATUS ret = NT_STATUS_NOT_FOUND;
+
+       if (!mapfile_open())
+               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+
+       while (mapfile_read_line(r_key, r_value))
+       {
+               if (strequal(r_key, key)) {
+                       ret = NT_STATUS_OK;
+
+                       /* We're done once finishing this block */
+                       *value = talloc_strdup(ctx, r_value);
+                       if (!*key) {
+                               ret = NT_STATUS_NO_MEMORY;
+                       }
+                       break;
+               }
+       }
+
+       mapfile_close();
+
+       return ret;
+}
index daa3dd037d85836a1e28e3c505c1babf0624e38e..0e8cb602571bb53b9adae25958a4292292bc88b6 100644 (file)
@@ -278,6 +278,47 @@ static struct nss_domain_entry *find_nss_domain( const char *domain )
                                homedir, shell, gecos, p_gid );
 }
 
+/********************************************************************
+ *******************************************************************/
+
+ NTSTATUS nss_map_to_alias( TALLOC_CTX *mem_ctx, const char *domain,
+                           const char *name, char **alias )
+{
+       struct nss_domain_entry *p;
+       struct nss_info_methods *m;
+
+       if ( (p = find_nss_domain( domain )) == NULL ) {
+               DEBUG(4,("nss_map_to_alias: Failed to find nss domain pointer for %s\n",
+                        domain ));
+               return NT_STATUS_NOT_FOUND;
+       }
+
+       m = p->backend->methods;
+
+       return m->map_to_alias( mem_ctx, domain, name, alias );
+}
+
+
+/********************************************************************
+ *******************************************************************/
+
+ NTSTATUS nss_map_from_alias( TALLOC_CTX *mem_ctx, const char *domain,
+                             const char *alias, char **name )
+{
+       struct nss_domain_entry *p;
+       struct nss_info_methods *m;
+
+       if ( (p = find_nss_domain( domain )) == NULL ) {
+               DEBUG(4,("nss_map_from_alias: Failed to find nss domain pointer for %s\n",
+                        domain ));
+               return NT_STATUS_NOT_FOUND;
+       }
+
+       m = p->backend->methods;
+
+       return m->map_from_alias( mem_ctx, domain, alias, name );
+}
+
 /********************************************************************
  *******************************************************************/
 
index aaf02e4abe9ff134b4b65c07559349d9479e9591..d8f903ddd08348edb5ffc3c12975c42b95c5d5a5 100644 (file)
@@ -45,6 +45,8 @@ static NTSTATUS nss_template_get_info( struct nss_domain_entry *e,
        if ( !homedir || !shell || !gecos )
                return NT_STATUS_INVALID_PARAMETER;
        
+       /* protect against home directories using whitespace in the
+         username */
        *homedir = talloc_strdup( ctx, lp_template_homedir() );
        *shell   = talloc_strdup( ctx, lp_template_shell() );
        *gecos   = NULL;
@@ -56,6 +58,28 @@ static NTSTATUS nss_template_get_info( struct nss_domain_entry *e,
        return NT_STATUS_OK;
 }
 
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_template_map_to_alias( TALLOC_CTX *mem_ctx,
+                                          const char *domain,
+                                          const char *name,
+                                          char **alias )
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS nss_template_map_from_alias( TALLOC_CTX *mem_ctx,
+                                            const char *domain,
+                                            const char *alias,
+                                            char **name )
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
 /************************************************************************
  ***********************************************************************/
 
@@ -69,9 +93,11 @@ static NTSTATUS nss_template_close( void )
  ***********************************************************************/
 
 static struct nss_info_methods nss_template_methods = {
-       .init         = nss_template_init,
-       .get_nss_info = nss_template_get_info,
-       .close_fn     = nss_template_close
+       .init           = nss_template_init,
+       .get_nss_info   = nss_template_get_info,
+       .map_to_alias   = nss_template_map_to_alias,
+       .map_from_alias = nss_template_map_from_alias,
+       .close_fn       = nss_template_close
 };
                
 NTSTATUS nss_info_template_init( void )
index 2fbb01b623ac24b412fc49a2ce53cd238244cc4f..360e915bc47542e9ac52e3df6618ef3e0de1297f 100644 (file)
@@ -934,6 +934,8 @@ static void wcache_save_lockout_policy(struct winbindd_domain *domain,
        centry_free(centry);
 }
 
+
+
 static void wcache_save_password_policy(struct winbindd_domain *domain,
                                        NTSTATUS status,
                                        struct samr_DomInfo1 *policy)
@@ -957,6 +959,209 @@ static void wcache_save_password_policy(struct winbindd_domain *domain,
        centry_free(centry);
 }
 
+/***************************************************************************
+ ***************************************************************************/
+
+static void wcache_save_username_alias(struct winbindd_domain *domain,
+                                      NTSTATUS status,
+                                      const char *name, const char *alias)
+{
+       struct cache_entry *centry;
+       fstring uname;
+
+       if ( (centry = centry_start(domain, status)) == NULL )
+               return;
+
+       centry_put_string( centry, alias );
+
+       fstrcpy(uname, name);
+       strupper_m(uname);
+       centry_end(centry, "NSS/NA/%s", uname);
+
+       DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
+
+       centry_free(centry);
+}
+
+static void wcache_save_alias_username(struct winbindd_domain *domain,
+                                      NTSTATUS status,
+                                      const char *alias, const char *name)
+{
+       struct cache_entry *centry;
+       fstring uname;
+
+       if ( (centry = centry_start(domain, status)) == NULL )
+               return;
+
+       centry_put_string( centry, name );
+
+       fstrcpy(uname, alias);
+       strupper_m(uname);
+       centry_end(centry, "NSS/AN/%s", uname);
+
+       DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
+
+       centry_free(centry);
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
+                                   struct winbindd_domain *domain,
+                                   const char *name, char **alias )
+{
+       struct winbind_cache *cache = get_cache(domain);
+       struct cache_entry *centry = NULL;
+       NTSTATUS status;
+       char *upper_name;
+
+       if ( domain->internal )
+               return NT_STATUS_NOT_SUPPORTED;
+
+       if (!cache->tdb)
+               goto do_query;
+
+       if ( (upper_name = SMB_STRDUP(name)) == NULL )
+               return NT_STATUS_NO_MEMORY;
+       strupper_m(upper_name);
+
+       centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
+
+       SAFE_FREE( upper_name );
+
+       if (!centry)
+               goto do_query;
+
+       status = centry->status;
+
+       if (!NT_STATUS_IS_OK(status)) {
+               centry_free(centry);
+               return status;
+       }
+
+       *alias = centry_string( centry, mem_ctx );
+
+       centry_free(centry);
+
+       DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
+                 name, *alias ? *alias : "(none)"));
+
+       return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+do_query:
+
+       /* If its not in cache and we are offline, then fail */
+
+       if ( get_global_winbindd_state_offline() || !domain->online ) {
+               DEBUG(8,("resolve_username_to_alias: rejecting query "
+                        "in offline mode\n"));
+               return NT_STATUS_NOT_FOUND;
+       }
+
+       status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
+
+       if ( NT_STATUS_IS_OK( status ) ) {
+               wcache_save_username_alias(domain, status, name, *alias);
+       }
+
+       if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
+               wcache_save_username_alias(domain, status, name, "(NULL)");
+       }
+
+       DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
+                nt_errstr(status)));
+
+       if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
+               set_domain_offline( domain );
+       }
+
+       return status;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
+                                   struct winbindd_domain *domain,
+                                   const char *alias, char **name )
+{
+       struct winbind_cache *cache = get_cache(domain);
+       struct cache_entry *centry = NULL;
+       NTSTATUS status;
+       char *upper_name;
+
+       if ( domain->internal )
+               return  NT_STATUS_NOT_SUPPORTED;
+
+       if (!cache->tdb)
+               goto do_query;
+
+       if ( (upper_name = SMB_STRDUP(alias)) == NULL )
+               return NT_STATUS_NO_MEMORY;
+       strupper_m(upper_name);
+
+       centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
+
+       SAFE_FREE( upper_name );
+
+       if (!centry)
+               goto do_query;
+
+       status = centry->status;
+
+       if (!NT_STATUS_IS_OK(status)) {
+               centry_free(centry);
+               return status;
+       }
+
+       *name = centry_string( centry, mem_ctx );
+
+       centry_free(centry);
+
+       DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
+                 alias, *name ? *name : "(none)"));
+
+       return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+do_query:
+
+       /* If its not in cache and we are offline, then fail */
+
+       if ( get_global_winbindd_state_offline() || !domain->online ) {
+               DEBUG(8,("resolve_alias_to_username: rejecting query "
+                        "in offline mode\n"));
+               return NT_STATUS_NOT_FOUND;
+       }
+
+       /* an alias cannot contain a domain prefix or '@' */
+
+       if (strchr(alias, '\\') || strchr(alias, '@')) {
+               DEBUG(10,("resolve_alias_to_username: skipping fully "
+                         "qualified name %s\n", alias));
+               return NT_STATUS_OBJECT_NAME_INVALID;
+       }
+
+       status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
+
+       if ( NT_STATUS_IS_OK( status ) ) {
+               wcache_save_alias_username( domain, status, alias, *name );
+       }
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+               wcache_save_alias_username(domain, status, alias, "(NULL)");
+       }
+
+       DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
+                nt_errstr(status)));
+
+       if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
+               set_domain_offline( domain );
+       }
+
+       return status;
+}
+
 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
 {
        struct winbind_cache *cache = get_cache(domain);
@@ -3257,6 +3462,48 @@ static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
        return 0;
 }
 
+static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
+                          TDB_DATA dbuf,
+                          struct tdb_validation_status *state)
+{
+       struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+
+       if (!centry) {
+               return 1;
+       }
+
+       (void)centry_string( centry, mem_ctx );
+
+       centry_free(centry);
+
+       if (!(state->success)) {
+               return 1;
+       }
+       DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
+       return 0;
+}
+
+static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
+                          TDB_DATA dbuf,
+                          struct tdb_validation_status *state)
+{
+       struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+
+       if (!centry) {
+               return 1;
+       }
+
+       (void)centry_string( centry, mem_ctx );
+
+       centry_free(centry);
+
+       if (!(state->success)) {
+               return 1;
+       }
+       DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
+       return 0;
+}
+
 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
                              struct tdb_validation_status *state)
 {
@@ -3358,6 +3605,8 @@ struct key_val_struct {
        {"NSS/PWINFO/", validate_pwinfo},
        {"TRUSTDOMS/", validate_trustdoms},
        {"TRUSTDOMCACHE/", validate_trustdomcache},
+       {"NSS/NA/", validate_nss_na},
+       {"NSS/AN/", validate_nss_an},
        {"WINBINDD_OFFLINE", validate_offline},
        {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
        {NULL, NULL}
index 4d5026d158dabea21e5aa90c8ae2a72ecb886d92..088f946877824093a2c6896a795411e43b701cd8 100644 (file)
@@ -179,12 +179,32 @@ static bool fill_passdb_alias_grmem(struct winbindd_domain *domain,
 
 /* Fill a grent structure from various other information */
 
-static bool fill_grent(struct winbindd_gr *gr, const char *dom_name,
-                      const char *gr_name, gid_t unix_gid)
+static bool fill_grent(TALLOC_CTX *mem_ctx, struct winbindd_gr *gr,
+                      const char *dom_name,
+                      char *gr_name, gid_t unix_gid)
 {
        fstring full_group_name;
+       char *mapped_name = NULL;
+       struct winbindd_domain *domain = find_domain_from_name_noinit(dom_name);
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
-       fill_domain_username( full_group_name, dom_name, gr_name, True );
+       nt_status = normalize_name_map(mem_ctx, domain, gr_name,
+                                      &mapped_name);
+
+       /* Basic whitespace replacement */
+       if (NT_STATUS_IS_OK(nt_status)) {
+               fill_domain_username(full_group_name, dom_name,
+                                    mapped_name, true);
+       }
+       /* Mapped to an aliase */
+       else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
+               fstrcpy(full_group_name, mapped_name);
+       }
+       /* no change */
+       else {
+               fill_domain_username( full_group_name, dom_name,
+                                     gr_name, True );
+       }
 
        gr->gr_gid = unix_gid;
 
@@ -280,7 +300,10 @@ static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
                char *domainname = NULL;
                char *username = NULL;
                fstring name;
+               char *mapped_name = NULL;
                enum lsa_SidType type;
+               struct winbindd_domain *target_domain = NULL;
+               NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 
                DEBUG(10,("fill_grent_mem_domain_users: "
                          "sid %s in 'Domain Users' in domain %s\n",
@@ -300,7 +323,24 @@ static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
                                  nt_errstr(status)));
                        return False;
                }
-               fill_domain_username(name, domain->name, username, True);
+
+               target_domain = find_domain_from_name_noinit(domainname);
+               name_map_status = normalize_name_map(mem_ctx, target_domain,
+                                                    username, &mapped_name);
+
+               /* Basic whitespace replacement */
+               if (NT_STATUS_IS_OK(name_map_status)) {
+                       fill_domain_username(name, domainname, mapped_name, true);
+               }
+               /* Mapped to an alias */
+               else if (NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
+                       fstrcpy(name, mapped_name);
+               }
+               /* no mapping done...use original name */
+               else {
+                       fill_domain_username(name, domainname, username, true);
+               }
+
                len = strlen(name);
                buf_len = len + 1;
                if (!(buf = (char *)SMB_MALLOC(buf_len))) {
@@ -552,6 +592,7 @@ static bool fill_grent_mem(struct winbindd_domain *domain,
                uint32 n_members = 0;
                char **members = NULL;
                NTSTATUS nt_status;
+               int j;
 
                nt_status = expand_groups( mem_ctx, domain,
                                           glist, n_glist,
@@ -562,13 +603,45 @@ static bool fill_grent_mem(struct winbindd_domain *domain,
                        goto done;
                }
 
-               /* Add new group members to list */
+               /* Add new group members to list.  Pass through the
+                  alias mapping function */
 
-               nt_status = add_names_to_list( mem_ctx, &names, &num_names,
-                                              members, n_members );
-               if ( !NT_STATUS_IS_OK(nt_status) ) {
-                       result = False;
-                       goto done;
+               for (j=0; j<n_members; j++) {
+                       fstring name_domain, name_acct;
+                       fstring qualified_name;
+                       char *mapped_name = NULL;
+                       NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
+                       struct winbindd_domain *target_domain = NULL;
+
+                       if (parse_domain_user(members[j], name_domain, name_acct)) {
+                               target_domain = find_domain_from_name_noinit(name_domain);
+                               /* NOW WHAT ? */
+                       }
+                       if (!target_domain) {
+                               target_domain = domain;
+                       }
+
+                       name_map_status = normalize_name_map(members, target_domain,
+                                                            name_acct, &mapped_name);
+
+                       /* Basic whitespace replacement */
+                       if (NT_STATUS_IS_OK(name_map_status)) {
+                               fill_domain_username(qualified_name, name_domain,
+                                                    mapped_name, true);
+                               mapped_name = qualified_name;
+                       }
+                       /* no mapping at all */
+                       else if (!NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
+                               mapped_name = members[j];
+                       }
+
+                       nt_status = add_names_to_list( mem_ctx, &names,
+                                                      &num_names,
+                                                      &mapped_name, 1);
+                       if ( !NT_STATUS_IS_OK(nt_status) ) {
+                               result = False;
+                               goto done;
+                       }
                }
 
                TALLOC_FREE( members );
@@ -679,6 +752,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state)
        struct winbindd_domain *domain;
        fstring name_domain, name_group;
        char *tmp;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        /* Ensure null termination */
        state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
@@ -686,11 +760,20 @@ void winbindd_getgrnam(struct winbindd_cli_state *state)
        DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
                  state->request.data.groupname));
 
-       /* Parse domain and groupname */
+       nt_status = normalize_name_unmap(state->mem_ctx,
+                                        state->request.data.groupname,
+                                        &tmp);
+       /* If we didn't map anything in the above call, just reset the
+          tmp pointer to the original string */
+       if (!NT_STATUS_IS_OK(nt_status) &&
+           !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
+       {
+               tmp = state->request.data.groupname;
+       }
 
-       memset(name_group, 0, sizeof(fstring));
+       /* Parse domain and groupname */
 
-       tmp = state->request.data.groupname;
+       memset(name_group, 0, sizeof(name_group));
 
        name_domain[0] = '\0';
        name_group[0] = '\0';
@@ -723,7 +806,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state)
 
        /* Get rid and name type from name */
 
-       ws_name_replace( name_group, WB_REPLACE_CHAR );
+       fstrcpy( name_group, tmp );
 
        winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
                                   getgrnam_recv, WINBINDD_GETGRNAM, state );
@@ -771,7 +854,8 @@ static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
                return;
        }
 
-       if (!fill_grent(&s->state->response.data.gr, dom_name, group_name, gid) ||
+       if (!fill_grent(s->state->mem_ctx, &s->state->response.data.gr,
+                       dom_name, group_name, gid) ||
            !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
                            &num_gr_mem, &gr_mem, &gr_mem_len))
        {
@@ -796,6 +880,9 @@ static void getgrsid_lookupsid_recv( void *private_data, bool success,
                                     enum lsa_SidType name_type )
 {
        struct getgrsid_state *s = (struct getgrsid_state *)private_data;
+       char *mapped_name = NULL;
+       fstring raw_name;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        if (!success) {
                DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
@@ -814,15 +901,39 @@ static void getgrsid_lookupsid_recv( void *private_data, bool success,
                          dom_name, name, name_type));
                request_error(s->state);
                return;
-}
+       }
 
-       if ( (s->group_name = talloc_asprintf( s->state->mem_ctx,
-                                               "%s%c%s",
-                                               dom_name,
-                                              *lp_winbind_separator(),
-                                               name)) == NULL )
-{
-               DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n"));
+       /* normalize the name and ensure that we have the DOM\name
+         coming out of here */
+
+       fstrcpy(raw_name, name);
+
+       nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name,
+                                        &mapped_name);
+
+       /* basiuc whitespace reversal */
+       if (NT_STATUS_IS_OK(nt_status)) {
+               s->group_name = talloc_asprintf(s->state->mem_ctx,
+                                               "%s%c%s",
+                                               dom_name,
+                                               *lp_winbind_separator(),
+                                               mapped_name);
+       }
+       /* mapped from alias */
+       else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
+               s->group_name = mapped_name;
+       }
+       /* no mapping at all.  use original string */
+       else {
+               s->group_name = talloc_asprintf(s->state->mem_ctx,
+                                               "%s%c%s",
+                                               dom_name,
+                                               *lp_winbind_separator(),
+                                               raw_name);
+       }
+
+       if (s->group_name == NULL) {
+               DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
                request_error(s->state);
                return;
        }
@@ -831,10 +942,10 @@ static void getgrsid_lookupsid_recv( void *private_data, bool success,
 
        winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
                               getgrsid_sid2gid_recv, s);
-       }
+}
 
 static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
-       {
+{
        struct getgrsid_state *s;
 
        if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
@@ -1261,7 +1372,7 @@ void winbindd_getgrent(struct winbindd_cli_state *state)
                fill_domain_username(domain_group_name, ent->domain_name,
                         name_list[ent->sam_entry_index].acct_name, True);
 
-               result = fill_grent(&group_list[group_list_ndx],
+               result = fill_grent(state->mem_ctx, &group_list[group_list_ndx],
                                    ent->domain_name,
                                    name_list[ent->sam_entry_index].acct_name,
                                    group_gid);
@@ -1413,6 +1524,8 @@ static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
 void winbindd_getgroups(struct winbindd_cli_state *state)
 {
        struct getgroups_state *s;
+       char *real_name = NULL;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        /* Ensure null termination */
        state->request.data.username
@@ -1432,13 +1545,22 @@ void winbindd_getgroups(struct winbindd_cli_state *state)
 
        s->state = state;
 
-       ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
+       nt_status = normalize_name_unmap(state->mem_ctx,
+                                        state->request.data.username,
+                                        &real_name);
+
+       /* Reset the real_name pointer if we didn't do anything
+          productive in the above call */
+       if (!NT_STATUS_IS_OK(nt_status) &&
+           !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
+       {
+               real_name = state->request.data.username;
+       }
 
-       if (!parse_domain_user_talloc(state->mem_ctx,
-                                     state->request.data.username,
+       if (!parse_domain_user_talloc(state->mem_ctx, real_name,
                                      &s->domname, &s->username)) {
                DEBUG(5, ("Could not parse domain user: %s\n",
-                         state->request.data.username));
+                         real_name));
 
                /* error out if we do not have nested group support */
 
index d4a2e3ed7942f2a524856efebafad15d69fd9069..d9104ca600577fcade960cb0066596a4d11c0421 100644 (file)
@@ -811,7 +811,9 @@ void winbindd_pam_auth(struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain;
        fstring name_domain, name_user;
+       char *mapped_user = NULL;
        NTSTATUS result;
+       NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 
        /* Ensure null termination */
        state->request.data.auth.user
@@ -831,10 +833,20 @@ void winbindd_pam_auth(struct winbindd_cli_state *state)
 
        /* Parse domain and username */
 
-       ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
+       name_map_status = normalize_name_unmap(state->mem_ctx,
+                                              state->request.data.auth.user,
+                                              &mapped_user);
 
-       if (!canonicalize_username(state->request.data.auth.user,
-                              name_domain, name_user)) {
+       /* If the name normalization didnt' actually do anything,
+          just use the original name */
+
+       if (!NT_STATUS_IS_OK(name_map_status) &&
+           !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
+       {
+               mapped_user = state->request.data.auth.user;
+       }
+
+       if (!canonicalize_username(mapped_user, name_domain, name_user)) {
                result = NT_STATUS_NO_SUCH_USER;
                goto done;
        }
@@ -1447,7 +1459,10 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
        NTSTATUS result = NT_STATUS_LOGON_FAILURE;
        NTSTATUS krb5_result = NT_STATUS_OK;
        fstring name_domain, name_user;
+       char *mapped_user;
+       fstring domain_user;
        struct netr_SamInfo3 *info3 = NULL;
+       NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 
        /* Ensure null termination */
        state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
@@ -1465,9 +1480,26 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 
        /* Parse domain and username */
 
-       ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
+       name_map_status = normalize_name_unmap(state->mem_ctx,
+                                              state->request.data.auth.user,
+                                              &mapped_user);
 
-       parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+       /* If the name normalization didnt' actually do anything,
+          just use the original name */
+
+       if (!NT_STATUS_IS_OK(name_map_status) &&
+           !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
+       {
+               mapped_user = state->request.data.auth.user;
+       }
+
+       parse_domain_user(mapped_user, name_domain, name_user);
+
+       if ( mapped_user != state->request.data.auth.user ) {
+               fstr_sprintf( domain_user, "%s\\%s", name_domain, name_user );
+               safe_strcpy( state->request.data.auth.user, domain_user,
+                            sizeof(state->request.data.auth.user)-1 );
+       }
 
        if (domain->online == false) {
                result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
@@ -1970,14 +2002,30 @@ done:
 void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
 {
        fstring domain, user;
+       char *mapped_user;
        struct winbindd_domain *contact_domain;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
                state->request.data.chauthtok.user));
 
        /* Setup crap */
 
-       ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
+       nt_status = normalize_name_unmap(state->mem_ctx,
+                                        state->request.data.chauthtok.user,
+                                        &mapped_user);
+
+       /* Update the chauthtok name if we did any mapping */
+
+       if (NT_STATUS_IS_OK(nt_status) ||
+           NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
+       {
+               fstrcpy(state->request.data.chauthtok.user, mapped_user);
+       }
+
+       /* Must pass in state->...chauthtok.user because
+          canonicalize_username() assumes an fstring().  Since
+          we have already copied it (if necessary), this is ok. */
 
        if (!canonicalize_username(state->request.data.chauthtok.user, domain, user)) {
                set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
index e0fc073a0a5456a43fb82cc0150067154dae2b43..4774bc8106adef83a7edd7fcb1aff844ffd5cbc6 100644 (file)
@@ -583,8 +583,22 @@ NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
                                  TALLOC_CTX *mem_ctx,
                                  const DOM_SID *user_sid,
                                  uint32 *p_num_groups, DOM_SID **user_sids);
-void ws_name_replace( char *name, char replace );
-void ws_name_return( char *name, char replace );
+
+NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
+                           struct winbindd_domain *domain,
+                           char *name,
+                           char **normalized);
+NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
+                             char *name,
+                             char **normalized);
+
+NTSTATUS resolve_username_to_alias(TALLOC_CTX *mem_ctx,
+                                  struct winbindd_domain *domain,
+                                  const char *name, char **alias);
+NTSTATUS resolve_alias_to_username(TALLOC_CTX *mem_ctx,
+                                  struct winbindd_domain *domain,
+                                  const char *alias, char **name);
+
 bool winbindd_can_contact_domain(struct winbindd_domain *domain);
 bool winbindd_internal_child(struct winbindd_child *child);
 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain);
index bb79d7ec1269a24d54a7ff91c46f6d23a099e3e0..df80ad80297c8c3a2e5f18152aa0174581ba834f 100644 (file)
@@ -279,6 +279,8 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
        char *full_name = NULL;
        struct rpc_pipe_client *cli;
        POLICY_HND lsa_policy;
+       NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
+       char *mapped_name = NULL;
 
        if (name == NULL || *name=='\0') {
                full_name = talloc_asprintf(mem_ctx, "%s", domain_name);
@@ -294,9 +296,19 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
 
        DEBUG(3,("rpc: name_to_sid name=%s\n", full_name));
 
-       ws_name_return( full_name, WB_REPLACE_CHAR );
+       name_map_status = normalize_name_unmap(mem_ctx, full_name,
+                                              &mapped_name);
 
-       DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", full_name?full_name:"", domain_name ));
+       /* Reset the full_name pointer if we mapped anytthing */
+
+       if (NT_STATUS_IS_OK(name_map_status) ||
+           NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
+       {
+               full_name = mapped_name;
+       }
+
+       DEBUG(3,("name_to_sid [rpc] %s for domain %s\n",
+                full_name?full_name:"", domain_name ));
 
        result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
        if (!NT_STATUS_IS_OK(result))
@@ -332,6 +344,8 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
        NTSTATUS result;
        struct rpc_pipe_client *cli;
        POLICY_HND lsa_policy;
+       NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
+       char *mapped_name = NULL;
 
        DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_dbg(sid),
                 domain->name ));
@@ -356,9 +370,17 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
        *domain_name = domains[0];
        *name = names[0];
 
-       ws_name_replace( *name, WB_REPLACE_CHAR );      
-               
        DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
+
+       name_map_status = normalize_name_map(mem_ctx, domain, *name,
+                                            &mapped_name);
+       if (NT_STATUS_IS_OK(name_map_status) ||
+           NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
+       {
+               *name = mapped_name;
+               DEBUG(5,("returning mapped name -- %s\n", *name));
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -411,8 +433,20 @@ NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain,
 
        ret_names = *names;
        for (i=0; i<num_rids; i++) {
+               NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
+               char *mapped_name = NULL;
+
                if ((*types)[i] != SID_NAME_UNKNOWN) {
-                       ws_name_replace( ret_names[i], WB_REPLACE_CHAR );
+                       name_map_status = normalize_name_map(mem_ctx,
+                                                            domain,
+                                                            ret_names[i],
+                                                            &mapped_name);
+                       if (NT_STATUS_IS_OK(name_map_status) ||
+                           NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
+                       {
+                               ret_names[i] = mapped_name;
+                       }
+
                        *domain_name = domains[i];
                }
        }
index 3b6dfdda1c9db38dc07888e361d252f2e823048b..e5d0a22a7324e03c905d1832fa526de3121f8f56 100644 (file)
@@ -67,12 +67,15 @@ static bool fillup_pw_field(const char *lp_template,
 }
 /* Fill a pwent structure with information we have obtained */
 
-static bool winbindd_fill_pwent(char *dom_name, char *user_name,
+static bool winbindd_fill_pwent(TALLOC_CTX *ctx, char *dom_name, char *user_name,
                                DOM_SID *user_sid, DOM_SID *group_sid,
                                char *full_name, char *homedir, char *shell,
                                struct winbindd_pw *pw)
 {
        fstring output_username;
+       char *mapped_name = NULL;
+       struct winbindd_domain *domain = NULL;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        if (!pw || !dom_name || !user_name)
                return False;
@@ -99,7 +102,28 @@ static bool winbindd_fill_pwent(char *dom_name, char *user_name,
 
        /* Username */
 
-       fill_domain_username(output_username, dom_name, user_name, True);
+       domain = find_domain_from_name_noinit(dom_name);
+       if (domain) {
+               nt_status = normalize_name_map(ctx, domain, user_name,
+                                              &mapped_name);
+       } else {
+               DEBUG(5,("winbindd_fill_pwent: Failed to find domain for %s.  "
+                        "Disabling name alias support\n", dom_name));
+               nt_status = NT_STATUS_NO_SUCH_DOMAIN;
+       }
+
+       /* Basic removal of whitespace */
+       if (NT_STATUS_IS_OK(nt_status)) {
+               fill_domain_username(output_username, dom_name, mapped_name, True);
+       }
+       /* Complete name replacement */
+       else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
+               fstrcpy(output_username, mapped_name);
+       }
+       /* No change at all */
+       else {
+               fill_domain_username(output_username, dom_name, user_name, True);
+       }
 
        safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
 
@@ -179,6 +203,7 @@ struct getpwsid_state {
        uid_t uid;
        DOM_SID group_sid;
        gid_t gid;
+       bool username_mapped;
 };
 
 static void getpwsid_queryuser_recv(void *private_data, bool success,
@@ -231,6 +256,8 @@ static void getpwsid_queryuser_recv(void *private_data, bool success,
        fstring username;
        struct getpwsid_state *s =
                talloc_get_type_abort(private_data, struct getpwsid_state);
+       char *mapped_name;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        if (!success) {
                DEBUG(5, ("Could not query domain %s SID %s\n",
@@ -272,7 +299,23 @@ static void getpwsid_queryuser_recv(void *private_data, bool success,
        strlower_m( username );
        s->username = talloc_strdup(s->state->mem_ctx, username);
 
-       ws_name_replace( s->username, WB_REPLACE_CHAR );
+       nt_status = normalize_name_map(s->state->mem_ctx, s->domain,
+                                      s->username, &mapped_name);
+
+       /* Basic removal of whitespace */
+       if (NT_STATUS_IS_OK(nt_status)) {
+               s->username = mapped_name;
+               s->username_mapped = false;
+       }
+       /* Complete name replacement */
+       else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
+               s->username = mapped_name;
+               s->username_mapped = true;
+       }
+       /* No change at all */
+       else {
+               s->username_mapped = false;
+       }
 
        s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
        s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
@@ -330,8 +373,16 @@ static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
        pw = &s->state->response.data.pw;
        pw->pw_uid = s->uid;
        pw->pw_gid = s->gid;
+
+       /* allow username to be overridden by the alias mapping */
+
+       if ( s->username_mapped ) {
+               fstrcpy( output_username, s->username );
+       } else {
        fill_domain_username(output_username, s->domain->name,
                             s->username, True);
+       }
+
        safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
        safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
 
@@ -370,8 +421,10 @@ void winbindd_getpwnam(struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain;
        fstring domname, username;
+       char *mapped_user = NULL;
        char *domuser;
        size_t dusize;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        domuser = state->request.data.username;
        dusize = sizeof(state->request.data.username);
@@ -383,9 +436,19 @@ void winbindd_getpwnam(struct winbindd_cli_state *state)
                  (unsigned long)state->pid,
                  domuser));
 
-       ws_name_return(domuser, WB_REPLACE_CHAR);
+       nt_status = normalize_name_unmap(state->mem_ctx, domuser,
+                                        &mapped_user);
+
+       /* If we could not convert from an aliased name or a
+          normalized name, then just use the original name */
+
+       if (!NT_STATUS_IS_OK(nt_status) &&
+           !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
+       {
+               mapped_user = domuser;
+       }
 
-       if (!parse_domain_user(domuser, domname, username)) {
+       if (!parse_domain_user(mapped_user, domname, username)) {
                DEBUG(5, ("Could not parse domain user: %s\n", domuser));
                request_error(state);
                return;
@@ -743,6 +806,7 @@ void winbindd_getpwent(struct winbindd_cli_state *state)
                /* Lookup user info */
 
                result = winbindd_fill_pwent(
+                       state->mem_ctx,
                        ent->domain_name,
                        name_list[ent->sam_entry_index].name,
                        &name_list[ent->sam_entry_index].user_sid,
index 132c96f1eefb6d7013dcc5e0fadbcd49273130ef..e7b6576317557372af5cd0863c70fdae478343a4 100644 (file)
@@ -1378,34 +1378,107 @@ NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
  We use this to remove spaces from user and group names
 ********************************************************************/
 
-void ws_name_replace( char *name, char replace )
+NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
+                            struct winbindd_domain *domain,
+                            char *name,
+                            char **normalized)
 {
-       char replace_char[2] = { 0x0, 0x0 };
-    
-       if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
-               return;
+       NTSTATUS nt_status;
 
-       replace_char[0] = replace;      
-       all_string_sub( name, " ", replace_char, 0 );
+       if (!name || !normalized) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
-       return; 
+       if (!lp_winbind_normalize_names()) {
+               return NT_STATUS_PROCEDURE_NOT_FOUND;
+       }
+
+       /* Alias support and whitespace replacement are mutually
+          exclusive */
+
+       nt_status = resolve_username_to_alias(mem_ctx, domain,
+                                             name, normalized );
+       if (NT_STATUS_IS_OK(nt_status)) {
+               /* special return code to let the caller know we
+                  mapped to an alias */
+               return NT_STATUS_FILE_RENAMED;
+       }
+
+       /* check for an unreachable domain */
+
+       if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
+               DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
+                        domain->name));
+               set_domain_offline(domain);
+               return nt_status;
+       }
+
+       /* deal with whitespace */
+
+       *normalized = talloc_strdup(mem_ctx, name);
+       if (!(*normalized)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       all_string_sub( *normalized, " ", "_", 0 );
+
+       return NT_STATUS_OK;
 }
 
 /*********************************************************************
- We use this to do the inverse of ws_name_replace()
+ We use this to do the inverse of normalize_name_map()
 ********************************************************************/
 
-void ws_name_return( char *name, char replace )
+NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
+                             char *name,
+                             char **normalized)
 {
-       char replace_char[2] = { 0x0, 0x0 };
-    
-       if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
-               return;
+       NTSTATUS nt_status;
+       struct winbindd_domain *domain = find_our_domain();
+
+       if (!name || !normalized) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
        
-       replace_char[0] = replace;      
-       all_string_sub( name, replace_char, " ", 0 );
+       if (!lp_winbind_normalize_names()) {
+               return NT_STATUS_PROCEDURE_NOT_FOUND;
+       }
 
-       return; 
+       /* Alias support and whitespace replacement are mutally
+          exclusive */
+
+       /* When mapping from an alias to a username, we don't know the
+          domain.  But we only need a domain structure to cache
+          a successful lookup , so just our own domain structure for
+          the seqnum. */
+
+       nt_status = resolve_alias_to_username(mem_ctx, domain,
+                                             name, normalized);
+       if (NT_STATUS_IS_OK(nt_status)) {
+               /* Special return code to let the caller know we mapped
+                  from an alias */
+               return NT_STATUS_FILE_RENAMED;
+       }
+
+       /* check for an unreachable domain */
+
+       if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
+               DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
+                        domain->name));
+               set_domain_offline(domain);
+               return nt_status;
+       }
+
+       /* deal with whitespace */
+
+       *normalized = talloc_strdup(mem_ctx, name);
+       if (!(*normalized)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       all_string_sub(*normalized, "_", " ", 0);
+
+       return NT_STATUS_OK;
 }
 
 /*********************************************************************