summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/Makefile.in32
-rw-r--r--source3/include/smb.h8
-rw-r--r--source3/lib/util_str.c21
-rw-r--r--source3/nsswitch/wb_client.c22
-rw-r--r--source3/nsswitch/wb_common.c5
-rw-r--r--source3/nsswitch/winbind_nss_config.h19
-rw-r--r--source3/nsswitch/winbindd.c849
-rw-r--r--source3/nsswitch/winbindd.h64
-rw-r--r--source3/nsswitch/winbindd_cache.c249
-rw-r--r--source3/nsswitch/winbindd_group.c1371
-rw-r--r--source3/nsswitch/winbindd_idmap.c80
-rw-r--r--source3/nsswitch/winbindd_pam.c88
-rw-r--r--source3/nsswitch/winbindd_proto.h90
-rw-r--r--source3/nsswitch/winbindd_user.c845
-rw-r--r--source3/nsswitch/winbindd_util.c638
15 files changed, 2710 insertions, 1671 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 2b31ace4c3..e40a647fb7 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -122,7 +122,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
libsmb/passchange.o libsmb/unexpected.o $(RPC_PARSE_OBJ1)
LIBMSRPC_OBJ = libsmb/cli_lsarpc.o libsmb/cli_samr.o libsmb/cli_spoolss.o \
- rpc_client/cli_pipe.o
+ rpc_client/cli_pipe.o nsswitch/winbindd_glue.o
RPC_SERVER_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o \
rpc_server/srv_lsa_hnd.o rpc_server/srv_netlog.o rpc_server/srv_netlog_nt.o \
@@ -145,11 +145,11 @@ RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_net.o \
rpc_parse/parse_creds.o
-RPC_CLIENT_OBJ = rpc_client/cli_netlogon.o rpc_client/cli_pipe.o \
- rpc_client/cli_lsarpc.o rpc_client/cli_connect.o \
- rpc_client/cli_use.o rpc_client/cli_login.o \
- rpc_client/cli_spoolss_notify.o rpc_client/ncacn_np_use.o \
- lib/util_list.o
+#RPC_CLIENT_OBJ = rpc_client/cli_netlogon.o rpc_client/cli_pipe.o \
+# rpc_client/cli_lsarpc.o rpc_client/cli_connect.o \
+# rpc_client/cli_use.o rpc_client/cli_login.o \
+# rpc_client/cli_spoolss_notify.o rpc_client/ncacn_np_use.o \
+# lib/util_list.o
LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
@@ -351,6 +351,9 @@ PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
PAM_SMBPASS_PICOOBJ = $(PAM_SMBPASS_OBJ_0:.o=.po)
+NSS_OBJ_0 = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
+NSS_OBJ = $(NSS_OBJ_0:.o=.po)
+
WINBINDD_OBJ1 = \
nsswitch/winbindd.o \
nsswitch/winbindd_user.o \
@@ -358,13 +361,14 @@ WINBINDD_OBJ1 = \
nsswitch/winbindd_idmap.o \
nsswitch/winbindd_util.o \
nsswitch/winbindd_cache.o \
- nsswitch/winbindd_pam.o
+ nsswitch/winbindd_pam.o \
+ nsswitch/winbindd_sid.o \
+ nsswitch/winbindd_misc.o
WINBINDD_OBJ = \
- $(WINBINDD_OBJ1) \
- $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) $(STUB_UID_OBJ) \
+ $(WINBINDD_OBJ1) $(NOPROTO_OBJ) $(PASSDB_OBJ) \
$(LIBNMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
- $(NSSWINS_OBJ) $(SIDDB_OBJ) $(LIBSMB_OBJ)
+ $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) $(GROUPDB_OBJ)
WBINFO_OBJ = nsswitch/wbinfo.o
@@ -372,10 +376,6 @@ WINBIND_NSS_OBJ = nsswitch/winbind_nss.o nsswitch/wb_common.o
WINBIND_NSS_PICOBJS = $(WINBIND_NSS_OBJ:.o=.po)
-
-NSS_OBJ_0 = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
-NSS_OBJ = $(NSS_OBJ_0:.o=.po)
-
######################################################################
# now the rules...
######################################################################
@@ -623,8 +623,8 @@ bin/wbinfo: $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) $(NOPROTO_OBJ) $(UBIQX_OBJ) bi
@$(LINK) -o $@ $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) $(NOPROTO_OBJ) \
$(UBIQX_OBJ) $(LIBS)
-nsswitch: nsswitch/libnss_wins.so nsswitch/pam_winbind.so \
- nsswitch/libnss_winbind.so bin/wbinfo
+nsswitch: nsswitch/pam_winbind.so nsswitch/libnss_winbind.so bin/winbindd \
+ bin/wbinfo
bin/pam_smbpass.@SHLIBEXT@: $(PAM_SMBPASS_PICOOBJ)
@echo "Linking shared library $@"
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 0993d349a2..8b18ee5010 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1649,4 +1649,12 @@ typedef struct user_struct
#include "nsswitch/winbindd_nss.h"
#include "smb_acls.h"
+/* Used by winbindd_glue functions */
+
+typedef struct {
+ struct cli_state *cli;
+ POLICY_HND handle;
+ TALLOC_CTX *mem_ctx;
+} CLI_POLICY_HND;
+
#endif /* _SMB_H */
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index d09bd6a2b4..b517d93dd8 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -1282,24 +1282,3 @@ char *string_truncate(char *s, int length)
}
return s;
}
-
-/* Parse a string of the form DOMAIN/user into a domain and a user */
-
-void parse_domain_user(char *domuser, fstring domain, fstring user)
-{
- char *p;
- char *sep = lp_winbind_separator();
- if (!sep) sep = "\\";
- p = strchr(domuser,*sep);
- if (!p) p = strchr(domuser,'\\');
- if (!p) {
- fstrcpy(domain,"");
- fstrcpy(user, domuser);
- return;
- }
-
- fstrcpy(user, p+1);
- fstrcpy(domain, domuser);
- domain[PTR_DIFF(p, domuser)] = 0;
- strupper(domain);
-}
diff --git a/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c
index 746e5406bc..366edbbe41 100644
--- a/source3/nsswitch/wb_client.c
+++ b/source3/nsswitch/wb_client.c
@@ -25,6 +25,28 @@
#include "includes.h"
+/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
+ form DOMAIN/user into a domain and a user */
+
+static void parse_domain_user(char *domuser, fstring domain, fstring user)
+{
+ char *p;
+ char *sep = lp_winbind_separator();
+ if (!sep) sep = "\\";
+ p = strchr(domuser,*sep);
+ if (!p) p = strchr(domuser,'\\');
+ if (!p) {
+ fstrcpy(domain,"");
+ fstrcpy(user, domuser);
+ return;
+ }
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ strupper(domain);
+}
+
/* Call winbindd to convert a name to a sid */
BOOL winbind_lookup_name(const char *name, DOM_SID *sid, enum SID_NAME_USE *name_type)
diff --git a/source3/nsswitch/wb_common.c b/source3/nsswitch/wb_common.c
index 4040e1cff2..8376007424 100644
--- a/source3/nsswitch/wb_common.c
+++ b/source3/nsswitch/wb_common.c
@@ -169,6 +169,7 @@ int write_sock(void *buffer, int count)
while(nwritten < count) {
struct timeval tv;
fd_set r_fds;
+ int selret;
/* Catch pipe close on other end by checking if a read()
call would not block by calling select(). */
@@ -177,8 +178,8 @@ int write_sock(void *buffer, int count)
FD_SET(established_socket, &r_fds);
ZERO_STRUCT(tv);
- if (select(established_socket + 1, &r_fds,
- NULL, NULL, &tv) == -1) {
+ if ((selret = select(established_socket + 1, &r_fds,
+ NULL, NULL, &tv)) == -1) {
close_sock();
return -1; /* Select error */
}
diff --git a/source3/nsswitch/winbind_nss_config.h b/source3/nsswitch/winbind_nss_config.h
index 5c09a5dd1b..39fe006557 100644
--- a/source3/nsswitch/winbind_nss_config.h
+++ b/source3/nsswitch/winbind_nss_config.h
@@ -29,16 +29,6 @@
#include <config.h>
-#ifdef RELIANTUNIX
-/*
- * <unistd.h> has to be included before any other to get
- * large file support on Reliant UNIX. Yes, it's broken :-).
- */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#endif /* RELIANTUNIX */
-
#include <stdio.h>
#ifdef HAVE_STDLIB_H
@@ -173,13 +163,4 @@ typedef int BOOL;
/* zero a structure given a pointer to the structure */
#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
-/* Some systems (SCO) treat UNIX domain sockets as FIFOs */
-
-#ifndef S_IFSOCK
-#define S_IFSOCK S_IFIFO
-#endif
-#ifndef S_ISSOCK
-#define S_ISSOCK(mode) ((mode & S_IFSOCK) == S_IFSOCK)
-#endif
-
#endif
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index b0e35f3cd6..9d315a0811 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -23,17 +23,29 @@
#include "winbindd.h"
+pstring servicesf = CONFIGFILE;
+
/* List of all connected clients */
-static struct winbindd_cli_state *client_list;
+struct winbindd_cli_state *client_list;
+static int num_clients;
/* Reload configuration */
-static BOOL reload_services_file(void)
+static BOOL reload_services_file(BOOL test)
{
- pstring servicesf = CONFIGFILE;
BOOL ret;
+ if (lp_loaded()) {
+ pstring fname;
+
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) {
+ pstrcpy(servicesf,fname);
+ test = False;
+ }
+ }
+
reopen_logs();
ret = lp_load(servicesf,False,False,True);
@@ -43,61 +55,75 @@ static BOOL reload_services_file(void)
return(ret);
}
-/* Print client information */
-
-static void do_print_client_info(void)
+void winbindd_dump_status(void)
{
- struct winbindd_cli_state *client;
- int i;
-
- if (client_list == NULL) {
- DEBUG(0, ("no clients in list\n"));
- return;
- }
+ struct winbindd_cli_state *tmp;
+
+ DEBUG(0, ("Global status for winbindd:\n"));
+
+ /* Print client state information */
+
+ DEBUG(0, ("\t%d clients currently active\n", num_clients));
+
+ if (DEBUGLEVEL >= 2) {
+ DEBUG(2, ("\tclient list:\n"));
+ for(tmp = client_list; tmp; tmp = tmp->next) {
+ DEBUG(2, ("\t\tpid %d, sock %d, rbl %d, wbl %d\n",
+ tmp->pid, tmp->sock, tmp->read_buf_len,
+ tmp->write_buf_len));
+ }
+ }
+}
- DEBUG(0, ("client list is:\n"));
+/* Print winbindd status to log file */
- for (client = client_list, i = 0; client; client = client->next) {
- DEBUG(0, ("client %3d: pid = %5d fd = %d read = %4d write = %4d\n",
- i, client->pid, client->sock, client->read_buf_len,
- client->write_buf_len));
- i++;
- }
+static void do_print_winbindd_status(void)
+{
+ winbindd_dump_status();
+ winbindd_idmap_dump_status();
+ winbindd_cache_dump_status();
}
/* Flush client cache */
static void do_flush_caches(void)
{
- /* Clear cached user and group enumation info */
-
- winbindd_flush_cache();
+ /* Clear cached user and group enumation info */
+
+ winbindd_flush_cache();
}
/* Handle the signal by unlinking socket and exiting */
static void termination_handler(int signum)
{
- pstring path;
+ pstring path;
+
+ /* Remove socket file */
+
+ snprintf(path, sizeof(path), "%s/%s",
+ WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
+ unlink(path);
+
+ exit(0);
+}
- /* Remove socket file */
+static BOOL print_winbindd_status;
- slprintf(path, sizeof(path)-1, "%s/%s",
- WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
- unlink(path);
-
- exit(0);
+static void sigusr1_handler(int signum)
+{
+ BlockSignals(True, SIGUSR1);
+ print_winbindd_status = True;
+ BlockSignals(False, SIGUSR1);
}
-static BOOL print_client_info;
-
-static BOOL flush_cache;
+static BOOL do_sighup;
static void sighup_handler(int signum)
{
- BlockSignals(True, SIGHUP);
- flush_cache = True;
- BlockSignals(False, SIGHUP);
+ BlockSignals(True, SIGHUP);
+ do_sighup = True;
+ BlockSignals(False, SIGHUP);
}
/* Create winbindd socket */
@@ -120,14 +146,14 @@ static int create_sock(void)
if (mkdir(WINBINDD_SOCKET_DIR, 0755) == -1) {
DEBUG(0, ("error creating socket directory %s: %s\n",
- WINBINDD_SOCKET_DIR, sys_errlist[errno]));
+ WINBINDD_SOCKET_DIR, strerror(errno)));
return -1;
}
} else {
DEBUG(0, ("lstat failed on socket directory %s: %s\n",
- WINBINDD_SOCKET_DIR, sys_errlist[errno]));
+ WINBINDD_SOCKET_DIR, strerror(errno)));
return -1;
}
@@ -159,7 +185,7 @@ static int create_sock(void)
return -1;
}
- slprintf(path, sizeof(path)-1, "%s/%s",
+ snprintf(path, sizeof(path), "%s/%s",
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
unlink(path);
@@ -170,7 +196,7 @@ static int create_sock(void)
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
DEBUG(0, ("bind failed on winbind socket %s: %s\n",
path,
- sys_errlist[errno]));
+ strerror(errno)));
close(sock);
return -1;
}
@@ -178,7 +204,7 @@ static int create_sock(void)
if (listen(sock, 5) == -1) {
DEBUG(0, ("listen failed on winbind socket %s: %s\n",
path,
- sys_errlist[errno]));
+ strerror(errno)));
close(sock);
return -1;
}
@@ -190,377 +216,420 @@ static int create_sock(void)
return sock;
}
-static void process_request(struct winbindd_cli_state *state)
-{
- /* Process command */
+struct dispatch_table {
+ enum winbindd_cmd cmd;
+ enum winbindd_result (*fn)(struct winbindd_cli_state *state);
+};
- state->response.result = WINBINDD_ERROR;
- state->response.length = sizeof(struct winbindd_response);
+static struct dispatch_table dispatch_table[] = {
+
+ /* User functions */
- DEBUG(3,("processing command %s from pid %d\n",
- winbindd_cmd_to_string(state->request.cmd), state->pid));
+ { WINBINDD_GETPWNAM_FROM_USER, winbindd_getpwnam_from_user },
+ { WINBINDD_GETPWNAM_FROM_UID, winbindd_getpwnam_from_uid },
+ { WINBINDD_SETPWENT, winbindd_setpwent },
+ { WINBINDD_ENDPWENT, winbindd_endpwent },
+ { WINBINDD_GETPWENT, winbindd_getpwent },
+ { WINBINDD_GETGROUPS, winbindd_getgroups },
- if (!server_state.lsa_handle_open) return;
+ /* Group functions */
- switch(state->request.cmd) {
-
- /* User functions */
-
- case WINBINDD_GETPWNAM_FROM_USER:
- state->response.result = winbindd_getpwnam_from_user(state);
- break;
-
- case WINBINDD_GETPWNAM_FROM_UID:
- state->response.result = winbindd_getpwnam_from_uid(state);
- break;
-
- case WINBINDD_SETPWENT:
- state->response.result = winbindd_setpwent(state);
- break;
-
- case WINBINDD_ENDPWENT:
- state->response.result = winbindd_endpwent(state);
- break;
-
- case WINBINDD_GETPWENT:
- state->response.result = winbindd_getpwent(state);
- break;
+ { WINBINDD_GETGRNAM_FROM_GROUP, winbindd_getgrnam_from_group },
+ { WINBINDD_GETGRNAM_FROM_GID, winbindd_getgrnam_from_gid },
+ { WINBINDD_SETGRENT, winbindd_setgrent },
+ { WINBINDD_ENDGRENT, winbindd_endgrent },
+ { WINBINDD_GETGRENT, winbindd_getgrent },
- /* Group functions */
-
- case WINBINDD_GETGRNAM_FROM_GROUP:
- state->response.result = winbindd_getgrnam_from_group(state);
- break;
-
- case WINBINDD_GETGRNAM_FROM_GID:
- state->response.result = winbindd_getgrnam_from_gid(state);
- break;
-
- case WINBINDD_SETGRENT:
- state->response.result = winbindd_setgrent(state);
- break;
-
- case WINBINDD_ENDGRENT:
- state->response.result = winbindd_endgrent(state);
- break;
-
- case WINBINDD_GETGRENT:
- state->response.result = winbindd_getgrent(state);
- break;
+ /* PAM auth functions */
- /* pam auth functions */
- case WINBINDD_PAM_AUTH:
- state->response.result = winbindd_pam_auth(state);
- break;
+ { WINBINDD_PAM_AUTH, winbindd_pam_auth },
+ { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok },
- /* Oops */
-
- default:
- DEBUG(0, ("oops - unknown winbindd command %d\n", state->request.cmd));
- break;
- }
-}
-
-/* Process a new connection by adding it to the client connection list */
+ /* Enumeration functions */
-static void new_connection(int accept_sock)
-{
- struct sockaddr_un sunaddr;
- struct winbindd_cli_state *state;
- int len, sock;
-
- /* Accept connection */
-
- len = sizeof(sunaddr);
- if ((sock = accept(accept_sock, (struct sockaddr *)&sunaddr, &len))
- == -1) {
-
- return;
- }
+ { WINBINDD_LIST_USERS, winbindd_list_users },
+ { WINBINDD_LIST_GROUPS, winbindd_list_groups },
+ { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains },
- DEBUG(6,("accepted socket %d\n", sock));
+ /* SID related functions */
- /* Create new connection structure */
+ { WINBINDD_LOOKUPSID, winbindd_lookupsid },
+ { WINBINDD_LOOKUPNAME, winbindd_lookupname },
- if ((state = (struct winbindd_cli_state *)
- malloc(sizeof(*state))) == NULL) {
+ /* S*RS related functions */
- return;
- }
+ { WINBINDD_SID_TO_UID, winbindd_sid_to_uid },
+ { WINBINDD_SID_TO_GID, winbindd_sid_to_gid },
+ { WINBINDD_GID_TO_SID, winbindd_gid_to_sid },
+ { WINBINDD_UID_TO_SID, winbindd_uid_to_sid },
- ZERO_STRUCTP(state);
- state->sock = sock;
+ /* Miscellaneous */
- /* Add to connection list */
+ { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct },
- DLIST_ADD(client_list, state);
-}
+ /* End of list */
-/* Remove a client connection from client connection list */
+ { WINBINDD_NUM_CMDS, NULL }
+};
-static void remove_client(struct winbindd_cli_state *state)
+static void process_request(struct winbindd_cli_state *state)
{
- /* It's a dead client - hold a funeral */
+ struct dispatch_table *table = dispatch_table;
- if (state != NULL) {
+ /* Free response data - we may be interrupted and receive another
+ command before being able to send this data off. */
- /* Close socket */
+ safe_free(state->response.extra_data);
- close(state->sock);
+ ZERO_STRUCT(state->response);
- /* Free any getent state */
+ state->response.result = WINBINDD_ERROR;
+ state->response.length = sizeof(struct winbindd_response);
- free_getent_state(state->getpwent_state);
- free_getent_state(state->getgrent_state);
+ /* Process command */
- /* Free any extra data */
+ if (!server_state.lsa_handle_open) return;
- safe_free(state->response.extra_data);
+ for (table = dispatch_table; table->fn; table++) {
+ if (state->request.cmd == table->cmd) {
+ state->response.result = table->fn(state);
+ break;
+ }
+ }
- /* Remove from list and free */
+ /* In case extra data pointer is NULL */
- DLIST_REMOVE(client_list, state);
- free(state);
- }
+ if (!state->response.extra_data) {
+ state->response.length = sizeof(struct winbindd_response);
+ }
}
-/* Process a complete received packet from a client */
+/* Process a new connection by adding it to the client connection list */
-static void process_packet(struct winbindd_cli_state *state)
+static void new_connection(int accept_sock)
{
- /* Process request */
+ struct sockaddr_un sunaddr;
+ struct winbindd_cli_state *state;
+ int len, sock;
+
+ /* Accept connection */
+
+ len = sizeof(sunaddr);
+ if ((sock = accept(accept_sock, (struct sockaddr *)&sunaddr, &len))
+ == -1) {
+
+ return;
+ }
+
+ DEBUG(6,("accepted socket %d\n", sock));
+
+ /* Create new connection structure */
+
+ if ((state = (struct winbindd_cli_state *)
+ malloc(sizeof(*state))) == NULL) {
+
+ return;
+ }
+
+ ZERO_STRUCTP(state);
+ state->sock = sock;
+
+ /* Add to connection list */
+
+ DLIST_ADD(client_list, state);
+ num_clients++;
+}
- state->pid = state->request.pid;
+/* Remove a client connection from client connection list */
- process_request(state);
+static void remove_client(struct winbindd_cli_state *state)
+{
+ /* It's a dead client - hold a funeral */
+
+ if (state != NULL) {
+
+ /* Close socket */
+
+ close(state->sock);
+
+ /* Free any getent state */
+
+ free_getent_state(state->getpwent_state);
+ free_getent_state(state->getgrent_state);
+
+ /* We may have some extra data that was not freed if the
+ client was killed unexpectedly */
+
+ safe_free(state->response.extra_data);
+
+ /* Remove from list and free */
+
+ DLIST_REMOVE(client_list, state);
+ free(state);
+ num_clients--;
+ }
+}
- /* Update client state */
+/* Process a complete received packet from a client */
- state->read_buf_len = 0;
- state->write_buf_len = sizeof(state->response);
+static void process_packet(struct winbindd_cli_state *state)
+{
+ /* Process request */
+
+ state->pid = state->request.pid;
+
+ process_request(state);
+
+ /* Update client state */
+
+ state->read_buf_len = 0;
+ state->write_buf_len = sizeof(struct winbindd_response);
}
/* Read some data from a client connection */
static void client_read(struct winbindd_cli_state *state)
{
- int n;
+ int n;
- /* Read data */
-
- n = read(state->sock, state->read_buf_len + (char *)&state->request,
- sizeof(state->request) - state->read_buf_len);
-
- /* Read failed, kill client */
-
- if (n == -1 || n == 0) {
- DEBUG(5,("read failed on sock %d, pid %d: %s\n",
- state->sock, state->pid,
- (n == -1) ? sys_errlist[errno] : "EOF"));
-
- state->finished = True;
- return;
- }
-
- /* Update client state */
-
- state->read_buf_len += n;
+ /* Read data */
+
+ n = read(state->sock, state->read_buf_len + (char *)&state->request,
+ sizeof(state->request) - state->read_buf_len);
+
+ /* Read failed, kill client */
+
+ if (n == -1 || n == 0) {
+ DEBUG(5,("read failed on sock %d, pid %d: %s\n",
+ state->sock, state->pid,
+ (n == -1) ? strerror(errno) : "EOF"));
+
+ state->finished = True;
+ return;
+ }
+
+ /* Update client state */
+
+ state->read_buf_len += n;
}
/* Write some data to a client connection */
static void client_write(struct winbindd_cli_state *state)
{
- char *data;
- int n;
-
- /* Write data */
-
- if (state->write_extra_data) {
-
- /* Write extra data */
-
- data = (char *)state->response.extra_data +
- state->response.length - sizeof(struct winbindd_response) -
- state->write_buf_len;
-
- } else {
-
- /* Write response structure */
-
- data = (char *)&state->response + sizeof(state->response) -
- state->write_buf_len;
- }
-
- n = write(state->sock, data, state->write_buf_len);
-
- /* Write failed, kill cilent */
-
- if (n == -1 || n == 0) {
-
- DEBUG(3,("write failed on sock %d, pid %d: %s\n",
- state->sock, state->pid,
- (n == -1) ? sys_errlist[errno] : "EOF"));
-
- state->finished = True;
- return;
- }
-
- /* Update client state */
-
- state->write_buf_len -= n;
-
- /* Have we written all data? */
+ char *data;
+ int num_written;
+
+ /* Write some data */
+
+ if (!state->write_extra_data) {
+
+ /* Write response structure */
+
+ data = (char *)&state->response + sizeof(state->response) -
+ state->write_buf_len;
+
+ } else {
+
+ /* Write extra data */
+
+ data = (char *)state->response.extra_data +
+ state->response.length -
+ sizeof(struct winbindd_response) -
+ state->write_buf_len;
+ }
+
+ num_written = write(state->sock, data, state->write_buf_len);
+
+ /* Write failed, kill cilent */
+
+ if (num_written == -1 || num_written == 0) {
+
+ DEBUG(3,("write failed on sock %d, pid %d: %s\n",
+ state->sock, state->pid,
+ (num_written == -1) ? strerror(errno) : "EOF"));
+
+ state->finished = True;
+
+ safe_free(state->response.extra_data);
+ state->response.extra_data = NULL;
+
+ return;
+ }
+
+ /* Update client state */
+
+ state->write_buf_len -= num_written;
+
+ /* Have we written all data? */
+
+ if (state->write_buf_len == 0) {
+
+ /* Take care of extra data */
+
+ if (state->write_extra_data) {
+
+ safe_free(state->response.extra_data);
+ state->response.extra_data = NULL;
+
+ state->write_extra_data = False;
+
+ } else if (state->response.length >
+ sizeof(struct winbindd_response)) {
+
+ /* Start writing extra data */
+
+ state->write_buf_len =
+ state->response.length -
+ sizeof(struct winbindd_response);
+
+ state->write_extra_data = True;
+ }
+ }
+}
- if (state->write_buf_len == 0) {
+/* Process incoming clients on accept_sock. We use a tricky non-blocking,
+ non-forking, non-threaded model which allows us to handle many
+ simultaneous connections while remaining impervious to many denial of
+ service attacks. */
- /* Take care of extra data */
+static void process_loop(int accept_sock)
+{
+ /* We'll be doing this a lot */
- if (state->response.length > sizeof(struct winbindd_response)) {
+ while (1) {
+ struct winbindd_cli_state *state;
+ fd_set r_fds, w_fds;
+ int maxfd = accept_sock, selret;
+ struct timeval timeout;
- if (state->write_extra_data) {
+ /* Free up temporary memory */
- /* Already written extra data - free it */
+ lp_talloc_free();
- safe_free(state->response.extra_data);
- state->response.extra_data = NULL;
- state->write_extra_data = False;
+ /* Do any connection establishment that is needed */
- } else {
+ establish_connections(False); /* Honour timeout */
- /* Start writing extra data */
+ /* Initialise fd lists for select() */
- state->write_buf_len = state->response.length -
- sizeof(struct winbindd_response);
- state->write_extra_data = True;
- }
- }
- }
-}
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+ FD_SET(accept_sock, &r_fds);
-/* Process incoming clients on accept_sock. We use a tricky non-blocking,
- non-forking, non-threaded model which allows us to handle many
- simultaneous connections while remaining impervious to many denial of
- service attacks. */
+ timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
+ timeout.tv_usec = 0;
-static void process_loop(int accept_sock)
-{
- /* We'll be doing this a lot */
+ /* Set up client readers and writers */
- while (1) {
- struct winbindd_cli_state *state;
- fd_set r_fds, w_fds;
- int maxfd = accept_sock, selret;
- struct timeval timeout;
+ state = client_list;
- /* do any connection establishment that is needed */
- establish_connections();
+ while (state) {
- /* Initialise fd lists for select() */
+ /* Dispose of client connection if it is marked as
+ finished */
- FD_ZERO(&r_fds);
- FD_ZERO(&w_fds);
- FD_SET(accept_sock, &r_fds);
+ if (state->finished) {
+ struct winbindd_cli_state *next = state->next;
- timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
- timeout.tv_usec = 0;
+ remove_client(state);
+ state = next;
+ continue;
+ }
- /* Set up client readers and writers */
+ /* Select requires we know the highest fd used */
- state = client_list;
+ if (state->sock > maxfd) maxfd = state->sock;
- while (state) {
- /* Dispose of client connection if it is marked as finished */
+ /* Add fd for reading */
- if (state->finished) {
- struct winbindd_cli_state *next = state->next;
+ if (state->read_buf_len != sizeof(state->request)) {
+ FD_SET(state->sock, &r_fds);
+ }
- remove_client(state);
- state = next;
- continue;
- }
+ /* Add fd for writing */
- /* Select requires we know the highest fd used */
+ if (state->write_buf_len) {
+ FD_SET(state->sock, &w_fds);
+ }
- if (state->sock > maxfd) maxfd = state->sock;
+ state = state->next;
+ }
- /* Add fd for reading */
+ /* Check signal handling things */
- if (state->read_buf_len != sizeof(state->request)) {
- FD_SET(state->sock, &r_fds);
- }
+ if (do_sighup) {
- /* Add fd for writing */
+ /* Flush winbindd cache */
- if (state->write_buf_len) {
- FD_SET(state->sock, &w_fds);
- }
+ do_flush_caches();
+ reload_services_file(True);
- state = state->next;
- }
+ /* Close and re-open all connections. This will also
+ refresh the trusted domains list */
- /* Check signal handling things */
+ winbindd_kill_all_connections();
+ establish_connections(True); /* Force re-establish */
- if (flush_cache) {
- do_flush_caches();
- reload_services_file();
- flush_cache = False;
- }
+ do_sighup = False;
+ }
- if (print_client_info) {
- do_print_client_info();
- print_client_info = False;
- }
+ if (print_winbindd_status) {
+ do_print_winbindd_status();
+ print_winbindd_status = False;
+ }
- /* Call select */
+ /* Call select */
- selret = select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+ selret = select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
- if (selret == 0) continue;
+ if (selret == 0) continue;
- if ((selret == -1 && errno != EINTR) || selret == 0) {
+ if ((selret == -1 && errno != EINTR) || selret == 0) {
- /* Select error, something is badly wrong */
+ /* Select error, something is badly wrong */
- perror("select");
- exit(1);
- }
+ perror("select");
+ exit(1);
+ }
- /* Create a new connection if accept_sock readable */
+ /* Create a new connection if accept_sock readable */
- if (selret > 0) {
+ if (selret > 0) {
- if (FD_ISSET(accept_sock, &r_fds)) {
- new_connection(accept_sock);
- }
+ if (FD_ISSET(accept_sock, &r_fds)) {
+ new_connection(accept_sock);
+ }
- /* Process activity on client connections */
+ /* Process activity on client connections */
- for (state = client_list; state ; state = state->next) {
+ for (state = client_list; state; state = state->next) {
- /* Data available for reading */
+ /* Data available for reading */
- if (FD_ISSET(state->sock, &r_fds)) {
+ if (FD_ISSET(state->sock, &r_fds)) {
- /* Read data */
+ /* Read data */
- client_read(state);
+ client_read(state);
- /* A request packet might be complete */
+ /* A request packet might be
+ complete */
- if (state->read_buf_len == sizeof(state->request)) {
- process_packet(state);
- }
- }
+ if (state->read_buf_len ==
+ sizeof(state->request)) {
+ process_packet(state);
+ }
+ }
- /* Data available for writing */
+ /* Data available for writing */
- if (FD_ISSET(state->sock, &w_fds)) {
- client_write(state);
- }
- }
- }
- }
+ if (FD_ISSET(state->sock, &w_fds)) {
+ client_write(state);
+ }
+ }
+ }
+ }
}
/* Main function */
@@ -569,87 +638,125 @@ struct winbindd_state server_state; /* Server state information */
int main(int argc, char **argv)
{
- extern pstring global_myname;
- extern pstring debugf;
- int accept_sock;
- BOOL interactive = False;
- int opt;
-
- while ((opt = getopt(argc, argv, "i")) != EOF) {
- switch (opt) {
+ extern pstring global_myname;
+ extern pstring debugf;
+ int accept_sock;
+ BOOL interactive = False;
+ int opt, new_debuglevel = -1;
+
+ /* Set environment variable so we don't recursively call ourselves.
+ This may also be useful interactively. */
+ SETENV(WINBINDD_DONT_ENV, "1", 1);
+
+ /* Initialise samba/rpc client stuff */
+
+ while ((opt = getopt(argc, argv, "id:s:")) != EOF) {
+ switch (opt) {
+
+ /* Don't become a daemon */
+
case 'i':
interactive = True;
break;
+
+ /* Run with specified debug level */
+
+ case 'd':
+ new_debuglevel = atoi(optarg);
+ break;
+
+ /* Load a different smb.conf file */
+
+ case 's':
+ pstrcpy(servicesf,optarg);
+ break;
+
default:
- printf("Unknown option %c (%d)\n", (char)opt, opt);
+ printf("Unknown option %c\n", (char)opt);
exit(1);
}
- }
+ }
- /* Initialise samba/rpc client stuff */
- slprintf(debugf, sizeof(debugf)-1, "%s/log.winbindd", LOGFILEBASE);
- setup_logging("winbindd", interactive);
- reopen_logs();
+ snprintf(debugf, sizeof(debugf), "%s/log.winbindd", LOGFILEBASE);
+ setup_logging("winbindd", interactive);
+ reopen_logs();
- if (!*global_myname) {
- char *p;
+ if (!*global_myname) {
+ char *p;
- fstrcpy(global_myname, myhostname());
- p = strchr(global_myname, '.');
- if (p) {
- *p = 0;
- }
- }
+ fstrcpy(global_myname, myhostname());
+ p = strchr(global_myname, '.');
+ if (p) {
+ *p = 0;
+ }
+ }
- TimeInit();
- charset_initialise();
- codepage_initialise(lp_client_code_page());
+ TimeInit();
+ charset_initialise();
- if (!lp_load(CONFIGFILE, True, False, False)) {
- DEBUG(0, ("error opening config file\n"));
- exit(1);
- }
+ if (!reload_services_file(False)) {
+ DEBUG(0, ("error opening config file\n"));
+ exit(1);
+ }
- if (!interactive) {
- become_daemon();
- }
- load_interfaces();
+ if (new_debuglevel != -1) {
+ DEBUGLEVEL = new_debuglevel;
+ }
- secrets_init();
+ codepage_initialise(lp_client_code_page());
- ZERO_STRUCT(server_state);
+ if (!interactive) {
+ become_daemon();
+ }
- /* Winbind daemon initialisation */
- if (!winbindd_param_init()) {
- return 1;
- }
+ load_interfaces();
- if (!winbindd_idmap_init()) {
- return 1;
- }
+ secrets_init();
- winbindd_cache_init();
+ ZERO_STRUCT(server_state);
- /* Setup signal handlers */
+ /* Winbind daemon initialisation */
- CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */
- CatchSignal(SIGQUIT, termination_handler);
- CatchSignal(SIGTERM, termination_handler);
+ if (!winbindd_param_init()) {
+ return 1;
+ }
- CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */
+ if (!winbindd_idmap_init()) {
+ return 1;
+ }
- CatchSignal(SIGHUP, sighup_handler);
+ winbindd_cache_init();
- /* Create UNIX domain socket */
+ /* Unblock all signals we are interested in as they may have been
+ blocked by the parent process. */
- if ((accept_sock = create_sock()) == -1) {
- DEBUG(0, ("failed to create socket\n"));
- return 1;
- }
+ BlockSignals(False, SIGINT);
+ BlockSignals(False, SIGQUIT);
+ BlockSignals(False, SIGTERM);
+ BlockSignals(False, SIGUSR1);
+ BlockSignals(False, SIGHUP);
+
+ /* Setup signal handlers */
+
+ CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */
+ CatchSignal(SIGQUIT, termination_handler);
+ CatchSignal(SIGTERM, termination_handler);
+
+ CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */
+
+ CatchSignal(SIGUSR1, sigusr1_handler); /* Debugging sigs */
+ CatchSignal(SIGHUP, sighup_handler);
+
+ /* Create UNIX domain socket */
+
+ if ((accept_sock = create_sock()) == -1) {
+ DEBUG(0, ("failed to create socket\n"));
+ return 1;
+ }
- /* Loop waiting for requests */
+ /* Loop waiting for requests */
- process_loop(accept_sock);
+ process_loop(accept_sock);
- return 0;
+ return 0;
}
diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h
index d333b32bcf..c848047089 100644
--- a/source3/nsswitch/winbindd.h
+++ b/source3/nsswitch/winbindd.h
@@ -49,12 +49,23 @@ struct winbindd_cli_state {
struct getent_state *getgrent_state; /* State for getgrent() */
};
+/* State between get{pw,gr}ent() calls */
+
struct getent_state {
- struct getent_state *prev, *next;
- struct acct_info *sam_entries;
- uint32 sam_entry_index, num_sam_entries;
- struct winbindd_domain *domain;
- BOOL got_sam_entries;
+ struct getent_state *prev, *next;
+ void *sam_entries;
+ uint32 sam_entry_index, num_sam_entries;
+ uint32 dispinfo_ndx;
+ BOOL got_all_sam_entries, got_sam_entries;
+ struct winbindd_domain *domain;
+};
+
+/* Storage for cached getpwent() user entries */
+
+struct getpwent_user {
+ fstring name; /* Account name */
+ fstring gecos; /* User information */
+ uint32 user_rid, group_rid; /* NT user and group rids */
};
/* Server state structure */
@@ -68,7 +79,7 @@ struct winbindd_state {
gid_t gid_low, gid_high; /* Range of gids to allocate */
/* Cached handle to lsa pipe */
- POLICY_HND lsa_handle;
+ CLI_POLICY_HND lsa_handle;
BOOL lsa_handle_open;
BOOL pwdb_initialised;
};
@@ -79,19 +90,21 @@ extern struct winbindd_state server_state; /* Server information */
struct winbindd_domain {
- /* Domain information */
-
- fstring name; /* Domain name */
- fstring controller; /* NetBIOS name of DC */
-
- DOM_SID sid; /* SID for this domain */
- BOOL got_domain_info; /* Got controller and sid */
+ /* Domain information */
- /* Cached handles to samr pipe */
- POLICY_HND sam_handle, sam_dom_handle;
- BOOL sam_handle_open, sam_dom_handle_open;
-
- struct winbindd_domain *prev, *next; /* Linked list info */
+ fstring name; /* Domain name */
+ fstring controller; /* NetBIOS name of DC */
+
+ DOM_SID sid; /* SID for this domain */
+ BOOL got_domain_info; /* Got controller and sid */
+
+ /* Cached handles to samr pipe */
+
+ CLI_POLICY_HND sam_handle, sam_dom_handle;
+ BOOL sam_handle_open, sam_dom_handle_open;
+ time_t last_check;
+
+ struct winbindd_domain *prev, *next; /* Linked list info */
};
extern struct winbindd_domain *domain_list; /* List of domains we know */
@@ -99,8 +112,23 @@ extern struct winbindd_domain *domain_list; /* List of domains we know */
#include "winbindd_proto.h"
#include "rpc_parse.h"
+#include "rpc_client.h"
#define WINBINDD_ESTABLISH_LOOP 30
#define DOM_SEQUENCE_NONE ((uint32)-1)
+/* SETENV */
+#if HAVE_SETENV
+#define SETENV(name, value, overwrite) setenv(name,value,overwrite)
+#elif HAVE_PUTENV
+#define SETENV(name, value, overwrite) \
+{ \
+ fstring envvar; \
+ slprintf(envvar, sizeof(fstring), "%s=%s", name, value); \
+ putenv(envvar); \
+}
+#else
+#define SETENV(name, value, overwrite) ;
+#endif
+
#endif /* _WINBINDD_H */
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index 7b263dfe00..2e404a7eb0 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -38,10 +38,10 @@ struct cache_rec {
void winbindd_cache_init(void)
{
/* Open tdb cache */
- unlink(lock_path("winbindd_cache.tdb"));
+
if (!(cache_tdb = tdb_open(lock_path("winbindd_cache.tdb"), 0,
- TDB_NOLOCK,
- O_RDWR | O_CREAT, 0600))) {
+ TDB_NOLOCK, O_RDWR | O_CREAT | O_TRUNC,
+ 0600))) {
DEBUG(0, ("Unable to open tdb cache - user and group caching "
"disabled\n"));
}
@@ -55,8 +55,7 @@ static uint32 cached_sequence_number(char *domain_name)
struct cache_rec rec;
time_t t = time(NULL);
- slprintf(keystr, sizeof(keystr)-1, "CACHESEQ/%s", domain_name);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+ snprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain_name);
dbuf = tdb_fetch_by_string(cache_tdb, keystr);
if (!dbuf.dptr || dbuf.dsize != sizeof(rec)) {
goto refetch;
@@ -65,7 +64,7 @@ static uint32 cached_sequence_number(char *domain_name)
free(dbuf.dptr);
if (t < (rec.mod_time + lp_winbind_cache_time())) {
- DEBUG(4,("cached sequence number for %s is %u\n",
+ DEBUG(3,("cached sequence number for %s is %u\n",
domain_name, (unsigned)rec.seq_num));
return rec.seq_num;
}
@@ -82,54 +81,56 @@ static uint32 cached_sequence_number(char *domain_name)
static BOOL cache_domain_expired(char *domain_name, uint32 seq_num)
{
if (cached_sequence_number(domain_name) != seq_num) {
- DEBUG(4,("seq %u for %s has expired\n", (unsigned)seq_num, domain_name));
+ DEBUG(3,("seq %u for %s has expired\n", (unsigned)seq_num,
+ domain_name));
return True;
}
return False;
}
-static void set_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
+static void set_cache_sequence_number(char *domain_name, char *cache_type,
+ char *subkey)
{
fstring keystr;
- slprintf(keystr,sizeof(keystr)-1,"CACHESEQ %s/%s/%s",
+
+ snprintf(keystr, sizeof(keystr),"CACHESEQ %s/%s/%s",
domain_name, cache_type, subkey?subkey:"");
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+
tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain_name));
}
-static uint32 get_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
+static uint32 get_cache_sequence_number(char *domain_name, char *cache_type,
+ char *subkey)
{
fstring keystr;
uint32 seq_num;
- slprintf(keystr,sizeof(keystr)-1,"CACHESEQ %s/%s/%s",
+
+ snprintf(keystr, sizeof(keystr), "CACHESEQ %s/%s/%s",
domain_name, cache_type, subkey?subkey:"");
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
- DEBUG(4,("%s is %u\n", keystr, (unsigned)seq_num));
+
+ DEBUG(3,("%s is %u\n", keystr, (unsigned)seq_num));
+
return seq_num;
}
/* Fill the user or group cache with supplied data */
-static void fill_cache(char *domain_name, char *cache_type,
- struct acct_info *sam_entries,
- int num_sam_entries)
+
+static void store_cache(char *domain_name, char *cache_type,
+ void *sam_entries, int buflen)
{
fstring keystr;
if (lp_winbind_cache_time() == 0) return;
/* Error check */
- if (!sam_entries || (num_sam_entries == 0)) return;
-
- DEBUG(4, ("filling %s cache for domain %s with %d entries\n",
- cache_type, domain_name, num_sam_entries));
+ if (!sam_entries || buflen == 0) return;
/* Store data as a mega-huge chunk in the tdb */
- slprintf(keystr, sizeof(keystr)-1, "%s CACHE DATA/%s", cache_type,
+ snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
domain_name);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
- tdb_store_by_string(cache_tdb, keystr,
- sam_entries, sizeof(struct acct_info) * num_sam_entries);
+
+ tdb_store_by_string(cache_tdb, keystr, sam_entries, buflen);
/* Stamp cache with current seq number */
set_cache_sequence_number(domain_name, cache_type, NULL);
@@ -137,97 +138,124 @@ static void fill_cache(char *domain_name, char *cache_type,
/* Fill the user cache with supplied data */
-void winbindd_fill_user_cache(char *domain_name,
- struct acct_info *sam_entries,
- int num_sam_entries)
+void winbindd_store_user_cache(char *domain,
+ struct getpwent_user *sam_entries,
+ int num_sam_entries)
{
- fill_cache(domain_name, CACHE_TYPE_USER, sam_entries, num_sam_entries);
+ DEBUG(3, ("storing user cache %s/%d entries\n", domain,
+ num_sam_entries));
+
+ store_cache(domain, CACHE_TYPE_USER, sam_entries,
+ num_sam_entries * sizeof(struct getpwent_user));
}
/* Fill the group cache with supplied data */
-void winbindd_fill_group_cache(char *domain_name,
- struct acct_info *sam_entries,
- int num_sam_entries)
+void winbindd_store_group_cache(char *domain,
+ struct acct_info *sam_entries,
+ int num_sam_entries)
{
- fill_cache(domain_name, CACHE_TYPE_GROUP, sam_entries, num_sam_entries);
+ DEBUG(0, ("storing group cache %s/%d entries\n", domain,
+ num_sam_entries));
+
+ store_cache(domain, CACHE_TYPE_GROUP, sam_entries,
+ num_sam_entries * sizeof(struct acct_info));
}
-static void fill_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
+static void store_cache_entry(char *domain, char *cache_type, char *name,
+ void *buf, int len)
{
fstring keystr;
/* Create key for store */
- slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s", cache_type, domain, name);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
-
- DEBUG(4, ("filling cache entry %s\n", keystr));
+ snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
/* Store it */
tdb_store_by_string(cache_tdb, keystr, buf, len);
}
/* Fill a user info cache entry */
-void winbindd_fill_user_cache_entry(char *domain, char *user_name,
- struct winbindd_pw *pw)
+
+void winbindd_store_user_cache_entry(char *domain, char *user_name,
+ struct winbindd_pw *pw)
{
if (lp_winbind_cache_time() == 0) return;
- fill_cache_entry(domain, CACHE_TYPE_USER, user_name, pw, sizeof(struct winbindd_pw));
+ store_cache_entry(domain, CACHE_TYPE_USER, user_name, pw,
+ sizeof(struct winbindd_pw));
+
set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
}
/* Fill a user uid cache entry */
-void winbindd_fill_uid_cache_entry(char *domain, uid_t uid,
+
+void winbindd_store_uid_cache_entry(char *domain, uid_t uid,
struct winbindd_pw *pw)
{
fstring uidstr;
if (lp_winbind_cache_time() == 0) return;
- slprintf(uidstr, sizeof(uidstr)-1, "#%u", (unsigned)uid);
- fill_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
+ snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
+
+ DEBUG(3, ("storing uid cache entry %s/%s\n", domain, uidstr));
+
+ store_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
+ sizeof(struct winbindd_pw));
+
set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
}
/* Fill a group info cache entry */
-void winbindd_fill_group_cache_entry(char *domain, char *group_name,
- struct winbindd_gr *gr, void *extra_data,
- int extra_data_len)
+void winbindd_store_group_cache_entry(char *domain, char *group_name,
+ struct winbindd_gr *gr, void *extra_data,
+ int extra_data_len)
{
fstring keystr;
if (lp_winbind_cache_time() == 0) return;
+ DEBUG(3, ("storing group cache entry %s/%s\n", domain, group_name));
+
/* Fill group data */
- fill_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr, sizeof(struct winbindd_gr));
+
+ store_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr,
+ sizeof(struct winbindd_gr));
/* Fill extra data */
- slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, group_name);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+
+ snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
+ domain, group_name);
tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
}
/* Fill a group info cache entry */
-void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
- struct winbindd_gr *gr, void *extra_data,
- int extra_data_len)
+
+void winbindd_store_gid_cache_entry(char *domain, gid_t gid,
+ struct winbindd_gr *gr, void *extra_data,
+ int extra_data_len)
{
fstring keystr;
fstring gidstr;
- slprintf(gidstr, sizeof(gidstr)-1, "#%u", (unsigned)gid);
+ snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
if (lp_winbind_cache_time() == 0) return;
+ DEBUG(3, ("storing gid cache entry %s/%s\n", domain, gidstr));
+
/* Fill group data */
- fill_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr, sizeof(struct winbindd_gr));
+
+ store_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr,
+ sizeof(struct winbindd_gr));
/* Fill extra data */
- slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, gidstr);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+
+ snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
+ domain, gidstr);
+
tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
@@ -235,7 +263,7 @@ void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
/* Fetch some cached user or group data */
static BOOL fetch_cache(char *domain_name, char *cache_type,
- struct acct_info **sam_entries, int *num_sam_entries)
+ void **sam_entries, int *buflen)
{
TDB_DATA data;
fstring keystr;
@@ -243,20 +271,21 @@ static BOOL fetch_cache(char *domain_name, char *cache_type,
if (lp_winbind_cache_time() == 0) return False;
/* Parameter check */
- if (!sam_entries || !num_sam_entries) {
+ if (!sam_entries || !buflen) {
return False;
}
/* Check cache data is current */
if (cache_domain_expired(domain_name,
- get_cache_sequence_number(domain_name, cache_type, NULL))) {
+ get_cache_sequence_number(domain_name,
+ cache_type,
+ NULL))) {
return False;
}
/* Create key */
- slprintf(keystr, sizeof(keystr)-1, "%s CACHE DATA/%s", cache_type,
+ snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
domain_name);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
/* Fetch cache information */
data = tdb_fetch_by_string(cache_tdb, keystr);
@@ -268,10 +297,7 @@ static BOOL fetch_cache(char *domain_name, char *cache_type,
be freed by the end{pw,gr}ent() function. */
*sam_entries = (struct acct_info *)data.dptr;
- *num_sam_entries = data.dsize / sizeof(struct acct_info);
-
- DEBUG(4, ("fetched %d cached %s entries for domain %s\n",
- *num_sam_entries, cache_type, domain_name));
+ *buflen = data.dsize;
return True;
}
@@ -279,40 +305,58 @@ static BOOL fetch_cache(char *domain_name, char *cache_type,
/* Return cached entries for a domain. Return false if there are no cached
entries, or the cached information has expired for the domain. */
-BOOL winbindd_fetch_user_cache(char *domain_name,
- struct acct_info **sam_entries,
+BOOL winbindd_fetch_user_cache(char *domain_name,
+ struct getpwent_user **sam_entries,
int *num_entries)
{
- return fetch_cache(domain_name, CACHE_TYPE_USER, sam_entries,
- num_entries);
+ BOOL result;
+ int buflen;
+
+ result = fetch_cache(domain_name, CACHE_TYPE_USER,
+ (void **)sam_entries, &buflen);
+
+ *num_entries = buflen / sizeof(struct getpwent_user);
+
+ DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
+ domain_name));
+
+ return result;
}
/* Return cached entries for a domain. Return false if there are no cached
entries, or the cached information has expired for the domain. */
-BOOL winbindd_fetch_group_cache(char *domain_name,
- struct acct_info **sam_entries,
+BOOL winbindd_fetch_group_cache(char *domain_name,
+ struct acct_info **sam_entries,
int *num_entries)
{
- return fetch_cache(domain_name, CACHE_TYPE_GROUP, sam_entries,
- num_entries);
+ BOOL result;
+ int buflen;
+
+ result = fetch_cache(domain_name, CACHE_TYPE_GROUP,
+ (void **)sam_entries, &buflen);
+
+ *num_entries = buflen / sizeof(struct acct_info);
+
+ DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
+ domain_name));
+
+ return result;
}
-static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
+static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name,
+ void *buf, int len)
{
TDB_DATA data;
fstring keystr;
/* Create key for lookup */
- slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s", cache_type, domain, name);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+ snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
/* Look up cache entry */
data = tdb_fetch_by_string(cache_tdb, keystr);
if (!data.dptr) return False;
- DEBUG(4, ("returning cached entry for %s\\%s\n", domain, name));
-
/* Copy found entry into buffer */
memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
free(data.dptr);
@@ -327,10 +371,12 @@ BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
if (lp_winbind_cache_time() == 0) return False;
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, user);
+ seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
+ user);
if (cache_domain_expired(domain_name, seq_num)) return False;
- return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw, sizeof(struct winbindd_pw));
+ return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw,
+ sizeof(struct winbindd_pw));
}
/* Fetch an individual uid cache entry */
@@ -342,11 +388,13 @@ BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
if (lp_winbind_cache_time() == 0) return False;
- slprintf(uidstr, sizeof(uidstr)-1, "#%u", (unsigned)uid);
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, uidstr);
+ snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
+ seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
+ uidstr);
if (cache_domain_expired(domain_name, seq_num)) return False;
- return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
+ return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw,
+ sizeof(struct winbindd_pw));
}
/* Fetch an individual group cache entry. This function differs from the
@@ -362,15 +410,21 @@ BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
if (lp_winbind_cache_time() == 0) return False;
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, group);
+ seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
+ group);
+
if (cache_domain_expired(domain_name, seq_num)) return False;
/* Fetch group data */
- if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr, sizeof(struct winbindd_gr))) return False;
+ if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr,
+ sizeof(struct winbindd_gr))) {
+ return False;
+ }
/* Fetch extra data */
- slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, group);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+ snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
+ domain_name, group);
+
data = tdb_fetch_by_string(cache_tdb, keystr);
if (!data.dptr) return False;
@@ -395,20 +449,24 @@ BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
fstring gidstr;
uint32 seq_num;
- slprintf(gidstr, sizeof(gidstr)-1, "#%u", (unsigned)gid);
+ snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
if (lp_winbind_cache_time() == 0) return False;
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, gidstr);
+ seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
+ gidstr);
+
if (cache_domain_expired(domain_name, seq_num)) return False;
/* Fetch group data */
if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP,
- gidstr, gr, sizeof(struct winbindd_gr))) return False;
+ gidstr, gr, sizeof(struct winbindd_gr))) {
+ return False;
+ }
/* Fetch extra data */
- slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, gidstr);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+ snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
+ domain_name, gidstr);
data = tdb_fetch_by_string(cache_tdb, keystr);
if (!data.dptr) return False;
@@ -425,3 +483,8 @@ void winbindd_flush_cache(void)
tdb_close(cache_tdb);
winbindd_cache_init();
}
+
+/* Print cache status information */
+void winbindd_cache_dump_status(void)
+{
+}
diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c
index 77825cd579..67cf10a1f5 100644
--- a/source3/nsswitch/winbindd_group.c
+++ b/source3/nsswitch/winbindd_group.c
@@ -25,741 +25,918 @@
/* Fill a grent structure from various other information */
-static void winbindd_fill_grent(struct winbindd_gr *gr, char *gr_name,
- gid_t unix_gid)
+static BOOL fill_grent(struct winbindd_gr *gr, char *gr_name,
+ gid_t unix_gid)
{
- /* Fill in uid/gid */
+ /* Fill in uid/gid */
- gr->gr_gid = unix_gid;
-
- /* Group name and password */
+ gr->gr_gid = unix_gid;
+
+ /* Group name and password */
+
+ safe_strcpy(gr->gr_name, gr_name, sizeof(gr->gr_name) - 1);
+ safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
- safe_strcpy(gr->gr_name, gr_name, sizeof(gr->gr_name) - 1);
- safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
+ return True;
}
-/* Fill in group membership */
-
-struct grent_mem_group {
- uint32 rid;
- enum SID_NAME_USE name_type;
- fstring domain_name;
- struct winbindd_domain *domain;
- struct grent_mem_group *prev, *next;
-};
+/* Fill in the group membership field of a NT group given by group_rid */
-struct grent_mem_list {
- fstring name;
- struct grent_mem_list *prev, *next;
-};
-
-/* Name comparison function for qsort() */
-
-static int name_comp(struct grent_mem_list *n1, struct grent_mem_list *n2)
+static BOOL fill_grent_mem(struct winbindd_domain *domain,
+ uint32 group_rid,
+ enum SID_NAME_USE group_name_type,
+ int *num_gr_mem, char **gr_mem, int *gr_mem_len)
{
- /* Silly cases */
-
- if (!n1 && !n2) return 0;
- if (!n1) return -1;
- if (!n2) return 1;
-
- return strcmp(n1->name, n2->name);
+ uint32 *rid_mem = NULL, num_names = 0;
+ enum SID_NAME_USE *name_types = NULL;
+ int buf_len, buf_ndx, i;
+ char **names = NULL, *buf;
+ BOOL result = False;
+
+ if (!num_gr_mem || !gr_mem || !gr_mem_len) return False;
+
+ /* Initialise group membership information */
+
+ DEBUG(10, ("fill_grent_mem(): group %s rid 0x%x\n",
+ domain ? domain->name : "NULL", group_rid));
+
+ *num_gr_mem = 0;
+
+ if (group_name_type != SID_NAME_DOM_GRP) {
+ DEBUG(1, ("fill_grent_mem(): rid %d in domain %s isn't a "
+ "domain group\n", group_rid, domain->name));
+ return False;
+ }
+
+ /* Lookup group members */
+
+ if (!winbindd_lookup_groupmem(domain, group_rid, &num_names,
+ &rid_mem, &names, &name_types)) {
+
+ DEBUG(1, ("fill_grent_mem(): could not lookup membership "
+ "for group rid %d in domain %s\n",
+ group_rid, domain->name));
+
+ return False;
+ }
+
+ DEBUG(10, ("fill_grent_mem(): looked up %d names\n", num_names));
+
+ if (DEBUGLEVEL >= 10) {
+ for (i = 0; i < num_names; i++) {
+ DEBUG(10, ("\t%20s %x %d\n", names[i], rid_mem[i],
+ name_types[i]));
+ }
+ }
+
+ /* Add members to list */
+
+ buf = NULL;
+ buf_len = buf_ndx = 0;
+
+ again:
+
+ for (i = 0; i < num_names; i++) {
+ char *the_name;
+ fstring name;
+ int len;
+
+ the_name = names[i];
+
+ DEBUG(10, ("fill_grent_mem(): processing name %s\n", the_name));
+
+ /* Only add domain users */
+
+ if (name_types[i] != SID_NAME_USER) {
+ DEBUG(3, ("fill_grent_mem(): name %s isn't a domain "
+ "user\n", the_name));
+ continue;
+ }
+
+ /* Don't bother with machine accounts */
+
+ if (the_name[strlen(the_name) - 1] == '$') {
+ DEBUG(10, ("fill_grent_mem(): %s is machine account\n",
+ the_name));
+ continue;
+ }
+
+ /* Append domain name */
+
+ snprintf(name, sizeof(name), "%s%s%s", domain->name,
+ lp_winbind_separator(), the_name);
+
+ len = strlen(name);
+
+ /* Add to list or calculate buffer length */
+
+ if (!buf) {
+ buf_len += len + 1; /* List is comma separated */
+ (*num_gr_mem)++;
+ DEBUG(10, ("fill_grent_mem(): buf_len + %d = %d\n", len + 1,
+ buf_len));
+ } else {
+ DEBUG(10, ("fill_grent_mem(): appending %s at index %d\n",
+ name, len));
+ safe_strcpy(&buf[buf_ndx], name, len);
+ buf_ndx += len;
+ buf[buf_ndx] = ',';
+ buf_ndx++;
+ }
+ }
+
+ /* Allocate buffer */
+
+ if (!buf) {
+ if (!(buf = malloc(buf_len))) {
+ DEBUG(1, ("fill_grent_mem(): out of memory\n"));
+ result = False;
+ goto cleanup;
+ }
+ memset(buf, 0, buf_len);
+ goto again;
+ }
+
+ if (buf && buf_ndx > 0) {
+ buf[buf_ndx - 1] = '\0';
+ }
+
+ *gr_mem = buf;
+ *gr_mem_len = buf_len;
+
+ DEBUG(10, ("fill_grent_mem(): num_mem = %d, len = %d, mem = %s\n", *num_gr_mem,
+ buf_len, buf));
+
+ result = True;
+
+ cleanup:
+
+ /* Free memory allocated in winbindd_lookup_groupmem() */
+
+ safe_free(name_types);
+ safe_free(rid_mem);
+
+ free_char_array(num_names, names);
+
+ DEBUG(10, ("fill_grent_mem(): returning %d\n", result));
+
+ return result;
}
-static struct grent_mem_list *sort_groupmem_list(struct grent_mem_list *list,
- int num_gr_mem)
-{
- struct grent_mem_list *groupmem_array, *temp;
- int i;
-
- /* Allocate and zero an array to hold sorted entries */
-
- if ((groupmem_array = malloc(num_gr_mem *
- sizeof(struct grent_mem_list))) == NULL) {
- return NULL;
- }
+/* Return a group structure from a group name */
- memset((char *)groupmem_array, 0, num_gr_mem *
- sizeof(struct grent_mem_list));
+enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
+ *state)
+{
+ DOM_SID group_sid;
+ struct winbindd_domain *domain;
+ enum SID_NAME_USE name_type;
+ uint32 group_rid;
+ fstring name_domain, name_group, name;
+ char *tmp, *gr_mem;
+ gid_t gid;
+ int extra_data_len, gr_mem_len;
+
+ DEBUG(3, ("[%5d]: getgrnam %s\n", state->pid,
+ state->request.data.groupname));
+
+ /* Parse domain and groupname */
+
+ memset(name_group, 0, sizeof(fstring));
+
+ tmp = state->request.data.groupname;
+ parse_domain_user(tmp, name_domain, name_group);
+
+ /* Reject names that don't have a domain - i.e name_domain contains
+ the entire name. */
+
+ if (strequal(name_group, "")) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Get info for the domain */
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(0, ("getgrname_from_group(): could not get domain "
+ "sid for domain %s\n", name_domain));
+ return WINBINDD_ERROR;
+ }
+
+ if (!domain_handles_open(domain)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Check for cached group entry */
+
+ if (winbindd_fetch_group_cache_entry(name_domain, name_group,
+ &state->response.data.gr,
+ &state->response.extra_data,
+ &extra_data_len)) {
+ state->response.length += extra_data_len;
+ return WINBINDD_OK;
+ }
+
+ snprintf(name, sizeof(name), "%s\\%s", name_domain, name_group);
+
+ /* Get rid and name type from name */
+
+ if (!winbindd_lookup_sid_by_name(name, &group_sid, &name_type)) {
+ DEBUG(1, ("group %s in domain %s does not exist\n",
+ name_group, name_domain));
+ return WINBINDD_ERROR;
+ }
- /* Copy list to array */
+ if ((name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_DOM_GRP)) {
+ DEBUG(1, ("from_group: name '%s' is not a local or domain "
+ "group: %d\n", name_group, name_type));
+ return WINBINDD_ERROR;
+ }
- for(temp = list, i = 0; temp && i < num_gr_mem; temp = temp->next, i++) {
- fstrcpy(groupmem_array[i].name, temp->name);
- }
+ /* Fill in group structure */
- /* Sort array */
+ sid_split_rid(&group_sid, &group_rid);
- qsort(groupmem_array, num_gr_mem, sizeof(struct grent_mem_list),
- name_comp);
+ if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
+ DEBUG(1, ("error sursing unix gid for sid\n"));
+ return WINBINDD_ERROR;
+ }
- /* Fix up resulting array to a linked list and return it */
+ if (!fill_grent(&state->response.data.gr,
+ state->request.data.groupname, gid) ||
+ !fill_grent_mem(domain, group_rid, name_type,
+ &state->response.data.gr.num_gr_mem,
+ &gr_mem, &gr_mem_len)) {
+ return WINBINDD_ERROR;
+ }
- for(i = 0; i < num_gr_mem; i++) {
+ /* Group membership lives at start of extra data */
- /* Fix up previous link */
+ state->response.data.gr.gr_mem_ofs = 0;
- if (i != 0) {
- groupmem_array[i].prev = &groupmem_array[i - 1];
- }
+ state->response.length += gr_mem_len;
+ state->response.extra_data = gr_mem;
- /* Fix up next link */
+ /* Update cached group info */
- if (i != (num_gr_mem - 1)) {
- groupmem_array[i].next = &groupmem_array[i + 1];
- }
- }
+ winbindd_store_group_cache_entry(name_domain, name_group,
+ &state->response.data.gr,
+ state->response.extra_data,
+ gr_mem_len);
- return groupmem_array;
+ return WINBINDD_OK;
}
-static BOOL winbindd_fill_grent_mem(struct winbindd_domain *domain,
- uint32 group_rid,
- enum SID_NAME_USE group_name_type,
- struct winbindd_response *response)
-{
- struct grent_mem_group *done_groups = NULL, *todo_groups = NULL;
- struct grent_mem_group *temp_group;
- struct grent_mem_list *groupmem_list = NULL;
- struct winbindd_gr *gr;
-
- if (response) {
- gr = &response->data.gr;
- } else {
- return False;
- }
-
- /* Initialise group membership information */
-
- gr->num_gr_mem = 0;
-
- /* Add first group to todo_groups list */
-
- if ((temp_group =
- (struct grent_mem_group *)malloc(sizeof(*temp_group))) == NULL) {
- return False;
- }
-
- ZERO_STRUCTP(temp_group);
-
- temp_group->rid = group_rid;
- temp_group->name_type = group_name_type;
- temp_group->domain = domain;
- fstrcpy(temp_group->domain_name, domain->name);
-
- DLIST_ADD(todo_groups, temp_group);
-
- /* Iterate over all groups to find members of */
-
- while(todo_groups != NULL) {
- struct grent_mem_group *current_group = todo_groups;
- uint32 num_names = 0, *rid_mem = NULL;
- enum SID_NAME_USE *name_types = NULL;
-
- DOM_SID **sids = NULL;
- char **names = NULL;
- BOOL done_group;
- int i;
-
- /* Check we haven't looked up this group before */
+/* Return a group structure from a gid number */
- done_group = 0;
+enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
+ *state)
+{
+ struct winbindd_domain *domain;
+ DOM_SID group_sid;
+ enum SID_NAME_USE name_type;
+ fstring group_name;
+ uint32 group_rid;
+ int extra_data_len, gr_mem_len;
+ char *gr_mem;
- for (temp_group = done_groups; temp_group != NULL;
- temp_group = temp_group->next) {
+ /* Bug out if the gid isn't in the winbind range */
- if ((temp_group->rid == current_group->rid) &&
- (strcmp(temp_group->domain_name,
- current_group->domain_name) == 0)) {
-
- done_group = 1;
- }
- }
+ if ((state->request.data.gid < server_state.gid_low) ||
+ (state->request.data.gid > server_state.gid_high)) {
+ return WINBINDD_ERROR;
+ }
- if (done_group) goto cleanup;
+ DEBUG(3, ("[%5d]: getgrgid %d\n", state->pid,
+ state->request.data.gid));
- /* Lookup group membership for the current group */
+ /* Get rid from gid */
- if (current_group->name_type == SID_NAME_DOM_GRP) {
+ 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;
+ }
- if (!winbindd_lookup_groupmem(current_group->domain,
- current_group->rid, &num_names,
- &rid_mem, &names, &name_types)) {
+ if (!domain_handles_open(domain)) {
+ return WINBINDD_ERROR;
+ }
- DEBUG(1, ("fill_grent_mem(): could not lookup membership "
- "for group rid %d in domain %s\n",
- current_group->rid,
- current_group->domain->name));
+ /* Try a cached entry */
- /* Exit if we cannot lookup the membership for the group
- this function was called to look at */
+ if (winbindd_fetch_gid_cache_entry(domain->name,
+ state->request.data.gid,
+ &state->response.data.gr,
+ &state->response.extra_data,
+ &extra_data_len)) {
+ state->response.length += extra_data_len;
+ return WINBINDD_OK;
+ }
- if (current_group->rid == group_rid) {
- return False;
- } else {
- goto cleanup;
- }
- }
- }
+ /* Get sid from gid */
- if (current_group->name_type == SID_NAME_ALIAS) {
+ sid_copy(&group_sid, &domain->sid);
+ sid_append_rid(&group_sid, group_rid);
- if (!winbindd_lookup_aliasmem(current_group->domain,
- current_group->rid, &num_names,
- &sids, &names, &name_types)) {
+ if (!winbindd_lookup_name_by_sid(&group_sid, group_name, &name_type)) {
+ DEBUG(1, ("Could not lookup sid\n"));
+ return WINBINDD_ERROR;
+ }
- DEBUG(1, ("fill_grent_mem(): group rid %d not a local group\n",
- group_rid));
+ if (strcmp(lp_winbind_separator(),"\\")) {
+ string_sub(group_name, "\\", lp_winbind_separator(),
+ sizeof(fstring));
+ }
- /* Exit if we cannot lookup the membership for the group
- this function was called to look at */
+ if (!((name_type == SID_NAME_ALIAS) ||
+ (name_type == SID_NAME_DOM_GRP))) {
+ DEBUG(1, ("from_gid: name '%s' is not a local or domain "
+ "group: %d\n", group_name, name_type));
+ return WINBINDD_ERROR;
+ }
- if (current_group->rid == group_rid) {
- return False;
- } else {
- goto cleanup;
- }
- }
- }
+ /* Fill in group structure */
- /* Now for each member of the group, add it to the group list if it
- is a user, otherwise push it onto the todo_group list if it is a
- group or an alias. */
-
- for (i = 0; i < num_names; i++) {
- enum SID_NAME_USE name_type;
- fstring name_part1, name_part2;
- char *name_dom, *name_user, *the_name;
- struct winbindd_domain *name_domain;
-
- /* Lookup name */
+ if (!fill_grent(&state->response.data.gr, group_name,
+ state->request.data.gid) ||
+ !fill_grent_mem(domain, group_rid, name_type,
+ &state->response.data.gr.num_gr_mem,
+ &gr_mem, &gr_mem_len)) {
+ return WINBINDD_ERROR;
+ }
- ZERO_STRUCT(name_part1);
- ZERO_STRUCT(name_part2);
- the_name = names[i];
- parse_domain_user(the_name, name_part1, name_part2);
+ /* Group membership lives at start of extra data */
- if (strcmp(name_part1, "") != 0) {
- name_dom = name_part1;
- name_user = name_part2;
+ state->response.data.gr.gr_mem_ofs = 0;
- if ((name_domain = find_domain_from_name(name_dom)) == NULL) {
- DEBUG(0, ("unable to look up domain record for domain "
- "%s\n", name_dom));
- continue;
- }
+ state->response.length += gr_mem_len;
+ state->response.extra_data = gr_mem;
- } else {
- name_dom = current_group->domain->name;
- name_user = name_part2;
- name_domain = current_group->domain;
- }
+ /* Update cached group info */
- if (winbindd_lookup_sid_by_name(name_domain, name_user, NULL,
- &name_type) == WINBINDD_OK) {
+ winbindd_store_gid_cache_entry(domain->name, state->request.data.gid,
+ &state->response.data.gr,
+ state->response.extra_data,
+ gr_mem_len);
- /* Check name type */
+ return WINBINDD_OK;
+}
- if (name_type == SID_NAME_USER) {
- struct grent_mem_list *entry;
+/*
+ * set/get/endgrent functions
+ */
- /* Add to group membership list */
-
- if ((entry = (struct grent_mem_list *)
- malloc(sizeof(*entry))) != NULL) {
+/* "Rewind" file pointer for group database enumeration */
- /* Create name */
- slprintf(entry->name, sizeof(entry->name)-1,
- "%s%s%s", name_dom, lp_winbind_separator(), name_user);
-
- /* Add to list */
+enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *tmp;
+
+ DEBUG(3, ("[%5d]: setgrent\n", state->pid));
+
+ if (state == NULL) return WINBINDD_ERROR;
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_groups()) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Free old static data if it exists */
+
+ if (state->getgrent_state != NULL) {
+ free_getent_state(state->getgrent_state);
+ state->getgrent_state = NULL;
+ }
+
+ /* Create sam pipes for each domain we know about */
+
+ for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ struct getent_state *domain_state;
+
+ /* Skip domains other than WINBINDD_DOMAIN environment
+ variable */
+
+ if ((strcmp(state->request.domain, "") != 0) &&
+ !check_domain_env(state->request.domain, tmp->name)) {
+ continue;
+ }
+
+ /* Create a state record for this domain */
+
+ if ((domain_state = (struct getent_state *)
+ malloc(sizeof(struct getent_state))) == NULL) {
+
+ return WINBINDD_ERROR;
+ }
+
+ ZERO_STRUCTP(domain_state);
+
+ /* Add to list of open domains */
+
+ domain_state->domain = tmp;
+ DLIST_ADD(state->getgrent_state, domain_state);
+ }
+
+ return WINBINDD_OK;
+}
- DLIST_ADD(groupmem_list, entry);
- gr->num_gr_mem++;
- }
+/* Close file pointer to ntdom group database */
- } else {
- struct grent_mem_group *todo_group;
- DOM_SID todo_sid;
- uint32 todo_rid;
+enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5d]: endgrent\n", state->pid));
- /* Add group to todo list */
+ if (state == NULL) return WINBINDD_ERROR;
- if (winbindd_lookup_sid_by_name(name_domain, names[i],
- &todo_sid, &name_type)
- == WINBINDD_OK) {
+ free_getent_state(state->getgrent_state);
+ state->getgrent_state = NULL;
+
+ return WINBINDD_OK;
+}
- /* Fill in group entry */
+/* Get the list of domain groups and domain aliases for a domain. We fill in
+ the sam_entries and num_sam_entries fields with domain group information.
+ The dispinfo_ndx field is incremented to the index of the next group to
+ fetch. Return True if some groups were returned, False otherwise. */
- sid_split_rid(&todo_sid, &todo_rid);
+#define MAX_FETCH_SAM_ENTRIES 100
- if ((todo_group = (struct grent_mem_group *)
- malloc(sizeof(*todo_group))) != NULL) {
-
- ZERO_STRUCTP(todo_group);
+static BOOL get_sam_group_entries(struct getent_state *ent)
+{
+ uint32 status, num_entries, start_ndx = 0;
+ struct acct_info *name_list = NULL;
+
+ if (ent->got_all_sam_entries) {
+ return False;
+ }
+
+#if 0
+ if (winbindd_fetch_group_cache(ent->domain->name,
+ &ent->sam_entries,
+ &ent->num_sam_entries)) {
+ return True;
+ }
+#endif
+
+ /* Fetch group entries */
+
+ if (!domain_handles_open(ent->domain)) {
+ return False;
+ }
+
+ /* Free any existing group info */
+
+ if (ent->sam_entries) {
+ free(ent->sam_entries);
+ ent->sam_entries = NULL;
+ ent->num_sam_entries = 0;
+ }
+
+ /* Enumerate domain groups */
+
+ do {
+ struct acct_info *sam_grp_entries = NULL;
+
+ num_entries = 0;
+
+ status =
+ samr_enum_dom_groups(&ent->domain->
+ sam_dom_handle,
+ &start_ndx,
+ 0x8000, /* buffer size? */
+ (struct acct_info **)
+ &sam_grp_entries,
+ &num_entries);
+
+ /* Copy entries into return buffer */
+
+ if (num_entries) {
+
+ name_list = Realloc(name_list,
+ sizeof(struct acct_info) *
+ (ent->num_sam_entries +
+ num_entries));
+
+ memcpy(&name_list[ent->num_sam_entries],
+ sam_grp_entries,
+ num_entries * sizeof(struct acct_info));
+
+ safe_free(sam_grp_entries);
+ }
+
+ ent->num_sam_entries += num_entries;
+
+ if (status != STATUS_MORE_ENTRIES) {
+ break;
+ }
+
+ } while (ent->num_sam_entries < MAX_FETCH_SAM_ENTRIES);
+
+#if 0
+ /* Fill cache with received entries */
+
+ winbindd_store_group_cache(ent->domain->name, ent->sam_entries,
+ ent->num_sam_entries);
+#endif
+
+ /* Fill in remaining fields */
+
+ ent->sam_entries = name_list;
+ ent->sam_entry_index = 0;
+ ent->got_all_sam_entries = (status != STATUS_MORE_ENTRIES);
+
+ return ent->num_sam_entries > 0;
+}
- todo_group->rid = todo_rid;
- todo_group->name_type = name_type;
- todo_group->domain = name_domain;
+/* Fetch next group entry from ntdom database */
- fstrcpy(todo_group->domain_name, name_dom);
+#define MAX_GETGRENT_GROUPS 500
- DLIST_ADD(todo_groups, todo_group);
- }
- }
- }
- }
- }
+enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
+{
+ struct getent_state *ent;
+ struct winbindd_gr *group_list = NULL;
+ int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
+ char *sep, *new_extra_data, *gr_mem_list = NULL;
- cleanup:
-
- /* Remove group from todo list and add to done_groups list */
+ DEBUG(3, ("[%5d]: getgrent\n", state->pid));
- DLIST_REMOVE(todo_groups, current_group);
- DLIST_ADD(done_groups, current_group);
+ if (state == NULL) return WINBINDD_ERROR;
- /* Free memory allocated in winbindd_lookup_{alias,group}mem() */
+ /* Check user has enabled this */
- safe_free(name_types);
- safe_free(rid_mem);
+ if (!lp_winbind_enum_groups()) {
+ return WINBINDD_ERROR;
+ }
- free_char_array(num_names, names);
- free_sid_array(num_names, sids);
- }
-
- /* Free done groups list */
+ num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
- temp_group = done_groups;
+ if ((state->response.extra_data =
+ malloc(num_groups * sizeof(struct winbindd_gr))) == NULL) {
+ return WINBINDD_ERROR;
+ }
- if (temp_group != NULL) {
- while (temp_group != NULL) {
- struct grent_mem_group *next;
+ state->response.data.num_entries = 0;
- DLIST_REMOVE(done_groups, temp_group);
- next = temp_group->next;
+ group_list = (struct winbindd_gr *)state->response.extra_data;
+ sep = lp_winbind_separator();
- free(temp_group);
- temp_group = next;
- }
- }
+ if (!(ent = state->getgrent_state)) {
+ return WINBINDD_ERROR;
+ }
- /* Remove duplicates from group member list. */
+ /* Start sending back groups */
- if (gr->num_gr_mem > 0) {
- struct grent_mem_list *sorted_groupmem_list, *temp;
- int extra_data_len = 0;
- fstring prev_name;
- char *head;
+ for (i = 0; i < num_groups; i++) {
+ struct acct_info *name_list = NULL;
+ fstring domain_group_name;
+ uint32 result;
+ gid_t group_gid;
+
+ /* Do we need to fetch another chunk of groups? */
- /* Sort list */
+ tryagain:
- sorted_groupmem_list = sort_groupmem_list(groupmem_list,
- gr->num_gr_mem);
- /* Remove duplicates by iteration */
+ DEBUG(10, ("getgrent(): entry_index = %d, num_entries = %d\n",
+ ent->sam_entry_index, ent->num_sam_entries));
- fstrcpy(prev_name, "");
+ if (ent->num_sam_entries == ent->sam_entry_index) {
- for(temp = sorted_groupmem_list; temp; temp = temp->next) {
- if (strequal(temp->name, prev_name)) {
+ while(ent && !get_sam_group_entries(ent)) {
+ struct getent_state *next_ent;
- /* Got a duplicate name - delete it. Don't panic as we're
- only adjusting the prev and next pointers so memory
- allocation is not messed up. */
+ DEBUG(10, ("getgrent(): freeing state info for "
+ "domain %s\n", ent->domain->name));
- DLIST_REMOVE(sorted_groupmem_list, temp);
- gr->num_gr_mem--;
+ /* Free state information for this domain */
- } else {
+ safe_free(ent->sam_entries);
+ ent->sam_entries = NULL;
- /* Got a unique name - count how long it is */
+ next_ent = ent->next;
+ DLIST_REMOVE(state->getgrent_state, ent);
+
+ free(ent);
+ ent = next_ent;
+ }
- extra_data_len += strlen(temp->name) + 1;
- }
- }
+ /* No more domains */
- extra_data_len++; /* Don't forget null a terminator */
+ if (!ent) break;
+ }
+
+ name_list = ent->sam_entries;
+
+ /* Lookup group info */
+
+ if (!winbindd_idmap_get_gid_from_rid(
+ ent->domain->name,
+ name_list[ent->sam_entry_index].rid,
+ &group_gid)) {
+
+ DEBUG(1, ("getgrent(): could not look up gid for group %s\n",
+ name_list[ent->sam_entry_index].acct_name));
- /* Convert sorted list into extra data field to send back to ntdom
- client. Add one to extra_data_len for null termination */
+ ent->sam_entry_index++;
+ goto tryagain;
+ }
- if ((response->extra_data = malloc(extra_data_len))) {
+ DEBUG(10, ("getgrent(): got gid %d for group %x\n", group_gid,
+ name_list[ent->sam_entry_index].rid));
+
+ /* Fill in group entry */
- /* Initialise extra data */
+ slprintf(domain_group_name, sizeof(domain_group_name) - 1,
+ "%s%s%s", ent->domain->name, lp_winbind_separator(),
+ name_list[ent->sam_entry_index].acct_name);
+
+ result = fill_grent(&group_list[group_list_ndx],
+ domain_group_name, group_gid);
- memset(response->extra_data, 0, extra_data_len);
+ /* Fill in group membership entry */
- head = response->extra_data;
+ if (result) {
+ int gr_mem_len;
+ char *gr_mem, *new_gr_mem_list;
- /* Fill in extra data */
+ /* Get group membership */
- for(temp = sorted_groupmem_list; temp; temp = temp->next) {
- int len = strlen(temp->name) + 1;
-
- safe_strcpy(head, temp->name, len);
- head[len - 1] = ',';
- head += len;
- }
-
- *head = '\0';
+ result = fill_grent_mem(
+ ent->domain,
+ name_list[ent->sam_entry_index].rid,
+ SID_NAME_DOM_GRP,
+ &group_list[group_list_ndx].num_gr_mem,
+ &gr_mem, &gr_mem_len);
- /* Update response length */
+ /* Append to group membership list */
- response->length = sizeof(struct winbindd_response) +
- extra_data_len;
- }
+ new_gr_mem_list = Realloc(
+ gr_mem_list,
+ gr_mem_list_len + gr_mem_len);
- /* Free memory for sorted_groupmem_list. It was allocated as an
- array in sort_groupmem_list() so can be freed in one go. */
+ if (!new_gr_mem_list) {
+ DEBUG(0, ("getgrent(): out of memory\n"));
+ free(gr_mem_list);
+ gr_mem_list_len = 0;
+ break;
+ }
- free(sorted_groupmem_list);
+ DEBUG(10, ("getgrent(): list_len = %d, mem_len = %d\n",
+ gr_mem_list_len, gr_mem_len));
- /* Free groupmem_list */
+ gr_mem_list = new_gr_mem_list;
- temp = groupmem_list;
+ memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
+ gr_mem_len);
- while (temp != NULL) {
- struct grent_mem_list *next;
-
- DLIST_REMOVE(groupmem_list, temp);
- next = temp->next;
-
- free(temp);
- temp = next;
- }
- }
+ safe_free(gr_mem);
- return True;
-}
+ group_list[group_list_ndx].gr_mem_ofs =
+ gr_mem_list_len;
-/* Return a group structure from a group name */
+ gr_mem_list_len += gr_mem_len;
+ }
-enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state)
-{
- DOM_SID group_sid;
- struct winbindd_domain *domain;
- enum SID_NAME_USE name_type;
- uint32 group_rid;
- fstring name_domain, name_group, name;
- char *tmp;
- gid_t gid;
- int extra_data_len;
+ ent->sam_entry_index++;
+
+ /* Add group to return list */
+
+ if (result) {
- /* Parse domain and groupname */
+ DEBUG(10, ("getgrent(): adding group num_entries = %d\n",
+ state->response.data.num_entries));
- memset(name_group, 0, sizeof(fstring));
+ group_list_ndx++;
+ state->response.data.num_entries++;
+
+ state->response.length +=
+ sizeof(struct winbindd_gr);
+
+ } else {
+ DEBUG(0, ("could not lookup domain group %s\n",
+ domain_group_name));
+ }
+ }
- tmp = state->request.data.groupname;
- parse_domain_user(tmp, name_domain, name_group);
+ /* Copy the list of group memberships to the end of the extra data */
- /* Reject names that don't have a domain - i.e name_domain contains the
- entire name. */
+ if (group_list_ndx == 0) {
+ goto done;
+ }
- if (strequal(name_group, "")) {
- return WINBINDD_ERROR;
- }
+ new_extra_data = Realloc(
+ state->response.extra_data,
+ group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
- /* Get info for the domain */
+ if (!new_extra_data) {
+ DEBUG(0, ("out of memory\n"));
+ group_list_ndx = 0;
+ safe_free(state->response.extra_data);
+ state->response.extra_data = NULL;
+ safe_free(gr_mem_list);
- if ((domain = find_domain_from_name(name_domain)) == NULL) {
- DEBUG(0, ("getgrname_from_group(): could not get domain sid for "
- "domain %s\n", name_domain));
- return WINBINDD_ERROR;
- }
+ return WINBINDD_ERROR;
+ }
- /* Check for cached user entry */
+ state->response.extra_data = new_extra_data;
- if (winbindd_fetch_group_cache_entry(name_domain, name_group,
- &state->response.data.gr,
- &state->response.extra_data,
- &extra_data_len)) {
- state->response.length += extra_data_len;
- return WINBINDD_OK;
- }
+ memcpy(&((char *)state->response.extra_data)
+ [group_list_ndx * sizeof(struct winbindd_gr)],
+ gr_mem_list, gr_mem_list_len);
- slprintf(name, sizeof(name)-1, "%s\\%s", name_domain, name_group);
+ safe_free(gr_mem_list);
- /* Get rid and name type from name */
-
- if (!winbindd_lookup_sid_by_name(domain, name, &group_sid,
- &name_type)) {
- DEBUG(1, ("group %s in domain %s does not exist\n", name_group,
- name_domain));
- return WINBINDD_ERROR;
- }
-
- if ((name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_DOM_GRP)) {
- DEBUG(1, ("from_group: name '%s' is not a local or domain group: %d\n",
- name_group, name_type));
- return WINBINDD_ERROR;
- }
-
- /* Fill in group structure */
-
- sid_split_rid(&group_sid, &group_rid);
-
- if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
- DEBUG(1, ("error sursing unix gid for sid\n"));
- return WINBINDD_ERROR;
- }
-
- winbindd_fill_grent(&state->response.data.gr,
- state->request.data.groupname, gid);
-
- if (!winbindd_fill_grent_mem(domain, group_rid, name_type,
- &state->response)) {
- return WINBINDD_ERROR;
- }
+ state->response.length += gr_mem_list_len;
- /* Update cached group info */
+ DEBUG(10, ("getgrent(): returning %d groups, length = %d\n",
+ group_list_ndx, gr_mem_list_len));
- winbindd_fill_group_cache_entry(name_domain, name_group,
- &state->response.data.gr,
- state->response.extra_data,
- state->response.length -
- sizeof(struct winbindd_response));
+ /* Out of domains */
- return WINBINDD_OK;
+ done:
+ return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
}
-/* Return a group structure from a gid number */
+/* List domain groups without mapping to unix ids */
-enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
- *state)
+enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
{
- struct winbindd_domain *domain;
- DOM_SID group_sid;
- enum SID_NAME_USE name_type;
- fstring group_name;
- uint32 group_rid;
- int extra_data_len;
-
- /* Get rid from gid */
- 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;
- }
-
- /* try a cached entry */
- if (winbindd_fetch_gid_cache_entry(domain->name, state->request.data.gid,
- &state->response.data.gr,
- &state->response.extra_data,
- &extra_data_len)) {
- state->response.length += extra_data_len;
- return WINBINDD_OK;
- }
-
- /* Get sid from gid */
-
- sid_copy(&group_sid, &domain->sid);
- sid_append_rid(&group_sid, group_rid);
-
- if (!winbindd_lookup_name_by_sid(domain, &group_sid, group_name,
- &name_type)) {
- DEBUG(1, ("Could not lookup sid\n"));
- return WINBINDD_ERROR;
- }
-
- if (strcmp(lp_winbind_separator(),"\\")) {
- string_sub(group_name, "\\", lp_winbind_separator(), sizeof(fstring));
- }
-
- if (!((name_type == SID_NAME_ALIAS) || (name_type == SID_NAME_DOM_GRP))) {
- DEBUG(1, ("from_gid: name '%s' is not a local or domain group: %d\n",
- group_name, name_type));
- return WINBINDD_ERROR;
- }
-
- /* Fill in group structure */
-
- winbindd_fill_grent(&state->response.data.gr, group_name,
- state->request.data.gid);
-
- if (!winbindd_fill_grent_mem(domain, group_rid, name_type,
- &state->response)) {
- return WINBINDD_ERROR;
- }
-
- /* Update cached group info */
- winbindd_fill_gid_cache_entry(domain->name, state->request.data.gid,
- &state->response.data.gr,
- state->response.extra_data,
- state->response.length -
- sizeof(struct winbindd_response));
-
- return WINBINDD_OK;
-}
+ uint32 total_entries = 0;
+ struct winbindd_domain *domain;
+ struct getent_state groups;
+ char *extra_data = NULL;
+ int extra_data_len = 0, i;
-/*
- * set/get/endgrent functions
- */
+ DEBUG(3, ("[%5d]: list groups\n", state->pid));
-/* "Rewind" file pointer for group database enumeration */
+ /* Enumerate over trusted domains */
-enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
-{
- struct winbindd_domain *tmp;
+ for (domain = domain_list; domain; domain = domain->next) {
- if (state == NULL) return WINBINDD_ERROR;
+ /* Skip domains other than WINBINDD_DOMAIN environment
+ variable */
- /* Free old static data if it exists */
+ if ((strcmp(state->request.domain, "") != 0) &&
+ !check_domain_env(state->request.domain, domain->name)) {
+ continue;
+ }
- if (state->getgrent_state != NULL) {
- free_getent_state(state->getgrent_state);
- state->getgrent_state = NULL;
- }
+ /* Get list of sam groups */
- /* Create sam pipes for each domain we know about */
+ ZERO_STRUCT(groups);
+ groups.domain = domain;
- for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
- struct getent_state *domain_state;
+ get_sam_group_entries(&groups);
- /* Skip domains other than WINBINDD_DOMAIN environment variable */
+ if (groups.num_sam_entries == 0) continue;
- if ((strcmp(state->request.domain, "") != 0) &&
- (strcmp(state->request.domain, tmp->name) != 0)) {
- continue;
- }
+ /* Allocate some memory for extra data. Note that we limit
+ account names to sizeof(fstring) = 128 characters. */
- /* Create a state record for this domain */
+ total_entries += groups.num_sam_entries;
+ extra_data = Realloc(extra_data,
+ sizeof(fstring) * total_entries);
- if ((domain_state = (struct getent_state *)
- malloc(sizeof(struct getent_state))) == NULL) {
+ if (!extra_data) {
+ return WINBINDD_ERROR;
+ }
- return WINBINDD_ERROR;
- }
+ /* Pack group list into extra data fields */
- ZERO_STRUCTP(domain_state);
+ for (i = 0; i < groups.num_sam_entries; i++) {
+ char *group_name = ((struct acct_info *)
+ groups.sam_entries)[i].acct_name;
+ fstring name;
- /* Add to list of open domains */
+ /* Convert unistring to ascii */
- domain_state->domain = tmp;
- DLIST_ADD(state->getgrent_state, domain_state);
- }
+ snprintf(name, sizeof(name), "%s%s%s",
+ domain->name, lp_winbind_separator(),
+ group_name);
- return WINBINDD_OK;
-}
+ /* Append to extra data */
+
+ memcpy(&extra_data[extra_data_len], name,
+ strlen(name));
+ extra_data_len += strlen(name);
-/* Close file pointer to ntdom group database */
+ extra_data[extra_data_len++] = ',';
+ }
+ }
-enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
-{
- if (state == NULL) return WINBINDD_ERROR;
+ /* Assign extra_data fields in response structure */
+
+ if (extra_data) {
+ extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data = extra_data;
+ state->response.length += extra_data_len;
+ }
- free_getent_state(state->getgrent_state);
- state->getgrent_state = NULL;
+ /* No domains may have responded but that's still OK so don't
+ return an error. */
- return WINBINDD_OK;
+ return WINBINDD_OK;
}
-/* Fetch next group entry from netdom database */
+/* Get user supplementary groups. This is much quicker than trying to
+ invert the groups database. */
-enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
+enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
{
- if (state == NULL) return WINBINDD_ERROR;
-
- /* Process the current head of the getent_state list */
-
- while(state->getgrent_state != NULL) {
- struct getent_state *ent = state->getgrent_state;
-
- /* Get list of entries if we haven't already got them */
-
- if (!ent->got_sam_entries) {
- uint32 status, start_ndx = 0, start_ndx2 = 0;
-
- if (!winbindd_fetch_group_cache(ent->domain->name,
- &ent->sam_entries,
- &ent->num_sam_entries)) {
-
- /* Fetch group entries */
-
- if (!domain_handles_open(ent->domain)) goto cleanup;
-
- /* Enumerate domain groups */
-
- do {
- status =
- samr_enum_dom_groups(&ent->domain->sam_dom_handle,
- &start_ndx, 0x100000,
- &ent->sam_entries,
- &ent->num_sam_entries);
- } while (status == STATUS_MORE_ENTRIES);
-
- /* Enumerate domain aliases */
-
- do {
- status =
- samr_enum_dom_aliases(&ent->domain->sam_dom_handle,
- &start_ndx2, 0x100000,
- &ent->sam_entries,
- &ent->num_sam_entries);
- } while (status == STATUS_MORE_ENTRIES);
-
- /* Fill cache with received entries */
-
- winbindd_fill_group_cache(ent->domain->name, ent->sam_entries,
- ent->num_sam_entries);
- }
-
- ent->got_sam_entries = True;
- }
-
- /* Send back a group */
-
- while (ent->sam_entry_index < ent->num_sam_entries) {
- enum winbindd_result result;
- fstring domain_group_name;
- char *group_name = (ent->sam_entries)
- [ent->sam_entry_index].acct_name;
-
- /* Prepend domain to name */
-
- slprintf(domain_group_name, sizeof(domain_group_name)-1,
- "%s%s%s", ent->domain->name, lp_winbind_separator(), group_name);
-
- /* Get group entry from group name */
-
- fstrcpy(state->request.data.groupname, domain_group_name);
- result = winbindd_getgrnam_from_group(state);
-
- ent->sam_entry_index++;
-
- if (result == WINBINDD_OK) {
- return result;
- }
-
- /* Try next group */
-
- DEBUG(1, ("could not getgrnam_from_group for group name %s\n",
- domain_group_name));
- }
-
- /* We've exhausted all users for this pipe - close it down and
- start on the next one. */
-
- cleanup:
-
- /* Free mallocated memory for sam entries. The data stored here
- may have been allocated from the cache. */
-
- if (ent->sam_entries != NULL) free(ent->sam_entries);
- ent->sam_entries = NULL;
-
- /* Free state information for this domain */
-
- {
- struct getent_state *old_ent;
-
- old_ent = state->getgrent_state;
- DLIST_REMOVE(state->getgrent_state, state->getgrent_state);
- free(old_ent);
- }
- }
-
- /* Out of pipes so we're done */
-
- return WINBINDD_ERROR;
+ fstring name_domain, name_user, name;
+ DOM_SID user_sid;
+ enum SID_NAME_USE name_type;
+ uint32 user_rid, num_groups, num_gids;
+ DOM_GID *user_groups = NULL;
+ struct winbindd_domain *domain;
+ enum winbindd_result result;
+ gid_t *gid_list;
+ int i;
+
+ DEBUG(3, ("[%5d]: getgroups %s\n", state->pid,
+ state->request.data.username));
+
+ if (state == NULL) return WINBINDD_ERROR;
+
+ /* Parse domain and username */
+
+ parse_domain_user(state->request.data.username, name_domain,
+ name_user);
+
+ /* Reject names that don't have a domain - i.e name_domain contains
+ the entire name. */
+
+ if (strequal(name_domain, "")) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Get info for the domain */
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(0, ("could not find domain entry for domain %s\n",
+ name_domain));
+ return WINBINDD_ERROR;
+ }
+
+ if (!domain_handles_open(domain)) {
+ return WINBINDD_ERROR;
+ }
+
+ slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user);
+
+ /* Get rid and name type from name. The following costs 1 packet */
+
+ if (!winbindd_lookup_sid_by_name(name, &user_sid, &name_type)) {
+ DEBUG(1, ("user '%s' does not exist\n", name_user));
+ return WINBINDD_ERROR;
+ }
+
+ if (name_type != SID_NAME_USER) {
+ DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
+ name_type));
+ return WINBINDD_ERROR;
+ }
+
+ sid_split_rid(&user_sid, &user_rid);
+
+ if (!winbindd_lookup_usergroups(domain, user_rid, &num_groups,
+ &user_groups)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Copy data back to client */
+
+ num_gids = 0;
+ gid_list = malloc(sizeof(gid_t) * num_groups);
+
+ if (state->response.extra_data) {
+ result = WINBINDD_ERROR;
+ goto done;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ if (!winbindd_idmap_get_gid_from_rid(
+ domain->name, user_groups[i].g_rid,
+ &gid_list[num_gids])) {
+
+ DEBUG(1, ("unable to convert group rid %d to gid\n",
+ user_groups[i].g_rid));
+ continue;
+ }
+
+ num_gids++;
+ }
+
+ state->response.data.num_entries = num_gids;
+ state->response.extra_data = gid_list;
+ state->response.length += num_gids * sizeof(gid_t);
+
+ result = WINBINDD_OK;
+
+ done:
+ safe_free(user_groups);
+
+ return result;
}
diff --git a/source3/nsswitch/winbindd_idmap.c b/source3/nsswitch/winbindd_idmap.c
index 11f7b8aae7..2bb942396b 100644
--- a/source3/nsswitch/winbindd_idmap.c
+++ b/source3/nsswitch/winbindd_idmap.c
@@ -73,12 +73,11 @@ static BOOL get_id_from_rid(char *domain_name, uint32 rid, int *id,
{
TDB_DATA data, key;
fstring keystr;
- BOOL result;
+ BOOL result = False;
/* Check if rid is present in database */
- slprintf(keystr, sizeof(keystr)-1, "%s/%d", domain_name, rid);
- dos_to_unix(keystr, True); /* Convert key to unix-codepage */
+ slprintf(keystr, sizeof(keystr), "%s/%d", domain_name, rid);
key.dptr = keystr;
key.dsize = strlen(keystr) + 1;
@@ -116,7 +115,7 @@ static BOOL get_id_from_rid(char *domain_name, uint32 rid, int *id,
/* Store new id */
- slprintf(keystr2, sizeof(keystr2)-1, "%s %d", isgroup ? "GID" :
+ slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" :
"UID", *id);
data.dptr = keystr2;
@@ -155,7 +154,7 @@ BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
fstring keystr;
BOOL result = False;
- slprintf(keystr, sizeof(keystr)-1, "%s %d", isgroup ? "GID" : "UID", id);
+ slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", id);
key.dptr = keystr;
key.dsize = strlen(keystr) + 1;
@@ -177,11 +176,17 @@ BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
if (domain) {
*domain = find_domain_from_name(domain_name);
+ if (*domain == NULL) {
+ DEBUG(1, ("unknown domain %s for rid %d\n",
+ domain_name, the_rid));
+ result = False;
+ goto done;
+ }
}
result = True;
}
-
+ done:
free(data.dptr);
}
@@ -211,8 +216,7 @@ BOOL winbindd_idmap_init(void)
/* Open tdb cache */
if (!(idmap_tdb = tdb_open(lock_path("winbindd_idmap.tdb"), 0,
- TDB_NOLOCK | TDB_NOMMAP,
- O_RDWR | O_CREAT, 0600))) {
+ TDB_NOLOCK, O_RDWR | O_CREAT, 0600))) {
DEBUG(0, ("Unable to open idmap database\n"));
return False;
}
@@ -235,3 +239,63 @@ BOOL winbindd_idmap_init(void)
return True;
}
+
+/* Dump status information to log file. Display different stuff based on
+ the debug level:
+
+ Debug Level Information Displayed
+ =================================================================
+ 0 Percentage of [ug]id range allocated
+ 0 High water marks (next allocated ids)
+*/
+
+#define DUMP_INFO 0
+
+void winbindd_idmap_dump_status(void)
+{
+ int user_hwm, group_hwm;
+
+ DEBUG(0, ("Status for winbindd idmap:\n"));
+
+ /* Get current high water marks */
+
+ if ((user_hwm = tdb_fetch_int(idmap_tdb, HWM_USER)) == -1) {
+ DEBUG(DUMP_INFO, ("\tCould not get userid high water mark!\n"));
+ }
+
+ if ((group_hwm = tdb_fetch_int(idmap_tdb, HWM_GROUP)) == -1) {
+ DEBUG(DUMP_INFO, ("\tCould not get groupid high water mark!\n"));
+ }
+
+ /* Display next ids to allocate */
+
+ if (user_hwm != -1) {
+ DEBUG(DUMP_INFO, ("\tNext userid to allocate is %d\n", user_hwm));
+ }
+
+ if (group_hwm != -1) {
+ DEBUG(DUMP_INFO, ("\tNext groupid to allocate is %d\n", group_hwm));
+ }
+
+ /* Display percentage of id range already allocated. */
+
+ if (user_hwm != -1) {
+ int num_users = user_hwm - server_state.uid_low;
+ int total_users = server_state.uid_high - server_state.uid_low;
+
+ DEBUG(DUMP_INFO, ("\tUser id range is %d%% full (%d of %d)\n",
+ num_users * 100 / total_users, num_users,
+ total_users));
+ }
+
+ if (group_hwm != -1) {
+ int num_groups = group_hwm - server_state.gid_low;
+ int total_groups = server_state.gid_high - server_state.gid_low;
+
+ DEBUG(DUMP_INFO, ("\tGroup id range is %d%% full (%d of %d)\n",
+ num_groups * 100 / total_groups, num_groups,
+ total_groups));
+ }
+
+ /* Display complete mapping of users and groups to rids */
+}
diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c
index c74afd8e29..57b2394799 100644
--- a/source3/nsswitch/winbindd_pam.c
+++ b/source3/nsswitch/winbindd_pam.c
@@ -23,6 +23,28 @@
#include "winbindd.h"
+/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
+ form DOMAIN/user into a domain and a user */
+
+static void parse_domain_user(char *domuser, fstring domain, fstring user)
+{
+ char *p;
+ char *sep = lp_winbind_separator();
+ if (!sep) sep = "\\";
+ p = strchr(domuser,*sep);
+ if (!p) p = strchr(domuser,'\\');
+ if (!p) {
+ fstrcpy(domain,"");
+ fstrcpy(user, domuser);
+ return;
+ }
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ strupper(domain);
+}
+
/* Return a password structure from a username. Specify whether cached data
can be returned. */
@@ -31,31 +53,37 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
NET_USER_INFO_3 info3;
uchar ntpw[16];
uchar lmpw[16];
- uint8 trust_passwd[16];
+ uchar trust_passwd[16];
uint32 status;
fstring server;
fstring name_domain, name_user;
extern pstring global_myname;
- DEBUG(1,("winbindd_pam_auth user=%s\n",
- state->request.data.auth.user));
+ DEBUG(3, ("[%5d]: pam auth %s\n", state->pid,
+ state->request.data.auth.user));
/* Parse domain and username */
- parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+ parse_domain_user(state->request.data.auth.user, name_domain,
+ name_user);
/* don't allow the null domain */
if (strcmp(name_domain,"") == 0) return WINBINDD_ERROR;
ZERO_STRUCT(info3);
- if (!secrets_fetch_trust_account_password(lp_workgroup(),
- trust_passwd, NULL)) {
- return WINBINDD_ERROR;
- }
+ if (!_get_trust_account_password(lp_workgroup(), trust_passwd, NULL)) {
+ DEBUG(1, ("could not get trust password for domain %s\n",
+ name_domain));
+ return WINBINDD_ERROR;
+ }
nt_lm_owf_gen(state->request.data.auth.pass, ntpw, lmpw);
- slprintf(server, sizeof(server)-1, "\\\\%s", server_state.controller);
+ slprintf(server, sizeof(server), "\\\\%s", server_state.controller);
+
+#if 0
+
+ /* XXX */
status = domain_client_validate_backend(server,
name_user, name_domain,
@@ -64,9 +92,51 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
NULL,
lmpw, sizeof(lmpw),
ntpw, sizeof(ntpw), &info3);
+#else
+ status = NT_STATUS_UNSUCCESSFUL;
+#endif
+
if (status != NT_STATUS_NOPROBLEMO) return WINBINDD_ERROR;
return WINBINDD_OK;
}
+/* Change a user password */
+
+enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
+{
+ char *oldpass, *newpass;
+ fstring domain, user;
+ uchar nt_oldhash[16];
+ uchar lm_oldhash[16];
+
+ DEBUG(3, ("[%5d]: pam chauthtok %s\n", state->pid,
+ state->request.data.chauthtok.user));
+
+ /* Setup crap */
+
+ if (state == NULL) return WINBINDD_ERROR;
+
+ parse_domain_user(state->request.data.chauthtok.user, domain, user);
+
+ oldpass = state->request.data.chauthtok.oldpass;
+ newpass = state->request.data.chauthtok.newpass;
+
+ nt_lm_owf_gen(oldpass, nt_oldhash, lm_oldhash);
+
+ /* Change password */
+
+#if 0
+
+ /* XXX */
+
+ if (!msrpc_sam_ntchange_pwd(server_state.controller, domain, user,
+ lm_oldhash, nt_oldhash, newpass)) {
+ DEBUG(0, ("password change failed for user %s/%s\n", domain, user));
+ return WINBINDD_ERROR;
+ }
+#endif
+
+ return WINBINDD_OK;
+}
diff --git a/source3/nsswitch/winbindd_proto.h b/source3/nsswitch/winbindd_proto.h
index 774478fea5..6e03ec842f 100644
--- a/source3/nsswitch/winbindd_proto.h
+++ b/source3/nsswitch/winbindd_proto.h
@@ -5,32 +5,33 @@
/*The following definitions come from nsswitch/winbindd.c */
+void winbindd_dump_status(void);
int main(int argc, char **argv);
/*The following definitions come from nsswitch/winbindd_cache.c */
void winbindd_cache_init(void);
-void winbindd_fill_user_cache(char *domain_name,
- struct acct_info *sam_entries,
- int num_sam_entries);
-void winbindd_fill_group_cache(char *domain_name,
- struct acct_info *sam_entries,
- int num_sam_entries);
-void winbindd_fill_user_cache_entry(char *domain, char *user_name,
+void winbindd_store_user_cache(char *domain,
+ struct getpwent_user *sam_entries,
+ int num_sam_entries);
+void winbindd_store_group_cache(char *domain,
+ struct acct_info *sam_entries,
+ int num_sam_entries);
+void winbindd_store_user_cache_entry(char *domain, char *user_name,
+ struct winbindd_pw *pw);
+void winbindd_store_uid_cache_entry(char *domain, uid_t uid,
struct winbindd_pw *pw);
-void winbindd_fill_uid_cache_entry(char *domain, uid_t uid,
- struct winbindd_pw *pw);
-void winbindd_fill_group_cache_entry(char *domain, char *group_name,
- struct winbindd_gr *gr, void *extra_data,
- int extra_data_len);
-void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
- struct winbindd_gr *gr, void *extra_data,
- int extra_data_len);
-BOOL winbindd_fetch_user_cache(char *domain_name,
- struct acct_info **sam_entries,
+void winbindd_store_group_cache_entry(char *domain, char *group_name,
+ struct winbindd_gr *gr, void *extra_data,
+ int extra_data_len);
+void winbindd_store_gid_cache_entry(char *domain, gid_t gid,
+ struct winbindd_gr *gr, void *extra_data,
+ int extra_data_len);
+BOOL winbindd_fetch_user_cache(char *domain_name,
+ struct getpwent_user **sam_entries,
int *num_entries);
-BOOL winbindd_fetch_group_cache(char *domain_name,
- struct acct_info **sam_entries,
+BOOL winbindd_fetch_group_cache(char *domain_name,
+ struct acct_info **sam_entries,
int *num_entries);
BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
struct winbindd_pw *pw);
@@ -43,15 +44,19 @@ BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
struct winbindd_gr *gr,
void **extra_data, int *extra_data_len);
void winbindd_flush_cache(void);
+void winbindd_cache_dump_status(void);
/*The following definitions come from nsswitch/winbindd_group.c */
-enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
+ *state);
enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
*state);
enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state);
/*The following definitions come from nsswitch/winbindd_idmap.c */
@@ -66,34 +71,60 @@ BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid,
BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid,
struct winbindd_domain **domain);
BOOL winbindd_idmap_init(void);
+void winbindd_idmap_dump_status(void);
+
+/*The following definitions come from nsswitch/winbindd_misc.c */
+
+BOOL _get_trust_account_password(char *domain, unsigned char *ret_pwd,
+ time_t *pass_last_set_time);
+enum winbindd_result winbindd_check_machine_acct(
+ struct winbindd_cli_state *state);
+enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
+ *state);
/*The following definitions come from nsswitch/winbindd_pam.c */
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) ;
+enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state);
+
+/*The following definitions come from nsswitch/winbindd_sid.c */
+
+enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state);
/*The following definitions come from nsswitch/winbindd_user.c */
-enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state) ;
+enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state
+ *state) ;
enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state
*state);
enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state);
/*The following definitions come from nsswitch/winbindd_util.c */
+void debug_conn_state(void);
BOOL domain_handles_open(struct winbindd_domain *domain);
-void establish_connections(void) ;
+void winbindd_kill_connections(struct winbindd_domain *domain);
+void winbindd_kill_all_connections(void);
+void establish_connections(BOOL force_reestablish) ;
BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain);
BOOL get_domain_info(struct winbindd_domain *domain);
-BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
- char *name, DOM_SID *sid,
+BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid,
enum SID_NAME_USE *type);
-BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
- DOM_SID *sid, char *name,
+BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name,
enum SID_NAME_USE *type);
BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain,
uint32 user_rid, SAM_USERINFO_CTR *user_info);
+BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain,
+ uint32 user_rid, uint32 *num_groups,
+ DOM_GID **user_groups);
BOOL winbindd_lookup_groupinfo(struct winbindd_domain *domain,
uint32 group_rid, GROUP_INFO_CTR *info);
BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
@@ -105,9 +136,14 @@ int winbindd_lookup_aliasmem(struct winbindd_domain *domain,
DOM_SID ***sids, char ***names,
enum SID_NAME_USE **name_types);
struct winbindd_domain *find_domain_from_name(char *domain_name);
+struct winbindd_domain *find_domain_from_sid(DOM_SID *sid);
void free_getent_state(struct getent_state *state);
BOOL winbindd_param_init(void);
char *winbindd_cmd_to_string(enum winbindd_cmd cmd);
-void parse_domain_user(char *domuser, fstring domain, fstring user);
uint32 domain_sequence_number(char *domain_name);
+uint32 winbindd_query_dispinfo(struct winbindd_domain *domain,
+ uint32 *start_ndx, uint16 info_level,
+ uint32 *num_entries, SAM_DISPINFO_CTR *ctr);
+BOOL check_domain_env(char *domain_env, char *domain);
+void parse_domain_user(char *domuser, fstring domain, fstring user);
#endif /* _WINBINDD_PROTO_H_ */
diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c
index f3e62d2f7f..66e220f927 100644
--- a/source3/nsswitch/winbindd_user.c
+++ b/source3/nsswitch/winbindd_user.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 2.0
- Winbind daemon - user related function
+ Winbind daemon - user related functions
Copyright (C) Tim Potter 2000
@@ -25,144 +25,166 @@
/* Fill a pwent structure with information we have obtained */
-static void winbindd_fill_pwent(struct winbindd_pw *pw, char *name,
- uid_t unix_uid, gid_t unix_gid,
- char *full_name)
+static BOOL winbindd_fill_pwent(char *domain_name, char *name,
+ uint32 user_rid, uint32 group_rid,
+ char *full_name, struct winbindd_pw *pw)
{
- pstring homedir;
- fstring name_domain, name_user;
-
- if (!pw || !name) {
- return;
- }
-
- /* Fill in uid/gid */
-
- pw->pw_uid = unix_uid;
- pw->pw_gid = unix_gid;
-
- /* Username */
-
- safe_strcpy(pw->pw_name, name, sizeof(pw->pw_name) - 1);
-
- /* Full name (gecos) */
-
- safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
-
- /* Home directory and shell - use template config parameters. The
- defaults are /tmp for the home directory and /bin/false for shell. */
-
- parse_domain_user(name, name_domain, name_user);
-
- pstrcpy(homedir, lp_template_homedir());
-
- pstring_sub(homedir, "%U", name_user);
- pstring_sub(homedir, "%D", name_domain);
-
- safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1);
-
- safe_strcpy(pw->pw_shell, lp_template_shell(), sizeof(pw->pw_shell) - 1);
-
- /* Password - set to "x" as we can't generate anything useful here.
- Authentication can be done using the pam_ntdom module. */
-
- safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+ fstring name_domain, name_user;
+ pstring homedir;
+
+ if (!pw || !name) {
+ return False;
+ }
+
+ /* Resolve the uid number */
+
+ if (!winbindd_idmap_get_uid_from_rid(domain_name, user_rid,
+ &pw->pw_uid)) {
+ DEBUG(1, ("error getting user id for rid %d\n", user_rid));
+ return False;
+ }
+
+ /* Resolve the gid number */
+
+ if (!winbindd_idmap_get_gid_from_rid(domain_name, group_rid,
+ &pw->pw_gid)) {
+ DEBUG(1, ("error getting group id for rid %d\n", group_rid));
+ return False;
+ }
+
+ /* Username */
+
+ safe_strcpy(pw->pw_name, name, sizeof(pw->pw_name) - 1);
+
+ /* Full name (gecos) */
+
+ safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
+
+ /* Home directory and shell - use template config parameters. The
+ defaults are /tmp for the home directory and /bin/false for
+ shell. */
+
+ parse_domain_user(name, name_domain, name_user);
+
+ pstrcpy(homedir, lp_template_homedir());
+
+ /*
+ * Insist name_user is lowercase, name_domain is uppercase.
+ * This is a hack. JRA.
+ */
+
+ strlower(name_user);
+ strupper(name_domain);
+
+ pstring_sub(homedir, "%U", name_user);
+ pstring_sub(homedir, "%D", name_domain);
+
+ safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1);
+
+ safe_strcpy(pw->pw_shell, lp_template_shell(),
+ sizeof(pw->pw_shell) - 1);
+
+ /* Password - set to "x" as we can't generate anything useful here.
+ Authentication can be done using the pam_ntdom module. */
+
+ safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+
+ return True;
}
/* Return a password structure from a username. Specify whether cached data
can be returned. */
-enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state)
+enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state
+ *state)
{
- uint32 name_type, user_rid, group_rid;
- SAM_USERINFO_CTR user_info;
- DOM_SID user_sid;
- fstring name_domain, name_user, name, gecos_name;
- struct winbindd_domain *domain;
- uid_t uid;
- gid_t gid;
-
- /* Parse domain and username */
- parse_domain_user(state->request.data.username, name_domain, name_user);
-
- /* Reject names that don't have a domain - i.e name_domain contains the
- entire name. */
+ uint32 name_type, user_rid, group_rid;
+ SAM_USERINFO_CTR user_info;
+ DOM_SID user_sid;
+ fstring name_domain, name_user, name, gecos_name;
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5d]: getpwnam %s\n", state->pid,
+ state->request.data.username));
+
+ /* Parse domain and username */
+
+ parse_domain_user(state->request.data.username, name_domain,
+ name_user);
+
+ /* Reject names that don't have a domain - i.e name_domain contains
+ the entire name. */
- if (strequal(name_domain, "")) {
- return WINBINDD_ERROR;
- }
-
- /* Get info for the domain */
-
- if ((domain = find_domain_from_name(name_domain)) == NULL) {
- DEBUG(0, ("could not find domain entry for domain %s\n", name_domain));
- return WINBINDD_ERROR;
- }
-
- /* Check for cached user entry */
-
- if (winbindd_fetch_user_cache_entry(name_domain, name_user,
- &state->response.data.pw)) {
- return WINBINDD_OK;
- }
-
- slprintf(name,sizeof(name)-1,"%s\\%s", name_domain, name_user);
-
- /* Get rid and name type from name */
- /* the following costs 1 packet */
- if (!winbindd_lookup_sid_by_name(domain, name, &user_sid, &name_type)) {
- DEBUG(1, ("user '%s' does not exist\n", name_user));
- return WINBINDD_ERROR;
- }
-
- if (name_type != SID_NAME_USER) {
- DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, name_type));
- return WINBINDD_ERROR;
- }
-
- /* Get some user info. Split the user rid from the sid obtained from
- the winbind_lookup_by_name() call and use it in a
- winbind_lookup_userinfo() */
+ if (strequal(name_domain, "")) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Get info for the domain */
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(0, ("could not find domain entry for domain %s\n",
+ name_domain));
+ return WINBINDD_ERROR;
+ }
+
+ if (!domain_handles_open(domain)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Check for cached user entry */
+
+ if (winbindd_fetch_user_cache_entry(name_domain, name_user,
+ &state->response.data.pw)) {
+ return WINBINDD_OK;
+ }
+
+ slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user);
+
+ /* Get rid and name type from name. The following costs 1 packet */
+
+ if (!winbindd_lookup_sid_by_name(name, &user_sid, &name_type)) {
+ DEBUG(1, ("user '%s' does not exist\n", name_user));
+ return WINBINDD_ERROR;
+ }
+
+ if (name_type != SID_NAME_USER) {
+ DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
+ name_type));
+ return WINBINDD_ERROR;
+ }
+
+ /* Get some user info. Split the user rid from the sid obtained
+ from the winbind_lookup_by_name() call and use it in a
+ winbind_lookup_userinfo() */
- sid_split_rid(&user_sid, &user_rid);
-
- /* the following costs 3 packets */
- if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) {
- DEBUG(1, ("pwnam_from_user(): error getting user info for user '%s'\n",
- name_user));
- return WINBINDD_ERROR;
- }
+ sid_split_rid(&user_sid, &user_rid);
+
+ /* The following costs 3 packets */
+
+ if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) {
+ DEBUG(1, ("pwnam_from_user(): error getting user info for "
+ "user '%s'\n", name_user));
+ return WINBINDD_ERROR;
+ }
- group_rid = user_info.info.id21->group_rid;
- unistr2_to_ascii(gecos_name, &user_info.info.id21->uni_full_name,
- sizeof(gecos_name) - 1);
-
- free_samr_userinfo_ctr(&user_info);
-
- /* Resolve the uid number */
-
- if (!winbindd_idmap_get_uid_from_rid(domain->name, user_rid, &uid)) {
- DEBUG(1, ("error getting user id for user %s\n", name_user));
- return WINBINDD_ERROR;
- }
-
- /* Resolve the gid number */
-
- if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
- DEBUG(1, ("error getting group id for user %s\n", name_user));
- return WINBINDD_ERROR;
- }
-
- /* Now take all this information and fill in a passwd structure */
-
- winbindd_fill_pwent(&state->response.data.pw,
- state->request.data.username, uid, gid,
- gecos_name);
-
- winbindd_fill_user_cache_entry(name_domain, name_user,
- &state->response.data.pw);
-
- return WINBINDD_OK;
+ group_rid = user_info.info.id21->group_rid;
+ unistr2_to_ascii(gecos_name, &user_info.info.id21->uni_full_name,
+ sizeof(gecos_name) - 1);
+
+ free_samr_userinfo_ctr(&user_info);
+
+ /* Now take all this information and fill in a passwd structure */
+
+ if (!winbindd_fill_pwent(domain->name, state->request.data.username,
+ user_rid, group_rid, gecos_name,
+ &state->response.data.pw)) {
+ return WINBINDD_ERROR;
+ }
+
+ winbindd_store_user_cache_entry(name_domain, name_user,
+ &state->response.data.pw);
+
+ return WINBINDD_OK;
}
/* Return a password structure given a uid number */
@@ -170,77 +192,95 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *stat
enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state
*state)
{
- DOM_SID user_sid;
- struct winbindd_domain *domain;
- uint32 user_rid, group_rid;
- fstring user_name, gecos_name;
- enum SID_NAME_USE name_type;
- SAM_USERINFO_CTR user_info;
- gid_t gid;
-
- /* Get rid from 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;
- }
-
- /* Check for cached uid entry */
- if (winbindd_fetch_uid_cache_entry(domain->name, state->request.data.uid,
- &state->response.data.pw)) {
- return WINBINDD_OK;
- }
-
-
- /* Get name and name type from rid */
-
- sid_copy(&user_sid, &domain->sid);
- sid_append_rid(&user_sid, user_rid);
-
- if (!winbindd_lookup_name_by_sid(domain, &user_sid, user_name,
- &name_type)) {
- fstring temp;
-
- sid_to_string(temp, &user_sid);
- DEBUG(1, ("Could not lookup sid %s\n", temp));
- return WINBINDD_ERROR;
- }
-
- if (strcmp("\\", lp_winbind_separator())) {
- string_sub(user_name, "\\", lp_winbind_separator(), sizeof(fstring));
- }
-
- /* Get some user info */
-
- if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) {
- DEBUG(1, ("pwnam_from_uid(): error getting user info for user '%s'\n",
- user_name));
- return WINBINDD_ERROR;
- }
-
- group_rid = user_info.info.id21->group_rid;
- unistr2_to_ascii(gecos_name, &user_info.info.id21->uni_full_name,
- sizeof(gecos_name) - 1);
-
- free_samr_userinfo_ctr(&user_info);
-
- /* Resolve gid number */
-
- if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
- DEBUG(1, ("error getting group id for user %s\n", user_name));
- return WINBINDD_ERROR;
- }
-
- /* Fill in password structure */
-
- winbindd_fill_pwent(&state->response.data.pw, user_name,
- state->request.data.uid, gid, gecos_name);
-
- winbindd_fill_uid_cache_entry(domain->name, state->request.data.uid,
- &state->response.data.pw);
-
- return WINBINDD_OK;
+ DOM_SID user_sid;
+ struct winbindd_domain *domain;
+ uint32 user_rid, group_rid;
+ fstring user_name, gecos_name;
+ enum SID_NAME_USE name_type;
+ SAM_USERINFO_CTR user_info;
+ gid_t gid;
+
+ /* 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]: getpwuid %d\n", state->pid,
+ state->request.data.uid));
+
+ /* Get rid from 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;
+ }
+
+ if (!domain_handles_open(domain)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Check for cached uid entry */
+
+ if (winbindd_fetch_uid_cache_entry(domain->name,
+ state->request.data.uid,
+ &state->response.data.pw)) {
+ return WINBINDD_OK;
+ }
+
+ /* Get name and name type from rid */
+
+ sid_copy(&user_sid, &domain->sid);
+ sid_append_rid(&user_sid, user_rid);
+
+ if (!winbindd_lookup_name_by_sid(&user_sid, user_name, &name_type)) {
+ fstring temp;
+
+ sid_to_string(temp, &user_sid);
+ DEBUG(1, ("Could not lookup sid %s\n", temp));
+ return WINBINDD_ERROR;
+ }
+
+ if (strcmp("\\", lp_winbind_separator())) {
+ string_sub(user_name, "\\", lp_winbind_separator(),
+ sizeof(fstring));
+ }
+
+ /* Get some user info */
+
+ if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) {
+ DEBUG(1, ("pwnam_from_uid(): error getting user info for "
+ "user '%s'\n", user_name));
+ return WINBINDD_ERROR;
+ }
+
+ group_rid = user_info.info.id21->group_rid;
+ unistr2_to_ascii(gecos_name, &user_info.info.id21->uni_full_name,
+ sizeof(gecos_name) - 1);
+
+ free_samr_userinfo_ctr(&user_info);
+
+ /* Resolve gid number */
+
+ if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
+ DEBUG(1, ("error getting group id for user %s\n", user_name));
+ return WINBINDD_ERROR;
+ }
+
+ /* Fill in password structure */
+
+ if (!winbindd_fill_pwent(domain->name, user_name, user_rid, group_rid,
+ gecos_name, &state->response.data.pw)) {
+ return WINBINDD_ERROR;
+ }
+
+ winbindd_store_uid_cache_entry(domain->name, state->request.data.uid,
+ &state->response.data.pw);
+
+ return WINBINDD_OK;
}
/*
@@ -253,8 +293,16 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
{
struct winbindd_domain *tmp;
+ DEBUG(3, ("[%5d]: setpwent\n", state->pid));
+
if (state == NULL) return WINBINDD_ERROR;
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_users()) {
+ return WINBINDD_ERROR;
+ }
+
/* Free old static data if it exists */
if (state->getpwent_state != NULL) {
@@ -270,7 +318,7 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
/* Skip domains other than WINBINDD_DOMAIN environment variable */
if ((strcmp(state->request.domain, "") != 0) &&
- (strcmp(state->request.domain, tmp->name) != 0)) {
+ !check_domain_env(state->request.domain, tmp->name)) {
continue;
}
@@ -297,6 +345,8 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
{
+ DEBUG(3, ("[%5d]: endpwent\n", state->pid));
+
if (state == NULL) return WINBINDD_ERROR;
free_getent_state(state->getpwent_state);
@@ -305,110 +355,339 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
+/* Get partial list of domain users for a domain. We fill in the sam_entries,
+ and num_sam_entries fields with domain user information. The dispinfo_ndx
+ field is incremented to the index of the next user to fetch. Return True if
+ some users were returned, False otherwise. */
+
+#define MAX_FETCH_SAM_ENTRIES 100
+
+static BOOL get_sam_user_entries(struct getent_state *ent)
+{
+ uint32 status, num_entries;
+ SAM_DISPINFO_1 info1;
+ SAM_DISPINFO_CTR ctr;
+ struct getpwent_user *name_list = NULL;
+ uint32 group_rid;
+
+ if (ent->got_all_sam_entries) {
+ return False;
+ }
+
+ ZERO_STRUCT(info1);
+ ZERO_STRUCT(ctr);
+
+ ctr.sam.info1 = &info1;
+
+#if 0
+ /* Look in cache for entries, else get them direct */
+
+ if (winbindd_fetch_user_cache(ent->domain->name,
+ (struct getpwent_user **)
+ &ent->sam_entries,
+ &ent->num_sam_entries)) {
+ return True;
+ }
+#endif
+
+ /* For the moment we set the primary group for every user to be the
+ Domain Users group. There are serious problems with determining
+ the actual primary group for large domains. This should really
+ be made into a 'winbind force group' smb.conf parameter or
+ something like that. */
+
+ group_rid = DOMAIN_GROUP_RID_USERS;
+
+ if (!domain_handles_open(ent->domain)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Free any existing user info */
+
+ if (ent->sam_entries) {
+ free(ent->sam_entries);
+ ent->sam_entries = NULL;
+ ent->num_sam_entries = 0;
+ }
+
+ /* Call query_dispinfo to get a list of usernames and user rids */
+
+ do {
+ int i;
+
+ num_entries = 0;
+
+ status = winbindd_query_dispinfo(ent->domain,
+ &ent->dispinfo_ndx, 1,
+ &num_entries, &ctr);
+
+ if (num_entries) {
+ name_list = Realloc(name_list,
+ sizeof(struct getpwent_user) *
+ (ent->num_sam_entries +
+ num_entries));
+ }
+
+ for (i = 0; i < num_entries; i++) {
+
+ /* Store account name and gecos */
+
+ unistr2_to_ascii(
+ name_list[ent->num_sam_entries + i].name,
+ &info1.str[i].uni_acct_name,
+ sizeof(fstring));
+
+ unistr2_to_ascii(
+ name_list[ent->num_sam_entries + i].gecos,
+ &info1.str[i].uni_full_name,
+ sizeof(fstring));
+
+ /* User and group ids */
+
+ name_list[ent->num_sam_entries + i].user_rid =
+ info1.sam[i].rid_user;
+
+ name_list[ent->num_sam_entries + i].
+ group_rid = group_rid;
+ }
+
+ ent->num_sam_entries += num_entries;
+
+ if (status != STATUS_MORE_ENTRIES) {
+ break;
+ }
+
+ } while (ent->num_sam_entries < MAX_FETCH_SAM_ENTRIES);
+
+#if 0
+ /* Fill cache with received entries */
+
+ winbindd_store_user_cache(ent->domain->name, ent->sam_entries,
+ ent->num_sam_entries);
+#endif
+
+ /* Fill in remaining fields */
+
+ ent->sam_entries = name_list;
+ ent->sam_entry_index = 0;
+ ent->got_all_sam_entries = (status != STATUS_MORE_ENTRIES);
+
+ return ent->num_sam_entries > 0;
+}
+
/* Fetch next passwd entry from ntdom database */
+#define MAX_GETPWENT_USERS 500
+
enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
{
- if (state == NULL) return WINBINDD_ERROR;
+ struct getent_state *ent;
+ struct winbindd_pw *user_list;
+ int num_users, user_list_ndx = 0, i;
+ char *sep;
- /* Process the current head of the getent_state list */
+ DEBUG(3, ("[%5d]: getpwent\n", state->pid));
- while(state->getpwent_state != NULL) {
- struct getent_state *ent = state->getpwent_state;
+ if (state == NULL) return WINBINDD_ERROR;
- /* Get list of user entries for this pipe */
+ /* Check user has enabled this */
- if (!ent->got_sam_entries) {
- uint32 status, start_ndx = 0;
+ if (!lp_winbind_enum_users()) {
+ return WINBINDD_ERROR;
+ }
- /* Look in cache for entries, else get them direct */
+ /* Allocate space for returning a chunk of users */
- if (!winbindd_fetch_user_cache(ent->domain->name,
- &ent->sam_entries,
- &ent->num_sam_entries)) {
+ num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
+
+ if ((state->response.extra_data =
+ malloc(num_users * sizeof(struct winbindd_pw))) == NULL) {
+ return WINBINDD_ERROR;
+ }
- /* Fetch the user entries */
+ memset(state->response.extra_data, 0, num_users *
+ sizeof(struct winbindd_pw));
- if (!domain_handles_open(ent->domain)) goto cleanup;
+ user_list = (struct winbindd_pw *)state->response.extra_data;
+ sep = lp_winbind_separator();
+
+ if (!(ent = state->getpwent_state)) {
+ return WINBINDD_ERROR;
+ }
- do {
- status =
- samr_enum_dom_users(
- &ent->domain->sam_dom_handle, &start_ndx, 0, 0,
- 0x10000, &ent->sam_entries, &ent->num_sam_entries);
- } while (status == STATUS_MORE_ENTRIES);
+ /* Start sending back users */
- /* Fill cache with received entries */
-
- winbindd_fill_user_cache(ent->domain->name, ent->sam_entries,
- ent->num_sam_entries);
- }
-
- ent->got_sam_entries = True;
- }
-
- /* Send back a user */
-
- while (ent->sam_entry_index < ent->num_sam_entries) {
- enum winbindd_result result;
- fstring domain_user_name;
- char *user_name = (ent->sam_entries)
- [ent->sam_entry_index].acct_name;
-
- /* Don't bother with machine accounts */
-
- if (user_name[strlen(user_name) - 1] == '$') {
- ent->sam_entry_index++;
- continue;
- }
-
- /* Prepend domain to name */
-
- slprintf(domain_user_name, sizeof(domain_user_name)-1,
- "%s%s%s", ent->domain->name, lp_winbind_separator(), user_name);
-
- /* Get passwd entry from user name */
-
- fstrcpy(state->request.data.username, domain_user_name);
- result = winbindd_getpwnam_from_user(state);
-
- ent->sam_entry_index++;
-
- /* Return if user lookup worked */
-
- if (result == WINBINDD_OK) {
- return result;
- }
-
- /* Try next user */
-
- DEBUG(1, ("could not getpwnam_from_user for username %s\n",
- domain_user_name));
- }
+ for (i = 0; i < num_users; i++) {
+ struct getpwent_user *name_list = NULL;
+ fstring domain_user_name;
+ uint32 result;
- /* We've exhausted all users for this pipe - close it down and
- start on the next one. */
+ /* Do we need to fetch another chunk of users? */
- cleanup:
+ if (ent->num_sam_entries == ent->sam_entry_index) {
- /* Free mallocated memory for sam entries. The data stored here
- may have been allocated from the cache. */
+ while(ent && !get_sam_user_entries(ent)) {
+ struct getent_state *next_ent;
- if (ent->sam_entries != NULL) free(ent->sam_entries);
- ent->sam_entries = NULL;
+ /* Free state information for this domain */
- /* Free state information for this domain */
+ safe_free(ent->sam_entries);
+ ent->sam_entries = NULL;
- {
- struct getent_state *old_ent;
+ next_ent = ent->next;
+ DLIST_REMOVE(state->getpwent_state, ent);
+
+ free(ent);
+ ent = next_ent;
+ }
+
+ /* No more domains */
+
+ if (!ent) break;
+ }
+
+ name_list = ent->sam_entries;
+
+ /* Skip machine accounts */
+
+ if (name_list[ent->sam_entry_index].
+ name[strlen(name_list[ent->sam_entry_index].name) - 1]
+ == '$') {
+ ent->sam_entry_index++;
+ continue;
+ }
+
+ /* Lookup user info */
+
+ slprintf(domain_user_name, sizeof(domain_user_name) - 1,
+ "%s%s%s", ent->domain->name, sep,
+ name_list[ent->sam_entry_index].name);
+
+ result = winbindd_fill_pwent(
+ ent->domain->name,
+ domain_user_name,
+ name_list[ent->sam_entry_index].user_rid,
+ name_list[ent->sam_entry_index].group_rid,
+ name_list[ent->sam_entry_index].gecos,
+ &user_list[user_list_ndx]);
+
+ ent->sam_entry_index++;
+
+ /* Add user to return list */
+
+ if (result) {
+
+ user_list_ndx++;
+ state->response.data.num_entries++;
+ state->response.length +=
+ sizeof(struct winbindd_pw);
+
+ } else {
+ DEBUG(1, ("could not lookup domain user %s\n",
+ domain_user_name));
+ }
+
+ }
+
+ /* Out of domains */
+
+ return (user_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
+}
- old_ent = state->getpwent_state;
- DLIST_REMOVE(state->getpwent_state, state->getpwent_state);
- free(old_ent);
+/* List domain users without mapping to unix ids */
+
+enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ SAM_DISPINFO_CTR ctr;
+ SAM_DISPINFO_1 info1;
+ uint32 num_entries = 0, total_entries = 0;
+ char *extra_data = NULL;
+ int extra_data_len = 0;
+
+ DEBUG(3, ("[%5d]: list users\n", state->pid));
+
+ /* Enumerate over trusted domains */
+
+ ctr.sam.info1 = &info1;
+
+ for (domain = domain_list; domain; domain = domain->next) {
+ uint32 status, start_ndx = 0;
+
+ /* Skip domains other than WINBINDD_DOMAIN environment
+ variable */
+
+ if ((strcmp(state->request.domain, "") != 0) &&
+ !check_domain_env(state->request.domain, domain->name)) {
+ continue;
+ }
+
+ if (!domain_handles_open(domain)) {
+ continue;
+ }
+
+ /* Query display info */
+
+ do {
+ int i;
+
+ status = winbindd_query_dispinfo(domain, &start_ndx,
+ 1, &num_entries,
+ &ctr);
+
+ if (num_entries == 0) {
+ continue;
+ }
+
+ /* Allocate some memory for extra data */
+
+ total_entries += num_entries;
+
+ extra_data = Realloc(extra_data, sizeof(fstring) *
+ total_entries);
+
+ if (!extra_data) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Pack user list into extra data fields */
+
+ for (i = 0; i < num_entries; i++) {
+ UNISTR2 *uni_acct_name;
+ fstring acct_name, name;
+
+ /* Convert unistring to ascii */
+
+ uni_acct_name = &ctr.sam.info1->str[i].
+ uni_acct_name;
+ unistr2_to_ascii(acct_name, uni_acct_name,
+ sizeof(acct_name) - 1);
+
+ slprintf(name, sizeof(name) - 1, "%s%s%s",
+ domain->name, lp_winbind_separator(),
+ acct_name);
+
+ /* Append to extra data */
+
+ memcpy(&extra_data[extra_data_len], name,
+ strlen(name));
+ extra_data_len += strlen(name);
+
+ extra_data[extra_data_len++] = ',';
+ }
+ } while (status == STATUS_MORE_ENTRIES);
}
- }
- /* Out of pipes so we're done */
+ /* Assign extra_data fields in response structure */
+
+ if (extra_data) {
+ extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data = extra_data;
+ state->response.length += extra_data_len;
+ }
+
+ /* No domains responded but that's still OK so don't return an
+ error. */
- return WINBINDD_ERROR;
+ return WINBINDD_OK;
}
diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c
index 80d6955e6c..0661586376 100644
--- a/source3/nsswitch/winbindd_util.c
+++ b/source3/nsswitch/winbindd_util.c
@@ -22,36 +22,40 @@
*/
#include "winbindd.h"
+#include "sids.h"
-BOOL domain_handles_open(struct winbindd_domain *domain)
-{
- return domain->sam_handle_open &&
- domain->sam_dom_handle_open &&
- rpc_hnd_ok(&domain->sam_handle) &&
- rpc_hnd_ok(&domain->sam_dom_handle);
-}
+/* Debug connection state */
-static BOOL resolve_dc_name(char *domain_name, fstring domain_controller)
+void debug_conn_state(void)
{
- struct in_addr ip;
- extern pstring global_myname;
-
- /* if its our primary domain and password server is not '*' then use the
- password server parameter */
- if (strcmp(domain_name,lp_workgroup()) == 0 && !lp_wildcard_dc()) {
- fstrcpy(domain_controller, lp_passwordserver());
- return True;
- }
+ struct winbindd_domain *domain;
- if (!resolve_name(domain_name, &ip, 0x1B)) return False;
+ DEBUG(3, ("server: dc=%s, pwdb_init=%d, lsa_hnd=%d\n",
+ server_state.controller,
+ server_state.pwdb_initialised,
+ server_state.lsa_handle_open));
- return lookup_pdc_name(global_myname, domain_name, &ip,
- domain_controller);
+ for (domain = domain_list; domain; domain = domain->next) {
+ DEBUG(3, ("%s: dc=%s, got_sid=%d, sam_hnd=%d sam_dom_hnd=%d\n",
+ domain->name, domain->controller,
+ domain->got_domain_info, domain->sam_handle_open,
+ domain->sam_dom_handle_open));
+ }
}
+/* Add a trusted domain to our list of domains */
+
static struct winbindd_domain *add_trusted_domain(char *domain_name)
{
- struct winbindd_domain *domain;
+ struct winbindd_domain *domain, *tmp;
+
+ for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ if (strcmp(domain_name, tmp->name) == 0) {
+ DEBUG(3, ("domain %s already in trusted list\n",
+ domain_name));
+ return tmp;
+ }
+ }
DEBUG(1, ("adding trusted domain %s\n", domain_name));
@@ -77,12 +81,13 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name)
}
/* Look up global info for the winbind daemon */
+
static BOOL get_trusted_domains(void)
{
uint32 enum_ctx = 0;
uint32 num_doms = 0;
char **domains = NULL;
- DOM_SID **sids = NULL;
+ DOM_SID *sids = NULL;
BOOL result;
int i;
@@ -110,100 +115,184 @@ static BOOL get_trusted_domains(void)
}
}
- /* Free memory */
- free_char_array(num_doms, domains);
- free_sid_array(num_doms, sids);
-
return True;
}
+/* Open sam and sam domain handles */
-/* Open sam and sam domain handles to a domain and cache the results */
static BOOL open_sam_handles(struct winbindd_domain *domain)
{
- /* Get domain info */
+ /* Get domain info (sid and controller name) */
+
if (!domain->got_domain_info) {
domain->got_domain_info = get_domain_info(domain);
if (!domain->got_domain_info) return False;
}
- if ((domain->sam_handle_open && !rpc_hnd_ok(&domain->sam_handle)) ||
- (domain->sam_dom_handle_open &&
- !rpc_hnd_ok(&domain->sam_dom_handle))) {
+ /* Shut down existing sam handles */
- domain->got_domain_info = get_domain_info(domain);
- if (domain->sam_dom_handle_open) {
- samr_close(&domain->sam_dom_handle);
- domain->sam_dom_handle_open = False;
- }
- if (domain->sam_handle_open) {
- samr_close(&domain->sam_handle);
- domain->sam_handle_open = False;
- }
+ if (domain->sam_dom_handle_open) {
+ samr_close(&domain->sam_dom_handle);
+ domain->sam_dom_handle_open = False;
}
- /* Open sam handle if it isn't already open */
+ if (domain->sam_handle_open) {
+ samr_close(&domain->sam_handle);
+ domain->sam_handle_open = False;
+ }
- if (!domain->sam_handle_open) {
+ /* Open sam handle */
- domain->sam_handle_open =
- samr_connect(domain->controller,
- SEC_RIGHTS_MAXIMUM_ALLOWED,
- &domain->sam_handle);
+ domain->sam_handle_open =
+ samr_connect(domain->controller,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &domain->sam_handle);
- if (!domain->sam_handle_open) return False;
- }
+ if (!domain->sam_handle_open) return False;
+
+ /* Open sam domain handle */
+
+ domain->sam_dom_handle_open =
+ samr_open_domain(&domain->sam_handle,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &domain->sid,
+ &domain->sam_dom_handle);
+
+ if (!domain->sam_dom_handle_open) return False;
+
+ return True;
+}
+
+static BOOL rpc_hnd_ok(CLI_POLICY_HND *hnd)
+{
+ return hnd->cli->fd != -1;
+}
- /* Open sam domain handle if it isn't already open */
+/* Return true if the SAM domain handles are open and responding. */
- if (!domain->sam_dom_handle_open) {
+BOOL domain_handles_open(struct winbindd_domain *domain)
+{
+ time_t t;
+ BOOL result;
- domain->sam_dom_handle_open =
- samr_open_domain(&domain->sam_handle,
- SEC_RIGHTS_MAXIMUM_ALLOWED,
- &domain->sid, &domain->sam_dom_handle);
+ /* Check we haven't checked too recently */
- if (!domain->sam_dom_handle_open) return False;
+ t = time(NULL);
+
+ if ((t - domain->last_check) < WINBINDD_ESTABLISH_LOOP) {
+ return domain->sam_handle_open &&
+ domain->sam_dom_handle_open;
}
- return True;
+ DEBUG(3, ("checking domain handles for domain %s\n", domain->name));
+ debug_conn_state();
+
+ domain->last_check = t;
+
+ /* Open sam handles if they are marked as closed */
+
+ if (!domain->sam_handle_open || !domain->sam_dom_handle_open) {
+ reopen:
+ DEBUG(3, ("opening sam handles\n"));
+ return open_sam_handles(domain);
+ }
+
+ /* Check sam handles are ok - the domain controller may have failed
+ and we need to move to a BDC. */
+
+ if (!rpc_hnd_ok(&domain->sam_handle) ||
+ !rpc_hnd_ok(&domain->sam_dom_handle)) {
+
+ /* We want to close the current connection but attempt
+ to open a new set, possibly to a new dc. If this
+ doesn't work then return False as we have no dc
+ to talk to. */
+
+ DEBUG(3, ("sam handles not responding\n"));
+
+ winbindd_kill_connections(domain);
+ goto reopen;
+ }
+
+ result = domain->sam_handle_open && domain->sam_dom_handle_open;
+
+ return result;
}
-/* Close all LSA and SAM connections */
+/* Shut down connections to all domain controllers */
-static void winbindd_kill_connections(void)
+void winbindd_kill_connections(struct winbindd_domain *domain)
{
- struct winbindd_cli_state *cli;
- struct winbindd_domain *domain;
+ BOOL is_server = False;
+ struct winbindd_domain *server_domain;
+
+ /* Find pointer to domain of pdc */
+
+ server_domain = find_domain_from_name(lp_workgroup());
+ if (!server_domain) return;
+
+ /* If NULL passed, use pdc */
+
+ if (!domain) {
+ domain = server_domain;
+ }
+
+ if (domain == server_domain ||
+ strequal(domain->name, lp_workgroup())) {
+ is_server = True;
+ }
- DEBUG(1,("killing winbindd connections\n"));
+ /* Log a level 0 message - this is probably a domain controller
+ failure */
- /* Close LSA connection */
+ DEBUG(0, ("killing connections to domain %s with controller %s\n",
+ domain->name, domain->controller));
- server_state.pwdb_initialised = False;
- server_state.lsa_handle_open = False;
- lsa_close(&server_state.lsa_handle);
+ debug_conn_state();
+
+ if (is_server) {
+ server_state.pwdb_initialised = False;
+ server_state.lsa_handle_open = False;
+ lsa_close(&server_state.lsa_handle);
+ }
+
+ /* Close domain sam handles but don't free them as this
+ severely traumatises the getent state. The connections
+ will be reopened later. */
+
+ if (domain->sam_dom_handle_open) {
+ samr_close(&domain->sam_dom_handle);
+ domain->sam_dom_handle_open = False;
+ }
+
+ if (domain->sam_handle_open) {
+ samr_close(&domain->sam_handle);
+ domain->sam_handle_open = False;
+ }
+
+ /* Re-lookup domain info which includes domain controller name */
- /* Close SAM connections */
+ domain->got_domain_info = False;
+}
+
+/* Kill connections to all servers */
+
+void winbindd_kill_all_connections(void)
+{
+ struct winbindd_domain *domain;
+
+ /* Iterate over domain list */
domain = domain_list;
- while(domain) {
+ while (domain) {
struct winbindd_domain *next;
- /* Close SAM handles */
+ /* Kill conections */
- if (domain->sam_dom_handle_open) {
- samr_close(&domain->sam_dom_handle);
- domain->sam_dom_handle_open = False;
- }
-
- if (domain->sam_handle_open) {
- samr_close(&domain->sam_handle);
- domain->sam_handle_open = False;
- }
+ winbindd_kill_connections(domain);
- /* Remove from list */
+ /* Remove domain from list */
next = domain->next;
DLIST_REMOVE(domain_list, domain);
@@ -211,68 +300,106 @@ static void winbindd_kill_connections(void)
domain = next;
}
+}
- /* We also need to go through and trash any pointers to domains in
- get{pw,gr}ent state records */
+static BOOL get_any_dc_name(char *domain, fstring srv_name)
+{
+ struct in_addr *ip_list, dc_ip;
+ extern pstring global_myname;
+ int count, i;
- for (cli = client_list; cli; cli = cli->next) {
- free_getent_state(cli->getpwent_state);
- free_getent_state(cli->getgrent_state);
+ /* Lookup domain controller name */
+
+ if (!get_dc_list(False, lp_workgroup(), &ip_list, &count))
+ return False;
+
+ /* Firstly choose a PDC/BDC who has the same network address as any
+ of our interfaces. */
+
+ for (i = 0; i < count; i++) {
+ if(!is_local_net(ip_list[i]))
+ goto got_ip;
}
+
+ i = (sys_random() % count);
+
+ got_ip:
+ dc_ip = ip_list[i];
+ free(ip_list);
+
+ if (!lookup_pdc_name(global_myname, lp_workgroup(),
+ &dc_ip, server_state.controller))
+ return False;
+
+ return True;
}
-/* Try to establish connections to NT servers */
+/* Attempt to connect to all domain controllers we know about */
-void establish_connections(void)
+void establish_connections(BOOL force_reestablish)
{
- struct winbindd_domain *domain;
static time_t lastt;
time_t t;
+ /* Check we haven't checked too recently */
+
t = time(NULL);
- if (t - lastt < WINBINDD_ESTABLISH_LOOP) return;
+ if ((t - lastt < WINBINDD_ESTABLISH_LOOP) && !force_reestablish) {
+ return;
+ }
lastt = t;
- /* maybe the connection died - if so then close up and restart */
+ DEBUG(3, ("establishing connections\n"));
+ debug_conn_state();
+
+ /* Maybe the connection died - if so then close up and restart */
+
if (server_state.pwdb_initialised &&
server_state.lsa_handle_open &&
!rpc_hnd_ok(&server_state.lsa_handle)) {
- winbindd_kill_connections();
+ winbindd_kill_connections(NULL);
}
if (!server_state.pwdb_initialised) {
- fstrcpy(server_state.controller, lp_passwordserver());
- if (lp_wildcard_dc()) {
- if (!resolve_dc_name(lp_workgroup(), server_state.controller)) {
- return;
- }
+
+ /* Lookup domain controller name */
+
+ if (!get_any_dc_name(lp_workgroup(),
+ server_state.controller)) {
+ return;
}
- server_state.pwdb_initialised = pwdb_initialise(False);
- if (!server_state.pwdb_initialised) return;
+ /* Initialise password database and sids */
+
+// server_state.pwdb_initialised = pwdb_initialise(False);
+ server_state.pwdb_initialised = True;
+
+ if (!server_state.pwdb_initialised)
+ return;
}
/* Open lsa handle if it isn't already open */
+
if (!server_state.lsa_handle_open) {
+
server_state.lsa_handle_open =
- lsa_open_policy(server_state.controller, &server_state.lsa_handle,
- False, SEC_RIGHTS_MAXIMUM_ALLOWED);
+ lsa_open_policy(server_state.controller,
+ False, SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &server_state.lsa_handle);
+
if (!server_state.lsa_handle_open) return;
- /* now we can talk to the server we can get some info */
+ /* Now we can talk to the server we can get some info */
+
get_trusted_domains();
}
- for (domain=domain_list; domain; domain=domain->next) {
- if (!domain_handles_open(domain)) {
- open_sam_handles(domain);
- }
- }
+ debug_conn_state();
}
-
/* Connect to a domain controller using get_any_dc_name() to discover
the domain name and sid */
+
BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
{
fstring level5_dom;
@@ -280,7 +407,7 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
uint32 enum_ctx = 0;
uint32 num_doms = 0;
char **domains = NULL;
- DOM_SID **sids = NULL;
+ DOM_SID *sids = NULL;
if (domain == NULL) {
return False;
@@ -289,7 +416,10 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
DEBUG(1, ("looking up sid for domain %s\n", domain_name));
/* Get controller name for domain */
- if (!resolve_dc_name(domain_name, domain->controller)) {
+
+ if (!get_any_dc_name(domain_name, domain->controller)) {
+ DEBUG(0, ("Could not resolve domain controller for domain %s\n",
+ domain_name));
return False;
}
@@ -312,7 +442,7 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
for(i = 0; i < num_doms; i++) {
if (strequal(domain_name, domains[i])) {
- sid_copy(&domain->sid, sids[i]);
+ sid_copy(&domain->sid, &sids[i]);
found = True;
break;
}
@@ -321,15 +451,9 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
res = found;
}
- /* Free memory */
-
- free_char_array(num_doms, domains);
- free_sid_array(num_doms, sids);
-
return res;
}
-
/* Lookup domain controller and sid for a domain */
BOOL get_domain_info(struct winbindd_domain *domain)
@@ -339,8 +463,14 @@ BOOL get_domain_info(struct winbindd_domain *domain)
DEBUG(1, ("Getting domain info for domain %s\n", domain->name));
/* Lookup domain sid */
+
if (!lookup_domain_sid(domain->name, domain)) {
DEBUG(0, ("could not find sid for domain %s\n", domain->name));
+
+ /* Could be a DC failure - shut down connections to this domain */
+
+ winbindd_kill_connections(domain);
+
return False;
}
@@ -356,8 +486,7 @@ BOOL get_domain_info(struct winbindd_domain *domain)
/* Lookup a sid in a domain from a name */
-BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
- char *name, DOM_SID *sid,
+BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid,
enum SID_NAME_USE *type)
{
int num_sids = 0, num_names = 1;
@@ -403,8 +532,7 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
/* Lookup a name in a domain from a sid */
-BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
- DOM_SID *sid, char *name,
+BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name,
enum SID_NAME_USE *type)
{
int num_sids = 1, num_names = 0;
@@ -413,8 +541,9 @@ BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
BOOL res;
/* Lookup name */
- res = lsa_lookup_sids(&server_state.lsa_handle, num_sids, &sid, &names,
- &types, &num_names);
+
+ res = lsa_lookup_sids(&server_state.lsa_handle, num_sids, sid,
+ &names, &types, &num_names);
/* Return name and type if successful */
@@ -446,19 +575,49 @@ BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain,
uint32 user_rid, SAM_USERINFO_CTR *user_info)
{
- if (!domain_handles_open(domain)) return False;
-
- return get_samr_query_userinfo(&domain->sam_dom_handle, 0x15, user_rid, user_info);
+ return get_samr_query_userinfo(&domain->sam_dom_handle, 0x15,
+ user_rid, user_info);
}
+/* Lookup groups a user is a member of. I wish Unix had a call like this! */
+
+BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain,
+ uint32 user_rid, uint32 *num_groups,
+ DOM_GID **user_groups)
+{
+ POLICY_HND user_pol;
+ BOOL result;
+
+ if (!samr_open_user(&domain->sam_dom_handle,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ user_rid, &user_pol)) {
+ return False;
+ }
+
+ if (cli_samr_query_usergroups(domain->sam_dom_handle.cli,
+ domain->sam_dom_handle.mem_ctx,
+ &user_pol, num_groups, user_groups)
+ != NT_STATUS_NOPROBLEMO) {
+ result = False;
+ goto done;
+ }
+
+ result = True;
+
+done:
+ cli_samr_close(domain->sam_dom_handle.cli,
+ domain->sam_dom_handle.mem_ctx, &user_pol);
+
+ return True;
+}
+
/* Lookup group information from a rid */
BOOL winbindd_lookup_groupinfo(struct winbindd_domain *domain,
uint32 group_rid, GROUP_INFO_CTR *info)
{
- if (!domain_handles_open(domain)) return False;
-
- return get_samr_query_groupinfo(&domain->sam_dom_handle, 1, group_rid, info);
+ return get_samr_query_groupinfo(&domain->sam_dom_handle, 1,
+ group_rid, info);
}
/* Lookup group membership given a rid */
@@ -468,40 +627,48 @@ BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
uint32 **rid_mem, char ***names,
enum SID_NAME_USE **name_types)
{
- if (!domain_handles_open(domain)) return False;
-
- return sam_query_groupmem(&domain->sam_dom_handle, group_rid, num_names,
- rid_mem, names, name_types);
+ return sam_query_groupmem(&domain->sam_dom_handle, group_rid,
+ num_names, rid_mem, names, name_types);
}
-/* Lookup alias membership given a rid */
+/* Globals for domain list stuff */
+
+struct winbindd_domain *domain_list = NULL;
-int winbindd_lookup_aliasmem(struct winbindd_domain *domain,
- uint32 alias_rid, uint32 *num_names,
- DOM_SID ***sids, char ***names,
- enum SID_NAME_USE **name_types)
+/* Given a domain name, return the struct winbindd domain info for it
+ if it is actually working. */
+
+struct winbindd_domain *find_domain_from_name(char *domain_name)
{
- /* Open sam handles */
- if (!domain_handles_open(domain)) return False;
+ struct winbindd_domain *tmp;
- return sam_query_aliasmem(domain->controller,
- &domain->sam_dom_handle, alias_rid, num_names,
- sids, names, name_types);
-}
+ /* Search through list */
-/* Globals for domain list stuff */
+ for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ if (strcmp(domain_name, tmp->name) == 0) {
-struct winbindd_domain *domain_list = NULL;
+ if (!tmp->got_domain_info) {
+ get_domain_info(tmp);
+ }
+
+ return tmp->got_domain_info ? tmp : NULL;
+ }
+ }
+
+ /* Not found */
+
+ return NULL;
+}
/* Given a domain name, return the struct winbindd domain info for it */
-struct winbindd_domain *find_domain_from_name(char *domain_name)
+struct winbindd_domain *find_domain_from_sid(DOM_SID *sid)
{
struct winbindd_domain *tmp;
/* Search through list */
for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
- if (strcmp(domain_name, tmp->name) == 0) {
+ if (sid_equal(sid, &tmp->sid)) {
if (!tmp->got_domain_info) return NULL;
return tmp;
}
@@ -544,14 +711,14 @@ static BOOL parse_id_list(char *paramstr, BOOL is_user)
/* Give a nicer error message if no parameters specified */
if (strequal(paramstr, "")) {
- DEBUG(0, ("winbid %s parameter missing\n", is_user ? "uid" : "gid"));
+ DEBUG(0, ("winbind %s parameter missing\n", is_user ? "uid" : "gid"));
return False;
}
/* Parse entry */
if (sscanf(paramstr, "%u-%u", &id_low, &id_high) != 2) {
- DEBUG(0, ("winbid %s parameter invalid\n",
+ DEBUG(0, ("winbind %s parameter invalid\n",
is_user ? "uid" : "gid"));
return False;
}
@@ -588,7 +755,7 @@ BOOL winbindd_param_init(void)
}
if (server_state.gid_low > server_state.gid_high) {
- DEBUG(0, ("gid range for invalid\n"));
+ DEBUG(0, ("gid range invalid\n"));
return False;
}
@@ -597,85 +764,83 @@ BOOL winbindd_param_init(void)
/* Convert a enum winbindd_cmd to a string */
-char *winbindd_cmd_to_string(enum winbindd_cmd cmd)
-{
- char *result;
+struct cmdstr_table {
+ enum winbindd_cmd cmd;
+ char *desc;
+};
- switch (cmd) {
+static struct cmdstr_table cmdstr_table[] = {
+
+ /* User functions */
- case WINBINDD_GETPWNAM_FROM_USER:
- result = "getpwnam from user";
- break;
-
- case WINBINDD_GETPWNAM_FROM_UID:
- result = "getpwnam from uid";
- break;
+ { WINBINDD_GETPWNAM_FROM_USER, "getpwnam from user" },
+ { WINBINDD_GETPWNAM_FROM_UID, "getpwnam from uid" },
+ { WINBINDD_SETPWENT, "setpwent" },
+ { WINBINDD_ENDPWENT, "endpwent" },
+ { WINBINDD_GETPWENT, "getpwent" },
+ { WINBINDD_GETGROUPS, "getgroups" },
- case WINBINDD_GETGRNAM_FROM_GROUP:
- result = "getgrnam from group";
- break;
+ /* Group functions */
- case WINBINDD_GETGRNAM_FROM_GID:
- result = "getgrnam from gid";
- break;
+ { WINBINDD_GETGRNAM_FROM_GROUP, "getgrnam from group" },
+ { WINBINDD_GETGRNAM_FROM_GID, "getgrnam from gid" },
+ { WINBINDD_SETGRENT, "setgrent" },
+ { WINBINDD_ENDGRENT, "endgrent" },
+ { WINBINDD_GETGRENT, "getgrent" },
- case WINBINDD_SETPWENT:
- result = "setpwent";
- break;
+ /* PAM auth functions */
- case WINBINDD_ENDPWENT:
- result = "endpwent";
- break;
+ { WINBINDD_PAM_AUTH, "pam auth" },
+ { WINBINDD_PAM_CHAUTHTOK, "pam chauthtok" },
- case WINBINDD_GETPWENT:
- result = "getpwent";
- break;
+ /* List things */
- case WINBINDD_SETGRENT:
- result = "setgrent";
- break;
+ { WINBINDD_LIST_USERS, "list users" },
+ { WINBINDD_LIST_GROUPS, "list groups" },
+ { WINBINDD_LIST_TRUSTDOM, "list trusted domains" },
- case WINBINDD_ENDGRENT:
- result = "endgrent";
- break;
+ /* SID related functions */
- case WINBINDD_GETGRENT:
- result = "getgrent";
- break;
+ { WINBINDD_LOOKUPSID, "lookup sid" },
+ { WINBINDD_LOOKUPNAME, "lookup name" },
- case WINBINDD_PAM_AUTH:
- result = "pam_auth";
- break;
+ /* S*RS related functions */
- default:
- result = "invalid command";
- break;
- }
+ { WINBINDD_SID_TO_UID, "sid to uid" },
+ { WINBINDD_SID_TO_GID, "sid to gid " },
+ { WINBINDD_GID_TO_SID, "gid to sid" },
+ { WINBINDD_UID_TO_SID, "uid to sid" },
- return result;
-};
+ /* Miscellaneous other stuff */
+ { WINBINDD_CHECK_MACHACC, "check machine acct pw" },
-/* parse a string of the form DOMAIN/user into a domain and a user */
-void parse_domain_user(char *domuser, fstring domain, fstring user)
+ /* End of list */
+
+ { WINBINDD_NUM_CMDS, NULL }
+};
+
+char *winbindd_cmd_to_string(enum winbindd_cmd cmd)
{
- char *p;
- char *sep = lp_winbind_separator();
- if (!sep) sep = "\\";
- p = strchr(domuser,*sep);
- if (!p) p = strchr(domuser,'\\');
- if (!p) {
- fstrcpy(domain,"");
- fstrcpy(user, domuser);
- return;
+ struct cmdstr_table *table = cmdstr_table;
+ char *result = NULL;
+
+ for(table = cmdstr_table; table->desc; table++) {
+ if (cmd == table->cmd) {
+ result = table->desc;
+ break;
+ }
}
- fstrcpy(user, p+1);
- fstrcpy(domain, domuser);
- domain[PTR_DIFF(p, domuser)] = 0;
-}
+ if (result == NULL) {
+ result = "invalid command";
+ }
+
+ return result;
+};
/* find the sequence number for a domain */
+
uint32 domain_sequence_number(char *domain_name)
{
struct winbindd_domain *domain;
@@ -685,6 +850,11 @@ uint32 domain_sequence_number(char *domain_name)
if (!domain) return DOM_SEQUENCE_NONE;
if (!samr_query_dom_info(&domain->sam_dom_handle, 2, &ctr)) {
+
+ /* If this fails, something bad has gone wrong */
+
+ winbindd_kill_connections(domain);
+
DEBUG(2,("domain sequence query failed\n"));
return DOM_SEQUENCE_NONE;
}
@@ -694,3 +864,57 @@ uint32 domain_sequence_number(char *domain_name)
return ctr.info.inf2.seq_num;
}
+
+/* Query display info for a domain. This returns enough information plus a
+ bit extra to give an overview of domain users for the User Manager
+ application. */
+
+uint32 winbindd_query_dispinfo(struct winbindd_domain *domain,
+ uint32 *start_ndx, uint16 info_level,
+ uint32 *num_entries, SAM_DISPINFO_CTR *ctr)
+{
+ uint32 status;
+
+ status = samr_query_dispinfo(&domain->sam_dom_handle, start_ndx,
+ info_level, num_entries, ctr);
+
+ return status;
+}
+
+/* Check if a domain is present in a comma-separated list of domains */
+
+BOOL check_domain_env(char *domain_env, char *domain)
+{
+ fstring name;
+ char *tmp = domain_env;
+
+ while(next_token(&tmp, name, ",", sizeof(fstring))) {
+ if (strequal(name, domain)) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+
+/* Parse a string of the form DOMAIN/user into a domain and a user */
+
+void parse_domain_user(char *domuser, fstring domain, fstring user)
+{
+ char *p;
+ char *sep = lp_winbind_separator();
+ if (!sep) sep = "\\";
+ p = strchr(domuser,*sep);
+ if (!p) p = strchr(domuser,'\\');
+ if (!p) {
+ fstrcpy(domain,"");
+ fstrcpy(user, domuser);
+ return;
+ }
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ strupper(domain);
+}