summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/OID/allocated-arcs.txt16
-rw-r--r--docs/OID/samba-oid.mail27
-rw-r--r--examples/VFS/block/Makefile37
-rw-r--r--examples/VFS/block/block.c546
-rw-r--r--examples/VFS/block/samba-block.conf6
-rw-r--r--examples/VFS/block/smb.conf13
-rw-r--r--source/include/mapping.h48
-rw-r--r--source/nsswitch/.cvsignore1
-rw-r--r--source/nsswitch/winbindd_sid.c244
-rw-r--r--testsuite/lib/default-nt-names.exp20
-rw-r--r--testsuite/lib/nsswitch-config.exp21
-rw-r--r--testsuite/nsswitch/.cvsignore12
-rw-r--r--testsuite/nsswitch/Makefile.longarg5
-rw-r--r--testsuite/nsswitch/envvar.exp282
-rw-r--r--testsuite/nsswitch/getent.c151
-rw-r--r--testsuite/nsswitch/getent_grent.c101
-rw-r--r--testsuite/nsswitch/getent_pwent.c113
-rw-r--r--testsuite/nsswitch/groupmem_dom.exp33
-rw-r--r--testsuite/nsswitch/initgroups.c42
-rw-r--r--testsuite/nsswitch/initgroups.exp37
-rw-r--r--testsuite/nsswitch/longarg.exp29
-rw-r--r--testsuite/nsswitch/longarg_getgrnam.c42
-rw-r--r--testsuite/nsswitch/longarg_getpwnam.c42
-rw-r--r--testsuite/nsswitch/longarg_utils.h27
-rw-r--r--testsuite/nsswitch/wbinfo.exp360
25 files changed, 2255 insertions, 0 deletions
diff --git a/docs/OID/allocated-arcs.txt b/docs/OID/allocated-arcs.txt
new file mode 100644
index 00000000000..7a7cd8057b6
--- /dev/null
+++ b/docs/OID/allocated-arcs.txt
@@ -0,0 +1,16 @@
+!===========================================================================================
+!==
+!== Allocated Arcs from the Samba Team Private Enterprise Number
+!== ISO(1) org(3) dod(6) internet(1) experimental(3) private(4) enterprise(1) Samba(7165)
+!==
+!== Arc allocation is maintained by jerry carter <jerry@samba.org>. Please notify
+!== me if you need an OID and update this file.
+!==
+!== File Created : Tue May 8 09:33:31 CDT 2001
+!==
+!===========================================================================================
+
+ARC Owner Contact Purpose
+--- ----- ------- -------
+.1 Plainjoe.org Jerry Carter <jerry@samba.org> Use for Plainjoe.org domain
+ and examples in O'Reilly LDAP book
diff --git a/docs/OID/samba-oid.mail b/docs/OID/samba-oid.mail
new file mode 100644
index 00000000000..d1ad668f880
--- /dev/null
+++ b/docs/OID/samba-oid.mail
@@ -0,0 +1,27 @@
+From gruiz@icann.org Tue May 8 04:27:07 2001
+Date: Tue, 26 Sep 2000 15:29:02 -0700
+From: GIGI RUIZ <gruiz@icann.org>
+To: jerry@samba.org
+Cc: "Iana-Mib (E-mail)" <iana-mib@iana.org>
+Subject: PEN 7165 RE: Application for Enterprise-number
+
+ [ The following text is in the "iso-8859-1" character set. ]
+ [ Your display is set for the "US-ASCII" character set. ]
+ [ Some characters may be displayed incorrectly. ]
+
+Gerald,
+
+We have assigned Private Enterprise Number 7165 to SAMBA Team, with you as
+the point of contact. Please confirm the information listed below.
+
+7165 SAMBA Team Gerald Carter jerry@samba.org
+
+Sincerely,
+
+Gigi Ruiz
+Internet Assigned Numbers Authority - MIB
+
+Voice: (310) 823-9358
+Fax: (310) 823-8649
+EMAIL: iana-mib@iana.org
+
diff --git a/examples/VFS/block/Makefile b/examples/VFS/block/Makefile
new file mode 100644
index 00000000000..dcc7c077936
--- /dev/null
+++ b/examples/VFS/block/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for samba-vfs examples
+#
+#
+
+# Variables
+
+CC = gcc
+LIBTOOL = libtool
+
+SAMBA_SRC = /usr/local/src/samba/samba-2.2.0-ron/source
+SAMBA_INCL = ${SAMBA_SRC}/include
+UBIQX_SRC = ${SAMBA_SRC}/ubiqx
+SMBWR_SRC = ${SAMBA_SRC}/smbwrapper
+CFLAGS = -I$(SAMBA_SRC) -I$(SAMBA_INCL) -I$(UBIQX_SRC) -I$(SMBWR_SRC) -Wall -g -D_LARGEFILE63_SOURCE -D_GNU_SOURCE -fno-builtin
+
+
+VFS_OBJS = block.so
+
+# Default target
+
+default: $(VFS_OBJS)
+
+# Pattern rules
+
+%.so: %.lo
+ $(LIBTOOL) $(CC) -shared -o $@ $< $(LDFLAGS)
+
+%.lo: %.c
+ $(LIBTOOL) $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+# Misc targets
+
+clean:
+ rm -rf .libs
+ rm -f core *~ *% *.bak \
+ $(VFS_OBJS) $(VFS_OBJS:.so=.o) $(VFS_OBJS:.so=.lo)
diff --git a/examples/VFS/block/block.c b/examples/VFS/block/block.c
new file mode 100644
index 00000000000..3c4f736e849
--- /dev/null
+++ b/examples/VFS/block/block.c
@@ -0,0 +1,546 @@
+/*
+ *
+ * Block access from links to dev mount points specified in PARAMCONF file
+ *
+ * Copyright (C) Ronald Kuetemeier, 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <syslog.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+
+#include <includes.h>
+#include <vfs.h>
+
+
+
+DIR *block_opendir(struct connection_struct *conn, char *fname);
+int block_connect(struct connection_struct *conn, char *service, char *user);
+void block_disconnect(struct connection_struct *conn);
+
+
+/* VFS operations */
+
+
+extern struct vfs_ops default_vfs_ops; /* For passthrough operation */
+
+struct vfs_ops execute_vfs_ops = {
+
+ /* Disk operations */
+
+ block_connect,
+ block_disconnect,
+ NULL, /* disk free */
+
+ /* Directory operations */
+
+ block_opendir,
+ NULL, /* readdir */
+ NULL,
+ NULL,
+ NULL, /* closedir */
+
+ /* File operations */
+
+ NULL,
+ NULL,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* lseek */
+ NULL,
+ NULL, /* fsync */
+ NULL, /* stat */
+ NULL, /* fstat */
+ NULL, /* lstat */
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* chown */
+ NULL,
+ NULL, /* chdir */
+ NULL, /* getwd */
+ NULL, /* utime */
+ NULL, /* ftruncate */
+ NULL, /* lock */
+ NULL, /* fget_nt_acl */
+ NULL, /* get_nt_acl */
+ NULL, /* fset_nt_acl */
+ NULL, /* set_nt_acl */
+ NULL,
+ NULL
+};
+
+
+#ifndef PARAMCONF
+#define PARAMCONF "/etc/samba-block.conf"
+#endif
+
+extern BOOL pm_process(char *FileName, BOOL (*sfunc)(char *), BOOL(*pfunc)(char * , char *));
+
+//functions
+
+BOOL enter_pblock_mount(char *dir);
+BOOL get_section(char *sect);
+BOOL get_parameter_value(char *param, char *value);
+BOOL load_param(void);
+BOOL search(struct stat *stat_buf);
+BOOL dir_search(char *link, char *dir);
+BOOL enter_pblock_dir(char *dir);
+
+
+
+typedef struct block_dir
+{
+ dev_t st_dev;
+ int str_len;
+ char *dir_name;
+ struct block_dir *next;
+} block_dir;
+
+
+static char *params[] = {"mount_point","dir_name"};
+enum { MOUNT_POINT , DIR_NAME };
+
+static struct block_dir *pblock_mountp = NULL;
+static struct block_dir *pblock_dir = NULL;
+
+
+
+/*
+ * Load the conf file into a table
+ */
+
+BOOL load_param(void)
+{
+
+ if ((pm_process(PARAMCONF,&get_section,&get_parameter_value)) == TRUE)
+ {
+ return TRUE;
+
+ }
+ return FALSE;
+}
+
+
+
+/*
+ * Enter the key and data into the list
+ *
+ */
+
+BOOL enter_pblock_mount(char *dir)
+{
+ struct stat stat_buf;
+ static struct block_dir *tmp_pblock;
+
+
+ if((stat(dir,&stat_buf)) != 0)
+ {
+ return FALSE;
+ }
+
+ if(pblock_mountp == NULL)
+ {
+ pblock_mountp = calloc(1, sizeof(block_dir));
+ if( pblock_mountp == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = pblock_mountp;
+ tmp_pblock->next = NULL;
+
+ }else
+ {
+ tmp_pblock->next = calloc(1, sizeof(block_dir));
+ if(tmp_pblock->next == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ tmp_pblock->next = NULL;
+
+ }
+
+
+ tmp_pblock->st_dev = stat_buf.st_dev;
+ tmp_pblock->dir_name = strdup(dir);
+
+
+ return TRUE;
+
+}
+
+
+/*
+ * Enter the key and data into the list
+ *
+ */
+
+BOOL enter_pblock_dir(char *dir)
+{
+ static struct block_dir *tmp_pblock;
+
+
+ if(pblock_dir == NULL)
+ {
+ pblock_dir = calloc(1, sizeof(block_dir));
+ if( pblock_dir == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = pblock_dir;
+ tmp_pblock->next = NULL;
+
+ }else
+ {
+ tmp_pblock->next = calloc(1, sizeof(block_dir));
+ if(tmp_pblock->next == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ tmp_pblock->next = NULL;
+
+ }
+
+
+ tmp_pblock->dir_name = strdup(dir);
+ tmp_pblock->str_len = strlen(dir);
+
+
+ return TRUE;
+
+}
+
+
+
+
+/*
+ * Function callback for config section names
+ */
+
+BOOL get_section(char *sect)
+{
+ return TRUE;
+}
+
+
+
+/*
+ * Function callback for config parameter value pairs
+ *
+ */
+
+BOOL get_parameter_value(char *param, char *value)
+{
+ int i = 0, maxargs = sizeof(params) / sizeof(char *);
+
+
+ for( i= 0; i < maxargs; i++)
+ {
+ if (strcmp(param,params[i]) == 0)
+ {
+ switch(i)
+ {
+ case MOUNT_POINT :
+ enter_pblock_mount(value);
+ break;
+ case DIR_NAME :
+ enter_pblock_dir(value);
+ break;
+ default :
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+/* VFS initialisation function. Return initialised vfs_ops structure
+ back to SAMBA. */
+
+struct vfs_ops *vfs_init(int *vfs_version)
+{
+ *vfs_version = SMB_VFS_INTERFACE_VERSION;
+
+ return(&execute_vfs_ops);
+}
+
+
+/*
+ * VFS connect and param file loading
+ */
+
+int block_connect(struct connection_struct *conn, char *service, char *user)
+{
+ if((load_param()) == FALSE)
+ {
+
+ return -1;
+
+ }
+
+ DEBUG(0,("%s connecting \n",conn->user));
+
+ return (default_vfs_ops.connect(conn, service,user));
+}
+
+/*
+ * Free allocated structures and disconnect
+ *
+ */
+
+
+void block_disconnect(struct connection_struct *conn)
+{
+
+ struct block_dir *tmp_pblock = (pblock_mountp == NULL ? pblock_dir : pblock_mountp);
+ struct block_dir *free_pblock = NULL;
+
+ while(tmp_pblock != NULL)
+ {
+ free(tmp_pblock->dir_name);
+ free_pblock = tmp_pblock;
+ tmp_pblock = tmp_pblock->next;
+ free(free_pblock);
+
+ if(tmp_pblock == NULL && pblock_dir != NULL)
+ {
+ tmp_pblock = (pblock_mountp == NULL ? pblock_dir : NULL);
+ pblock_dir = NULL;
+
+ }
+
+ }
+
+
+
+ default_vfs_ops.disconnect(conn);
+}
+
+/*
+ * VFS opendir
+ */
+
+DIR *block_opendir(struct connection_struct *conn, char *fname)
+{
+
+ char *dir_name = NULL;
+ struct stat stat_buf;
+
+ dir_name = alloca((strlen(conn->origpath) + strlen(fname) + 2) * sizeof(char));
+
+ pstrcpy(dir_name,conn->origpath);
+ pstrcat(dir_name, "/");
+ strncat(dir_name, fname, strcspn(fname,"/"));
+
+ if((lstat(dir_name,&stat_buf)) == 0)
+ {
+ if((S_ISLNK(stat_buf.st_mode)) == 1)
+ {
+ stat(dir_name,&stat_buf);
+ if((search(&stat_buf) || dir_search(dir_name, fname) ) == TRUE)
+ {
+ DEBUG(0,("%s used link to blocked dir: %s \n", conn->user, dir_name));
+ errno = EACCES;
+ return NULL;
+ }
+ }
+ }
+
+ return (default_vfs_ops.opendir(conn, fname));
+}
+
+
+/*
+ * Find mount point to block in list
+ */
+
+BOOL search(struct stat *stat_buf)
+{
+ struct block_dir *tmp_pblock = pblock_mountp;
+
+ while(tmp_pblock != NULL)
+ {
+
+ if(tmp_pblock->st_dev == stat_buf->st_dev)
+ {
+ return TRUE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ }
+
+ return FALSE;
+
+}
+
+/*
+ * Find dir in list to block id the starting point is link from a share
+ */
+
+BOOL dir_search(char *link, char *dir)
+{
+ char buf[PATH_MAX +1], *ext_path;
+ int len = 0;
+ struct block_dir *tmp_pblock = pblock_dir;
+
+ if((len = readlink(link,buf,sizeof(buf))) == -1)
+ {
+ return TRUE;
+
+ }else
+ {
+ buf[len] = '\0';
+ }
+
+
+ if((ext_path = strchr(dir,'/')) != NULL)
+ {
+ pstrcat(buf,&ext_path[1]);
+ len = strlen(buf);
+ }
+
+ while(tmp_pblock != NULL)
+ {
+ if(len < tmp_pblock->str_len)
+ {
+ tmp_pblock = tmp_pblock->next;
+ continue;
+ }
+
+ if((strstr(buf,tmp_pblock->dir_name)) != NULL)
+ {
+ return TRUE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ }
+
+
+ return FALSE;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/VFS/block/samba-block.conf b/examples/VFS/block/samba-block.conf
new file mode 100644
index 00000000000..7a137980b73
--- /dev/null
+++ b/examples/VFS/block/samba-block.conf
@@ -0,0 +1,6 @@
+[ blocked ]
+mount_point = /
+mount_point = /boot
+mount_point = /proc
+dir_name = /usr/local/src/samba
+dir_name = /usr/bin
diff --git a/examples/VFS/block/smb.conf b/examples/VFS/block/smb.conf
new file mode 100644
index 00000000000..368155f1f83
--- /dev/null
+++ b/examples/VFS/block/smb.conf
@@ -0,0 +1,13 @@
+[homes]
+ comment = Home Directories
+ vfs object = /usr/local/samba/lib/block.so
+ browseable = yes
+ writable = yes
+
+
+
+
+
+
+
+
diff --git a/source/include/mapping.h b/source/include/mapping.h
new file mode 100644
index 00000000000..f3e0be6e4a7
--- /dev/null
+++ b/source/include/mapping.h
@@ -0,0 +1,48 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+typedef struct _GROUP_MAP {
+ gid_t gid;
+ DOM_SID sid;
+ enum SID_NAME_USE sid_name_use;
+ fstring nt_name;
+ fstring comment;
+ uint32 privilege;
+} GROUP_MAP;
+
+typedef struct _PRIVS {
+ uint32 se_priv;
+ char *priv;
+ char *description;
+} PRIVS;
+
+#define SE_PRIV_NONE 0x0000
+#define SE_PRIV_ADD_USERS 0x0001
+#define SE_PRIV_ADD_MACHINES 0x0002
+#define SE_PRIV_PRINT_OPERATOR 0x0004
+#define SE_PRIV_ALL 0xffff
+
+#define PRIV_ALL_INDEX 4
+
+
+#define ENUM_ONLY_MAPPED True
+#define ENUM_ALL_MAPPED False
diff --git a/source/nsswitch/.cvsignore b/source/nsswitch/.cvsignore
new file mode 100644
index 00000000000..6d609cec52b
--- /dev/null
+++ b/source/nsswitch/.cvsignore
@@ -0,0 +1 @@
+*.po
diff --git a/source/nsswitch/winbindd_sid.c b/source/nsswitch/winbindd_sid.c
new file mode 100644
index 00000000000..bc014f26918
--- /dev/null
+++ b/source/nsswitch/winbindd_sid.c
@@ -0,0 +1,244 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon - sid related functions
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+#include "sids.h"
+
+/* Convert a string */
+
+enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
+{
+ extern DOM_SID global_sid_Builtin;
+ enum SID_NAME_USE type;
+ DOM_SID sid, tmp_sid;
+ uint32 rid;
+ fstring name;
+
+ DEBUG(3, ("[%5d]: lookupsid %s\n", state->pid,
+ state->request.data.sid));
+
+ /* Lookup sid from PDC using lsa_lookup_sids() */
+
+ string_to_sid(&sid, state->request.data.sid);
+
+ /* Don't look up BUILTIN sids */
+
+ sid_copy(&tmp_sid, &sid);
+ sid_split_rid(&tmp_sid, &rid);
+
+ if (sid_equal(&tmp_sid, &global_sid_Builtin)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Lookup the sid */
+
+ if (!winbindd_lookup_name_by_sid(&sid, name, &type)) {
+ return WINBINDD_ERROR;
+ }
+
+ string_sub(name, "\\", lp_winbind_separator(), sizeof(fstring));
+ fstrcpy(state->response.data.name.name, name);
+ state->response.data.name.type = type;
+
+ return WINBINDD_OK;
+}
+
+/* Convert a sid to a string */
+
+enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
+{
+ enum SID_NAME_USE type;
+ fstring sid_str, name_domain, name_user, name;
+ DOM_SID sid;
+
+ DEBUG(3, ("[%5d]: lookupname %s\n", state->pid,
+ state->request.data.name));
+
+ parse_domain_user(state->request.data.name, name_domain, name_user);
+
+ snprintf(name, sizeof(name), "%s\\%s", name_domain, name_user);
+
+ /* Lookup name from PDC using lsa_lookup_names() */
+
+ if (!winbindd_lookup_sid_by_name(name, &sid, &type)) {
+ return WINBINDD_ERROR;
+ }
+
+ sid_to_string(sid_str, &sid);
+ fstrcpy(state->response.data.sid.sid, sid_str);
+ state->response.data.sid.type = type;
+
+ return WINBINDD_OK;
+}
+
+/* Convert a sid to a uid. We assume we only have one rid attached to the
+ sid. */
+
+enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ uint32 user_rid;
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5d]: sid to uid %s\n", state->pid,
+ state->request.data.sid));
+
+ /* Split sid into domain sid and user rid */
+
+ string_to_sid(&sid, state->request.data.sid);
+ sid_split_rid(&sid, &user_rid);
+
+ /* Find domain this sid belongs to */
+
+ if ((domain = find_domain_from_sid(&sid)) == NULL) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &sid);
+ DEBUG(1, ("Could not find domain for sid %s\n", sid_str));
+ return WINBINDD_ERROR;
+ }
+
+ /* Find uid for this sid and return it */
+
+ if (!winbindd_idmap_get_uid_from_rid(domain->name, user_rid,
+ &state->response.data.uid)) {
+ DEBUG(1, ("Could not get uid for sid %s\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ return WINBINDD_OK;
+}
+
+/* Convert a sid to a gid. We assume we only have one rid attached to the
+ sid.*/
+
+enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ uint32 group_rid;
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5d]: sid to gid %s\n", state->pid,
+ state->request.data.sid));
+
+ /* Split sid into domain sid and user rid */
+
+ string_to_sid(&sid, state->request.data.sid);
+ sid_split_rid(&sid, &group_rid);
+
+ /* Find domain this sid belongs to */
+
+ if ((domain = find_domain_from_sid(&sid)) == NULL) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &sid);
+ DEBUG(1, ("Could not find domain for sid %s\n", sid_str));
+ return WINBINDD_ERROR;
+ }
+
+ /* Find uid for this sid and return it */
+
+ if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid,
+ &state->response.data.gid)) {
+ DEBUG(1, ("Could not get gid for sid %s\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ return WINBINDD_OK;
+}
+
+/* Convert a uid to a sid */
+
+enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ uint32 user_rid;
+ DOM_SID sid;
+
+ /* Bug out if the uid isn't in the winbind range */
+
+ if ((state->request.data.uid < server_state.uid_low ) ||
+ (state->request.data.uid > server_state.uid_high)) {
+ return WINBINDD_ERROR;
+ }
+
+ DEBUG(3, ("[%5d]: uid to sid %d\n", state->pid,
+ state->request.data.uid));
+
+ /* Lookup rid for this uid */
+
+ if (!winbindd_idmap_get_rid_from_uid(state->request.data.uid,
+ &user_rid, &domain)) {
+ DEBUG(1, ("Could not convert uid %d to rid\n",
+ state->request.data.uid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Construct sid and return it */
+
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, user_rid);
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_USER;
+
+ return WINBINDD_OK;
+}
+
+/* Convert a gid to a sid */
+
+enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ uint32 group_rid;
+ DOM_SID sid;
+
+ /* Bug out if the gid isn't in the winbind range */
+
+ if ((state->request.data.gid < server_state.gid_low) ||
+ (state->request.data.gid > server_state.gid_high)) {
+ return WINBINDD_ERROR;
+ }
+
+ DEBUG(3, ("[%5d]: gid to sid %d\n", state->pid,
+ state->request.data.gid));
+
+ /* Lookup rid for this uid */
+
+ if (!winbindd_idmap_get_rid_from_gid(state->request.data.gid,
+ &group_rid, &domain)) {
+ DEBUG(1, ("Could not convert gid %d to rid\n",
+ state->request.data.gid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Construct sid and return it */
+
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, group_rid);
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_DOM_GRP;
+
+ return WINBINDD_OK;
+}
diff --git a/testsuite/lib/default-nt-names.exp b/testsuite/lib/default-nt-names.exp
new file mode 100644
index 00000000000..5d01d2a5bb3
--- /dev/null
+++ b/testsuite/lib/default-nt-names.exp
@@ -0,0 +1,20 @@
+#
+# A list of default domain/local users/groups. Unfortunately this is tied
+# to the English language version of Windows NT.
+#
+
+global domain
+
+# Domain users and groups
+
+set domain_users [list "$domain/Administrator" "$domain/Guest"]
+
+set domain_groups [list "$domain/Domain Admins" "$domain/Domain Guests" \
+ "$domain/Domain Users"]
+
+# Local groups
+
+set local_groups [list "BUILTIN/Replicator" "BUILTIN/Server Operators" \
+ "BUILTIN/Account Operators" "BUILTIN/Backup Operators" \
+ "BUILTIN/Print Operators" "BUILTIN/Guests" "BUILTIN/Users" \
+ "BUILTIN/Administrators"]
diff --git a/testsuite/lib/nsswitch-config.exp b/testsuite/lib/nsswitch-config.exp
new file mode 100644
index 00000000000..38342685dfa
--- /dev/null
+++ b/testsuite/lib/nsswitch-config.exp
@@ -0,0 +1,21 @@
+#
+# Load environment variables
+#
+
+global tool
+
+if { [file exists "deja-$tool.tcl"] } {
+ source "deja-$tool.tcl"
+}
+
+# Required options
+
+if { ![info exists WORKGROUP] } {
+ error "\$WORKGROUP not set in config file"
+}
+
+if { ![info exists PDC] } {
+ error "\$PDC not set in config file"
+}
+
+set domain $WORKGROUP
diff --git a/testsuite/nsswitch/.cvsignore b/testsuite/nsswitch/.cvsignore
new file mode 100644
index 00000000000..1c30875a884
--- /dev/null
+++ b/testsuite/nsswitch/.cvsignore
@@ -0,0 +1,12 @@
+initgroups
+nss_winbind_syms
+getgrent_r
+getgrgid
+getgrnam
+getpwent_r
+getpwnam
+wbtorture
+leaktest?
+getpwuid
+getent_pwent
+getent_grent
diff --git a/testsuite/nsswitch/Makefile.longarg b/testsuite/nsswitch/Makefile.longarg
new file mode 100644
index 00000000000..6cc7ef8306d
--- /dev/null
+++ b/testsuite/nsswitch/Makefile.longarg
@@ -0,0 +1,5 @@
+#
+# Makefile for null tests
+#
+
+longarg_getpwnam: longarg_getpwnam.o \ No newline at end of file
diff --git a/testsuite/nsswitch/envvar.exp b/testsuite/nsswitch/envvar.exp
new file mode 100644
index 00000000000..134a8b37a85
--- /dev/null
+++ b/testsuite/nsswitch/envvar.exp
@@ -0,0 +1,282 @@
+#
+# @(#) Test operation of WINBINDD_DOMAIN environment variable
+#
+
+load_lib "util-defs.exp"
+load_lib "$srcdir/lib/nsswitch-config.exp"
+
+#
+# @(#) Test that there is at least one domain user and domain group
+# @(#) in the output of getent passwd and getent group.
+#
+
+# Get list of users and groups
+
+set user_list [util_start "getent passwd"]
+set group_list [util_start "getent group"]
+
+verbose "user list is:\n$user_list"
+verbose "group list is:\n$group_list"
+
+# Check for domain users
+
+set no_dom 0
+
+if { ![regexp "$domain/" $user_list] } {
+ fail "no domain users in getent"
+ set no_dom 1
+}
+
+# Check for domain groups
+
+if { ![regexp "$domain/" $group_list] } {
+ fail "no domain groups in getent group"
+ set no_dom 1
+}
+
+if { $no_dom } {
+ return
+}
+
+#
+# @(#) Check for "leakage" between different domains using the
+# @(#) WINBINDD_DOMAIN environment variable.
+#
+
+verbose "Domain is $domain"
+
+set output [util_start "bin/wbinfo" "-m"]
+verbose "Trusted domains are $output"
+set trusted_domain_list [split $output "\n"]
+
+# Test simple inclusion by setting $WINBINDD_DOMAIN to each trusted domain
+# in turn and checking there are no users/groups from other domains in the
+# output of getent.
+
+set domain_list $trusted_domain_list
+lappend domain_list $domain
+
+foreach { the_domain } $domain_list {
+
+ set env(WINBINDD_DOMAIN) $the_domain
+
+ set user_out [util_start "getent passwd"]
+ set group_out [util_start "getent group"]
+
+ verbose "users in $the_domain:\n$user_out\n"
+ verbose "groups in $the_domain:\n$group_out\n"
+
+ # Users
+
+ set test_desc "users in WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { user } [split $user_out "\n"] {
+ set user_name [lindex [split $user ":"] 0]
+ if { [regexp "/" $user_name] && ![regexp $the_domain $user_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups in WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { group } [split $group_out "\n"] {
+ set group_name [lindex [split $group ":"] 0]
+ if { [regexp "/" $group_name] && ![regexp $the_domain $group_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+#
+# @(#) Test inclusion of a dummy domain doesn't generate users/groups
+# @(#) from that domain.
+#
+
+set env(WINBINDD_DOMAIN) "asmithee"
+set user_out [util_start "getent passwd"]
+set group_out [util_start "getent group"]
+
+# Users
+
+set test_desc "users in different WINBINDD_DOMAIN"
+if { [regexp $domain $user_out] } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Groups
+
+set test_desc "groups in different WINBINDD_DOMAIN"
+if { [regexp $domain $group_out] } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+#
+# @(#) Test comma separated inclusion of dummy domain doesn't generate
+# @(#) users/groups in the dummy domain.
+#
+
+foreach { the_domain } $domain_list {
+ set env(WINBINDD_DOMAIN) "$the_domain,asmithee"
+ set user_out [util_start "getent passwd"]
+ set group_out [util_start "getent group"]
+
+ verbose "users in $the_domain:\n$user_out\n"
+ verbose "groups in $the_domain:\n$group_out\n"
+
+ # Users
+
+ set test_desc "users in comma separated WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { user } [split $user_out "\n"] {
+ set user_name [lindex [split $user ":"] 0]
+ if { [regexp "/" $user_name] && ![regexp $the_domain $user_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups in comma separated WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { group } [split $group_out "\n"] {
+ set group_name [lindex [split $group ":"] 0]
+ if { [regexp "/" $group_name] && ![regexp $the_domain $group_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+#
+# @(#) Test two comma separated dummy domains do not generate any domain
+# @(#) users or groups.
+#
+
+foreach { the_domain } $domain_list {
+
+ set env(WINBINDD_DOMAIN) "moose,asmithee"
+ set user_out [util_start "getent passwd"]
+ set group_out [util_start "getent group"]
+
+ verbose "users in $the_domain:\n$user_out\n"
+ verbose "groups in $the_domain:\n$group_out\n"
+
+ # Users
+
+ set test_desc "users in comma separated invalid WINBINDD_DOMAIN"
+ if { [regexp $the_domain $user_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups in comma separated invalid WINBINDD_DOMAIN"
+ if { [regexp $the_domain $group_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+set env(WINBINDD_DOMAIN) ""
+
+#
+# @(#) Test _NO_WINBINDD doesn't return any domain users or groups
+#
+
+set env(_NO_WINBINDD) "1"
+set user_out [util_start "getent passwd"]
+set group_out [util_start "getent group"]
+
+verbose "users with _NO_WINBINDD:\n$user_out\n"
+verbose "groups with _NO_WINBINDD:\n$group_out\n"
+
+foreach { the_domain } $domain_list {
+
+ # Users
+
+ set test_desc "users found with _NO_WINBINDD environment variable set"
+ if { [regexp $the_domain $user_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups found with _NO_WINBINDD environment variable set"
+ if { [regexp $the_domain $group_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Unset _NO_WINBINDD and make sure everything still works
+
+unset env(_NO_WINBINDD)
+
+set user_out [util_start "getent passwd"]
+set group_out [util_start "getent group"]
+
+verbose "users with _NO_WINBINDD unset:\n$user_out\n"
+verbose "groups with _NO_WINBINDD unset:\n$group_out\n"
+
+# Users
+
+set test_desc "no users found with _NO_WINBINDD environment variable set"
+if { $user_out != $user_list } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Groups
+
+set test_desc "no groups found with _NO_WINBINDD environment variable set"
+if { $group_out != $group_list } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Make sure we unset the environment vars so we don't cause subsequent tests
+# any grief.
+
+catch { unset env(WINBINDD_DOMAIN) } tmp
+catch { unset env(_NO_WINBINDD) } tmp
diff --git a/testsuite/nsswitch/getent.c b/testsuite/nsswitch/getent.c
new file mode 100644
index 00000000000..b4c4e50c6fe
--- /dev/null
+++ b/testsuite/nsswitch/getent.c
@@ -0,0 +1,151 @@
+/* Cut down version of getent which only returns passwd and group database
+ entries and seems to compile on most systems without too much fuss.
+ Original copyright notice below. */
+
+/* Copyright (c) 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+
+group_keys (int number, char *key[])
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < number; ++i)
+ {
+ struct group *grp;
+
+ if (isdigit (key[i][0]))
+ grp = getgrgid (atol (key[i]));
+ else
+ grp = getgrnam (key[i]);
+
+ if (grp == NULL)
+ result = 2;
+ else
+ print_group (grp);
+ }
+
+ return result;
+}
+
+passwd_keys (int number, char *key[])
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < number; ++i)
+ {
+ struct passwd *pwd;
+
+ if (isdigit (key[i][0]))
+ pwd = getpwuid (atol (key[i]));
+ else
+ pwd = getpwnam (key[i]);
+
+ if (pwd == NULL)
+ result = 2;
+ else
+ print_passwd (pwd);
+ }
+
+ return result;
+}
+
+print_group (struct group *grp)
+{
+ unsigned int i = 0;
+
+ printf ("%s:%s:%ld:", grp->gr_name ? grp->gr_name : "",
+ grp->gr_passwd ? grp->gr_passwd : "",
+ (unsigned long)grp->gr_gid);
+
+ while (grp->gr_mem[i] != NULL)
+ {
+ fputs (grp->gr_mem[i], stdout);
+ ++i;
+ if (grp->gr_mem[i] != NULL)
+ fputs (",", stdout);
+ }
+ fputs ("\n", stdout);
+}
+
+print_passwd (struct passwd *pwd)
+{
+ printf ("%s:%s:%ld:%ld:%s:%s:%s\n",
+ pwd->pw_name ? pwd->pw_name : "",
+ pwd->pw_passwd ? pwd->pw_passwd : "",
+ (unsigned long)pwd->pw_uid,
+ (unsigned long)pwd->pw_gid,
+ pwd->pw_gecos ? pwd->pw_gecos : "",
+ pwd->pw_dir ? pwd->pw_dir : "",
+ pwd->pw_shell ? pwd->pw_shell : "");
+}
+
+int main(int argc, char **argv)
+{
+ switch(argv[1][0])
+ {
+ case 'g': /* group */
+ if (strcmp (argv[1], "group") == 0)
+ {
+ if (argc == 2)
+ {
+ struct group *grp;
+
+ setgrent ();
+ while ((grp = getgrent()) != NULL)
+ print_group (grp);
+ endgrent ();
+ }
+ else
+ return group_keys (argc - 2, &argv[2]);
+ }
+ else
+ goto error;
+ break;
+
+ case 'p': /* passwd, protocols */
+ if (strcmp (argv[1], "passwd") == 0)
+ {
+ if (argc == 2)
+ {
+ struct passwd *pwd;
+
+ setpwent ();
+ while ((pwd = getpwent()) != NULL)
+ print_passwd (pwd);
+ endpwent ();
+ }
+ else
+ return passwd_keys (argc - 2, &argv[2]);
+ }
+ else
+ goto error;
+ break;
+ default:
+ error:
+ fprintf (stderr, "Unknown database: %s\n", argv[1]);
+ return 1;
+ }
+ return 0;
+}
diff --git a/testsuite/nsswitch/getent_grent.c b/testsuite/nsswitch/getent_grent.c
new file mode 100644
index 00000000000..782cc0c86b7
--- /dev/null
+++ b/testsuite/nsswitch/getent_grent.c
@@ -0,0 +1,101 @@
+/* Test out of order operations with {set,get,end}grent */
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <grp.h>
+
+int main (int argc, char **argv)
+{
+ struct group *gr;
+ int found = 0;
+ int num_users, i;
+
+ /* Test getgrent() without setgrent() */
+
+ for (i = 0; i < 100; i++) {
+ gr = getgrent();
+
+ /* This is supposed to work */
+
+#if 0
+ if (gr != NULL) {
+ printf("FAIL: getgrent() with no setgrent()\n");
+ return 1;
+ }
+#endif
+ }
+
+ /* Work out how many user till first domain group */
+
+ num_users = 0;
+ setgrent();
+
+ while (1) {
+ gr = getgrent();
+ num_users++;
+
+ if (gr == NULL) break;
+
+ if (strchr(gr->gr_name, '/')) {
+ found = 1;
+ break;
+ }
+
+ }
+
+ if (!found) {
+ printf("FAIL: could not find any domain groups\n");
+ return 1;
+ }
+
+ /* Test stopping getgrent in the middle of a set of users */
+
+ endgrent();
+
+ /* Test setgrent() without any getgrent() calls */
+
+ setgrent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getgrent();
+ }
+
+ endgrent();
+
+ /* Test lots of setgrent() calls */
+
+ for (i = 0; i < 100; i++) {
+ setgrent();
+ }
+
+ /* Test lots of endgrent() calls */
+
+ for (i = 0; i < 100; i++) {
+ endgrent();
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/getent_pwent.c b/testsuite/nsswitch/getent_pwent.c
new file mode 100644
index 00000000000..96c804433a4
--- /dev/null
+++ b/testsuite/nsswitch/getent_pwent.c
@@ -0,0 +1,113 @@
+/* Test out of order operations with {set,get,end}pwent */
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <pwd.h>
+
+int main (int argc, char **argv)
+{
+ struct passwd *pw;
+ int found = 0;
+ int num_users, i;
+
+ /* Test getpwent() without setpwent() */
+
+ for (i = 0; i < 100; i++) {
+ pw = getpwent();
+
+ /* This is supposed to work */
+
+#if 0
+ if (pw != NULL) {
+ printf("FAIL: getpwent() with no setpwent()\n");
+ return 1;
+ }
+#endif
+ }
+
+ /* Work out how many user till first domain user */
+
+ num_users = 0;
+ setpwent();
+
+ while (1) {
+ pw = getpwent();
+ num_users++;
+
+ if (pw == NULL) break;
+
+ if (strchr(pw->pw_name, '/')) {
+ found = 1;
+ break;
+ }
+
+ }
+
+ if (!found) {
+ printf("FAIL: could not find any domain users\n");
+ return 1;
+ }
+
+ /* Test stopping getpwent in the middle of a set of users */
+
+ endpwent();
+
+ /* Test setpwent() without any getpwent() calls */
+
+ setpwent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getpwent();
+ }
+
+ endpwent();
+
+ /* Test lots of setpwent() calls */
+
+ setpwent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getpwent();
+ }
+
+ for (i = 0; i < 100; i++) {
+ setpwent();
+ }
+
+ /* Test lots of endpwent() calls */
+
+ setpwent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getpwent();
+ }
+
+ for (i = 0; i < 100; i++) {
+ endpwent();
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/groupmem_dom.exp b/testsuite/nsswitch/groupmem_dom.exp
new file mode 100644
index 00000000000..3ba34bb810e
--- /dev/null
+++ b/testsuite/nsswitch/groupmem_dom.exp
@@ -0,0 +1,33 @@
+#
+# @(#) Test whether members of domain groups all have domain names
+#
+
+load_lib util-defs.exp
+
+set group_list [split [util_start "getent group" ""] "\n"]
+set failed 0
+
+foreach { group } $group_list {
+ set group_entry [split $group ":"]
+
+ set group_name [lindex $group_entry 0]
+ set group_members [split [lindex $group_entry 3] ","]
+
+ if { [regexp {^[^/]+/} $group_name] } {
+
+ verbose "group $group_name has members $group_members"
+
+ foreach { user } $group_members {
+ if { ![regexp {^[^/]+/} $user] } {
+ fail "group $group has non-domain user $user"
+ set failed 1
+ }
+ }
+ } else {
+ verbose "ignoring non-domain group $group_name"
+ }
+}
+
+if { !$failed } {
+ pass "domain groups contain only domain members"
+}
diff --git a/testsuite/nsswitch/initgroups.c b/testsuite/nsswitch/initgroups.c
new file mode 100644
index 00000000000..b7d9c50eaa3
--- /dev/null
+++ b/testsuite/nsswitch/initgroups.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv)
+{
+ int result, ngroups, i;
+ gid_t *groups;
+ struct passwd *pw;
+
+ if (!(pw = getpwnam(argv[1]))) {
+ printf("FAIL: no passwd entry for %s\n", argv[1]);
+ return 1;
+ }
+
+ result = initgroups(argv[1], pw->pw_gid);
+
+ if (result == -1) {
+ printf("FAIL");
+ return 1;
+ }
+
+ ngroups = getgroups(0, NULL);
+
+ groups = (gid_t *)malloc(sizeof(gid_t) * ngroups);
+ ngroups = getgroups(ngroups, groups);
+
+ printf("%s is a member of groups:\n", argv[1]);
+
+ for (i = 0; i < ngroups; i++) {
+ struct group *grp;
+
+ grp = getgrgid(groups[i]);
+
+ printf("%d (%s)\n", groups[i], grp ? grp->gr_name : "?");
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/initgroups.exp b/testsuite/nsswitch/initgroups.exp
new file mode 100644
index 00000000000..ab21bcc9e7b
--- /dev/null
+++ b/testsuite/nsswitch/initgroups.exp
@@ -0,0 +1,37 @@
+#
+# @(#) Test initgroups function
+#
+
+load_lib util-defs.exp
+load_lib compile.exp
+
+if { [util_start "id -u"] != 0 } {
+ set test_desc "must be userid 0 to run"
+ note $test_desc
+ untested $test_desc
+ return
+}
+
+# Compile test program
+
+simple_compile "initgroups"
+
+# Test domain users
+
+set user_list [split [util_start "bin/wbinfo" "-u"] "\n"]
+
+verbose $user_list
+
+foreach { user } $user_list {
+ set output [util_start "$srcdir/$subdir/initgroups" "\"$user\"" ""]
+
+ verbose $output
+
+ set test_desc "initgroups $user"
+
+ if { [regexp "PASS" $output] } {
+ pass $test_desc
+ } else {
+ fail $test_desc
+ }
+}
diff --git a/testsuite/nsswitch/longarg.exp b/testsuite/nsswitch/longarg.exp
new file mode 100644
index 00000000000..e1d0eda9ccb
--- /dev/null
+++ b/testsuite/nsswitch/longarg.exp
@@ -0,0 +1,29 @@
+#
+# @(#) Test handling of long arguments passed to various nss functions
+#
+
+load_lib compile.exp
+load_lib util-defs.exp
+
+# Run tests from C source files
+
+set longarg_tests [list \
+ { "long arg to getpwnam()" "longarg_getpwnam" } \
+ { "long arg to getgrnam()" "longarg_getgrnam" } \
+ ]
+
+foreach { test } $longarg_tests {
+ set test_desc [lindex $test 0]
+ set test_file [lindex $test 1]
+
+ simple_make "longarg" $test_file
+ set output [util_start "$srcdir/$subdir/$test_file" ]
+
+ if { [regexp "PASS" $output] } {
+ pass $test_desc
+ file delete "$srcdir/$subdir/$test_file" "$srcdir/$subdir/$test_file.o"
+ } else {
+ fail $test_desc
+ puts $output
+ }
+}
diff --git a/testsuite/nsswitch/longarg_getgrnam.c b/testsuite/nsswitch/longarg_getgrnam.c
new file mode 100644
index 00000000000..84083d2620e
--- /dev/null
+++ b/testsuite/nsswitch/longarg_getgrnam.c
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grp.h>
+#include <sys/types.h>
+
+#include "longarg_utils.h"
+
+int main(void)
+{
+ struct group *grp;
+ char *domain = getenv("TEST_WORKGROUP");
+ char long_name[65535];
+ int failed = 0;
+
+ sprintf(long_name, "%s/%s", domain, LONG_STRING);
+
+ grp = getgrnam(long_name);
+ printf("%s\n", !grp ? "PASS" : "FAIL");
+
+ return grp == NULL;
+}
diff --git a/testsuite/nsswitch/longarg_getpwnam.c b/testsuite/nsswitch/longarg_getpwnam.c
new file mode 100644
index 00000000000..f2a0a73ddca
--- /dev/null
+++ b/testsuite/nsswitch/longarg_getpwnam.c
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+#include "longarg_utils.h"
+
+int main(void)
+{
+ struct passwd *pwd;
+ char *domain = getenv("TEST_WORKGROUP");
+ char long_name[65535];
+ int failed = 0;
+
+ sprintf(long_name, "%s/%s", domain, LONG_STRING);
+
+ pwd = getpwnam(long_name);
+ printf("%s\n", !pwd ? "PASS" : "FAIL");
+
+ return pwd == NULL;
+}
diff --git a/testsuite/nsswitch/longarg_utils.h b/testsuite/nsswitch/longarg_utils.h
new file mode 100644
index 00000000000..1f2f2a7065d
--- /dev/null
+++ b/testsuite/nsswitch/longarg_utils.h
@@ -0,0 +1,27 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _LONGARG_UTILS_H
+#define _LONGARG_UTILS_H
+
+#define LONG_STRING "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+#endif
diff --git a/testsuite/nsswitch/wbinfo.exp b/testsuite/nsswitch/wbinfo.exp
new file mode 100644
index 00000000000..3518db387be
--- /dev/null
+++ b/testsuite/nsswitch/wbinfo.exp
@@ -0,0 +1,360 @@
+#
+# @(#) Test wbinfo client access to winbind daemon
+#
+
+load_lib "util-defs.exp"
+load_lib "$srcdir/lib/nsswitch-config.exp"
+load_lib "$srcdir/lib/default-nt-names.exp"
+
+# Name types
+
+set SID_NAME_USER 1
+set SID_NAME_DOM_GRP 2
+set SID_NAME_DOMAIN 3
+set SID_NAME_ALIAS 4
+set SID_NAME_UNKNOWN 8
+
+# Get list of users and groups
+
+set user_list [util_start "bin/wbinfo" "-u"]
+set group_list [util_start "bin/wbinfo" "-g"]
+
+verbose "user list is:\n$user_list"
+verbose "group list is:\n$group_list"
+
+set user_list [split $user_list "\n"]
+set group_list [split $group_list "\n"]
+
+#
+# @(#) Check list of users and groups contain default NT user and group
+# @(#) names
+#
+
+# Users
+
+foreach { user } $domain_users {
+ set test_desc "user $user in wbinfo domain users"
+ if {![regexp $user $user_list]} {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Groups
+
+foreach { group } $domain_groups {
+ set test_desc "group $group in wbinfo domain groups"
+ if {![regexp $group $group_list]} {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+#
+# @(#) Lookup sids for all user and group names returned by wbinfo
+#
+
+# Users
+
+foreach { user } $user_list {
+ set test_desc "get sid for user $user"
+ set output [util_start "bin/wbinfo" "-n \"$user\""]
+
+ verbose $output
+
+ # Split output into name and name_type
+
+ set list [split $output " "]
+ set sid_type [lindex $list [expr [llength $list] - 1]]
+ set sid [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { ![regexp "S-" $sid] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "sid type for user $user"
+ if { $sid_type != $SID_NAME_USER } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ lappend user_sid_list $sid
+}
+
+# Groups
+
+foreach { group } $group_list {
+ set test_desc "get sid for group $group"
+ set output [util_start "bin/wbinfo" "-n \"$group\""]
+
+ verbose $output
+
+ # Split output into sid and sid type
+
+ set list [split $output " "]
+ set sid_type [lindex $list [expr [llength $list] - 1]]
+ set sid [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { ![regexp "S-" $sid] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "sid type for group group"
+ if { $sid_type != $SID_NAME_DOM_GRP } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ lappend group_sid_list $sid
+}
+
+#
+# @(#) Check reverse lookup of sids to names
+#
+
+# Users
+
+set count 0
+
+foreach { sid } $user_sid_list {
+ set test_desc "reverse user name lookup for sid $sid"
+ set output [util_start "bin/wbinfo" "-s $sid"]
+
+ verbose $output
+
+ # Split output into name and name_type
+
+ set list [split $output " "]
+ set name_type [lindex $list [expr [llength $list] - 1]]
+ set name [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { $name != [lindex $user_list $count] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "reverse user name type lookup for sid $sid"
+
+ if { $name_type != 1 } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ incr count
+}
+
+# Groups
+
+set count 0
+
+foreach { sid } $group_sid_list {
+ set test_desc "reverse group name lookup for sid $sid"
+ set output [util_start "bin/wbinfo" "-s $sid"]
+
+ verbose $output
+
+ # Split output into name and name_type
+
+ set list [split $output " "]
+ set name_type [lindex $list [expr [llength $list] - 1]]
+ set name [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { $name != [lindex $group_list $count] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "reverse group name type lookup for sid $sid"
+
+ if { $name_type != 2 } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ incr count
+}
+
+#
+# @(#) Cross-check the output of wbinfo -n, getent passwd/group and
+# @(#) wbinfo -S
+#
+
+# Get mapped list of uids from winbindd
+
+set output [util_start "getent" "passwd"]
+set user_list [split $output "\n"]
+
+foreach { user_entry } $user_list {
+ if { [regexp $domain $user_entry] } {
+ set field_list [split $user_entry ":"]
+ set name_output [util_start "bin/wbinfo" \
+ "-n \"[lindex $field_list 0]\""]
+ set list [split $name_output " "]
+ set name_type [lindex $list [expr [llength $list] - 1]]
+ set name [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+ set username_uid_sid [lappend username_uid_sid [list \
+ [lindex $field_list 0] \
+ [lindex $field_list 2] \
+ $name]]
+ }
+}
+
+# Get mapped list of gids from winbindd
+
+set output [util_start "getent" "group"]
+set group_list [split $output "\n"]
+
+foreach { group_entry } $group_list {
+ if { [regexp $domain $group_entry] } {
+ set field_list [split $group_entry ":"]
+ set groupname_gid_sid [lappend groupname_gid_sid [list \
+ [lindex $field_list 0] \
+ [lindex $field_list 2] \
+ [util_start "bin/wbinfo" "-n \"[lindex $field_list 0]\""]]]
+ }
+}
+
+# OK, now we have enough info to cross-check the uid/gid -> sid and
+# sid -> uid/gid functions
+
+foreach { user } $username_uid_sid {
+ set sid [util_start "bin/wbinfo" "-U [lindex $user 1]"]
+ set uid [util_start "bin/wbinfo" "-S [lindex $user 2]"]
+
+ set test_desc "lookup sid by uid [lindex $user 1]"
+
+ if { $sid != [lindex $user 2] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "lookup uid by sid [lindex $user 2]"
+
+ if { $uid != [lindex $user 1] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+foreach { group } $groupname_gid_sid {
+ set sid [util_start "bin/wbinfo" "-G [lindex $group 1]"]
+ set gid [util_start "bin/wbinfo" "-Y [lindex $group 2]"]
+
+ set test_desc "lookup sid by gid [lindex $group 1]"
+
+ if { $sid != [lindex [split [lindex $group 2] " "] 0] ||
+ [lindex [split [lindex $group 2] " " ] 1] != 2 } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "lookup gid by sid [lindex $group 2]"
+
+ if { $gid != [lindex $group 1] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Check exit codes
+
+proc check_errcode { args } {
+ global errorCode
+ set test_desc [lindex $args 0]
+ set cmd [lindex $args 1]
+ set result [lindex $args 2]
+
+ set errorCode ""
+ verbose "Spawning $cmd"
+ catch "exec $cmd" output
+ set exit_code [lindex $errorCode 2]
+ if { $exit_code == "" } { set exit_code 0 }
+
+ if { $exit_code == $result } {
+ verbose "process returned correct exit code $exit_code"
+ pass $test_desc
+ } else {
+ verbose "process returned bad exit code $exit_code instead of $result"
+ fail $test_desc
+ }
+}
+
+set gooduser_name [lindex [split [lindex $user_list 0] ":"] 0]
+set gooduser_sid [util_start "bin/wbinfo" "-n $gooduser_name"]
+
+set goodgroup_name [lindex [split [lindex $group_list 0] ":"] 0]
+set goodgroup_sid [util_start "bin/wbinfo" "-n $goodgroup_name"]
+
+# Some conditions not tested:
+# - bad list users/groups
+# - good uid/gid to sid
+
+set errcode_tests [list \
+ { "no arg" "bin/wbinfo" 1 } \
+ { "invalid arg" "bin/wbinfo -@" 1 } \
+ { "list users" "bin/wbinfo -u" 0 } \
+ { "list groups" "bin/wbinfo -g" 0 } \
+ { "good name to sid" "bin/wbinfo -n $gooduser_name" 0 } \
+ { "bad name to sid" "bin/wbinfo -n asmithee" 0 } \
+ { "good sid to name" "bin/wbinfo -s $gooduser_sid" 0 } \
+ { "bad sid to name" "bin/wbinfo -s S-1234" 1 } \
+ { "bad uid to sid" "bin/wbinfo -U 0" 1 } \
+ { "bad gid to sid" "bin/wbinfo -G 0" 1} \
+ { "good sid to uid" "bin/wbinfo -S $gooduser_sid" 0 } \
+ { "bad sid to uid" "bin/wbinfo -S S-1234" 1 } \
+ { "good sid to gid" "bin/wbinfo -Y $goodgroup_sid" 0 } \
+ { "bad sid to gid" "bin/wbinfo -Y S-1234" 1 } \
+ ]
+
+foreach { test } $errcode_tests {
+ check_errcode [lindex $test 0] [lindex $test 1] [lindex $test 2]
+}
+
+# Test enumerate trusted domains
+
+set test_desc "enumerate trusted domains"
+set output [util_start "bin/wbinfo" "-m"]
+
+verbose $output
+
+foreach { the_domain } $output {
+ if { $the_domain == $domain} {
+ fail "own domain appears in trusted list"
+ }
+}
+
+if {[regexp "Usage" $output] || [regexp "Could not" $output]} {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Test check machine account
+
+set test_desc "check machine account"
+set output [util_start "bin/wbinfo" "-t"]
+
+verbose $output
+
+if {[regexp "Usage" $output] || [regexp "Could not" $output] || \
+ ![regexp "(good|bad)" $output]} {
+ fail $test_desc
+} else {
+ pass $test_desc
+}