summaryrefslogtreecommitdiff
path: root/source3/nsswitch
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2005-06-08 22:10:34 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:57:08 -0500
commitfed660877c16562265327c6093ea645cf4176b5c (patch)
treee92ae1356542ba095d806bbe1093fa56fbc8ddcc /source3/nsswitch
parent66bb4f03c3466205488f72e4878e8801c5bbb295 (diff)
downloadsamba-fed660877c16562265327c6093ea645cf4176b5c.tar.gz
samba-fed660877c16562265327c6093ea645cf4176b5c.tar.bz2
samba-fed660877c16562265327c6093ea645cf4176b5c.zip
r7415: * big change -- volker's new async winbindd from trunk
(This used to be commit a0ac9a8ffd4af31a0ebc423b4acbb2f043d865b8)
Diffstat (limited to 'source3/nsswitch')
-rw-r--r--source3/nsswitch/wb_client.c26
-rw-r--r--source3/nsswitch/wbinfo.c83
-rw-r--r--source3/nsswitch/winbindd.c733
-rw-r--r--source3/nsswitch/winbindd.h83
-rw-r--r--source3/nsswitch/winbindd_ads.c166
-rw-r--r--source3/nsswitch/winbindd_async.c1403
-rw-r--r--source3/nsswitch/winbindd_cache.c260
-rw-r--r--source3/nsswitch/winbindd_cm.c970
-rw-r--r--source3/nsswitch/winbindd_dual.c445
-rw-r--r--source3/nsswitch/winbindd_group.c591
-rw-r--r--source3/nsswitch/winbindd_ldap.c646
-rw-r--r--source3/nsswitch/winbindd_misc.c400
-rw-r--r--source3/nsswitch/winbindd_nss.h61
-rw-r--r--source3/nsswitch/winbindd_pam.c418
-rw-r--r--source3/nsswitch/winbindd_passdb.c19
-rw-r--r--source3/nsswitch/winbindd_reconnect.c273
-rw-r--r--source3/nsswitch/winbindd_rpc.c669
-rw-r--r--source3/nsswitch/winbindd_sid.c697
-rw-r--r--source3/nsswitch/winbindd_user.c384
-rw-r--r--source3/nsswitch/winbindd_util.c600
20 files changed, 6290 insertions, 2637 deletions
diff --git a/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c
index 5005f72457..32ac4319a0 100644
--- a/source3/nsswitch/wb_client.c
+++ b/source3/nsswitch/wb_client.c
@@ -257,6 +257,32 @@ BOOL winbind_allocate_rid(uint32 *rid)
return True;
}
+BOOL winbind_allocate_rid_and_gid(uint32 *rid, gid_t *gid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_ALLOCATE_RID_AND_GID, &request,
+ &response);
+
+ if (result != NSS_STATUS_SUCCESS)
+ return False;
+
+ /* Copy out result */
+ *rid = response.data.rid_and_gid.rid;
+ *gid = response.data.rid_and_gid.gid;
+
+ return True;
+}
+
/* Fetch the list of groups a user is a member of from winbindd. This is
used by winbind_getgroups. */
diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c
index baa35d7cfb..8407bb1e3a 100644
--- a/source3/nsswitch/wbinfo.c
+++ b/source3/nsswitch/wbinfo.c
@@ -167,6 +167,32 @@ static BOOL wbinfo_get_usersids(char *user_sid)
return True;
}
+static BOOL wbinfo_get_userdomgroups(const char *user_sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ ZERO_STRUCT(response);
+
+ /* Send request */
+ fstrcpy(request.data.sid, user_sid);
+
+ result = winbindd_request(WINBINDD_GETUSERDOMGROUPS, &request,
+ &response);
+
+ if (result != NSS_STATUS_SUCCESS)
+ return False;
+
+ if (response.data.num_entries != 0)
+ printf("%s", (char *)response.extra_data);
+
+ SAFE_FREE(response.extra_data);
+
+ return True;
+}
+
+
/* Convert NetBIOS name to IP */
static BOOL wbinfo_wins_byname(char *name)
@@ -224,7 +250,6 @@ static BOOL wbinfo_wins_byip(char *ip)
static BOOL wbinfo_list_domains(void)
{
struct winbindd_response response;
- fstring name;
ZERO_STRUCT(response);
@@ -238,9 +263,19 @@ static BOOL wbinfo_list_domains(void)
if (response.extra_data) {
const char *extra_data = (char *)response.extra_data;
-
- while(next_token(&extra_data, name, ",", sizeof(fstring)))
+ fstring name;
+ char *p;
+
+ while(next_token(&extra_data, name, "\n", sizeof(fstring))) {
+ p = strchr(name, '\\');
+ if (p == 0) {
+ d_printf("Got invalid response: %s\n",
+ extra_data);
+ return False;
+ }
+ *p = 0;
d_printf("%s\n", name);
+ }
SAFE_FREE(response.extra_data);
}
@@ -316,6 +351,32 @@ static BOOL wbinfo_domain_info(const char *domain_name)
return True;
}
+/* Get a foreign DC's name */
+static BOOL wbinfo_getdcname(const char *domain_name)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.domain_name, domain_name);
+
+ /* Send request */
+
+ if (winbindd_request(WINBINDD_GETDCNAME, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ d_printf("Could not get dc name for %s\n", domain_name);
+ return False;
+ }
+
+ /* Display response */
+
+ d_printf("%s\n", response.data.dc_name);
+
+ return True;
+}
+
/* Check trust account password */
static BOOL wbinfo_check_secret(void)
@@ -889,6 +950,8 @@ enum {
OPT_GET_AUTH_USER,
OPT_DOMAIN_NAME,
OPT_SEQUENCE,
+ OPT_GETDCNAME,
+ OPT_USERDOMGROUPS,
OPT_USERSIDS
};
@@ -924,9 +987,13 @@ int main(int argc, char **argv)
{ "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
{ "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" },
{ "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" },
+ { "user-domgroups", 0, POPT_ARG_STRING, &string_arg,
+ OPT_USERDOMGROUPS, "Get user domain groups", "SID" },
{ "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" },
{ "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" },
{ "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" },
+ { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
+ "Get a DC name for a foreign domain", "domainname" },
{ "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
{ "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
{ "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
@@ -1079,6 +1146,13 @@ int main(int argc, char **argv)
goto done;
}
break;
+ case OPT_USERDOMGROUPS:
+ if (!wbinfo_get_userdomgroups(string_arg)) {
+ d_printf("Could not get user's domain groups "
+ "for user SID %s\n", string_arg);
+ goto done;
+ }
+ break;
case 'a': {
BOOL got_error = False;
@@ -1116,6 +1190,9 @@ int main(int argc, char **argv)
case OPT_GET_AUTH_USER:
wbinfo_get_auth_user();
break;
+ case OPT_GETDCNAME:
+ wbinfo_getdcname(string_arg);
+ break;
/* generic configuration options */
case OPT_DOMAIN_NAME:
break;
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index 81dbf327fc..f083dfe44a 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -6,6 +6,7 @@
Copyright (C) by Tim Potter 2000-2002
Copyright (C) Andrew Tridgell 2002
Copyright (C) Jelmer Vernooij 2003
+ Copyright (C) Volker Lendecke 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,6 +28,7 @@
BOOL opt_nocache = False;
BOOL opt_dual_daemon = True;
+static BOOL interactive = False;
extern BOOL override_logfile;
@@ -131,7 +133,6 @@ static void winbindd_status(void)
static void print_winbindd_status(void)
{
winbindd_status();
- winbindd_cm_status();
}
/* Flush client cache */
@@ -163,6 +164,17 @@ static void terminate(void)
pstr_sprintf(path, "%s/%s",
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
unlink(path);
+
+#if 0
+ if (interactive) {
+ TALLOC_CTX *mem_ctx = talloc_init("end_description");
+ char *description = talloc_describe_all(mem_ctx);
+
+ DEBUG(3, ("tallocs left:\n%s\n", description));
+ talloc_destroy(mem_ctx);
+ }
+#endif
+
exit(0);
}
@@ -190,14 +202,11 @@ static void sighup_handler(int signum)
sys_select_signal();
}
+static BOOL do_sigchld;
+
static void sigchld_handler(int signum)
{
- pid_t pid;
- int status;
-
- while ((pid = wait(&status)) != -1 || errno == EINTR) {
- continue; /* Reap children */
- }
+ do_sigchld = True;
sys_select_signal();
}
@@ -215,13 +224,7 @@ static void msg_shutdown(int msg_type, pid_t src, void *buf, size_t len)
terminate();
}
-struct dispatch_table {
- enum winbindd_cmd cmd;
- enum winbindd_result (*fn)(struct winbindd_cli_state *state);
- const char *winbindd_cmd_name;
-};
-
-static struct dispatch_table dispatch_table[] = {
+static struct winbindd_dispatch_table dispatch_table[] = {
/* User functions */
@@ -234,6 +237,8 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
{ WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
+ { WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups,
+ "GETUSERDOMGROUPS" },
/* Group functions */
@@ -247,14 +252,15 @@ static struct dispatch_table dispatch_table[] = {
/* PAM auth functions */
{ WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
- { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
+ { WINBINDD_PAM_AUTH_CRAP, winbindd_crap_auth, "AUTH_CRAP" },
{ WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
/* Enumeration functions */
{ WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
{ WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
- { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains, "LIST_TRUSTDOM" },
+ { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
+ "LIST_TRUSTDOM" },
{ WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
/* SID related functions */
@@ -266,20 +272,25 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" },
{ WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
- { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
{ WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
+ { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
{ WINBINDD_ALLOCATE_RID, winbindd_allocate_rid, "ALLOCATE_RID" },
+ { WINBINDD_ALLOCATE_RID_AND_GID, winbindd_allocate_rid_and_gid,
+ "ALLOCATE_RID_AND_GID" },
/* Miscellaneous */
{ WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
{ WINBINDD_PING, winbindd_ping, "PING" },
{ WINBINDD_INFO, winbindd_info, "INFO" },
- { WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" },
+ { WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
+ "INTERFACE_VERSION" },
{ WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
{ WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
- { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir, "WINBINDD_PRIV_PIPE_DIR" },
+ { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
+ "WINBINDD_PRIV_PIPE_DIR" },
+ { WINBINDD_GETDCNAME, winbindd_getdcname, "GETDCNAME" },
/* WINS functions */
@@ -293,7 +304,7 @@ static struct dispatch_table dispatch_table[] = {
static void process_request(struct winbindd_cli_state *state)
{
- struct dispatch_table *table = dispatch_table;
+ struct winbindd_dispatch_table *table = dispatch_table;
/* Free response data - we may be interrupted and receive another
command before being able to send this data off. */
@@ -302,26 +313,255 @@ static void process_request(struct winbindd_cli_state *state)
ZERO_STRUCT(state->response);
- state->response.result = WINBINDD_ERROR;
+ state->response.result = WINBINDD_PENDING;
state->response.length = sizeof(struct winbindd_response);
+ state->mem_ctx = talloc_init("winbind request");
+ if (state->mem_ctx == NULL)
+ return;
+
/* Process command */
for (table = dispatch_table; table->fn; table++) {
if (state->request.cmd == table->cmd) {
- DEBUG(10,("process_request: request fn %s\n", table->winbindd_cmd_name ));
+ DEBUG(10,("process_request: request fn %s\n",
+ table->winbindd_cmd_name ));
state->response.result = table->fn(state);
break;
}
}
- if (!table->fn)
- DEBUG(10,("process_request: unknown request fn number %d\n", (int)state->request.cmd ));
+ if (!table->fn) {
+ DEBUG(10,("process_request: unknown request fn number %d\n",
+ (int)state->request.cmd ));
+ state->response.result = WINBINDD_ERROR;
+ }
+}
+
+/*
+ * A list of file descriptors being monitored by select in the main processing
+ * loop. fd_event->handler is called whenever the socket is readable/writable.
+ */
+
+static struct fd_event *fd_events = NULL;
+
+void add_fd_event(struct fd_event *ev)
+{
+ struct fd_event *match;
+
+ /* only add unique fd_event structs */
+
+ for (match=fd_events; match; match=match->next ) {
+#ifdef DEVELOPER
+ SMB_ASSERT( match != ev );
+#else
+ if ( match == ev )
+ return;
+#endif
+ }
+
+ DLIST_ADD(fd_events, ev);
+}
+
+void remove_fd_event(struct fd_event *ev)
+{
+ DLIST_REMOVE(fd_events, ev);
+}
+
+/*
+ * Handler for fd_events to complete a read/write request, set up by
+ * setup_async_read/setup_async_write.
+ */
+
+static void rw_callback(struct fd_event *event, int flags)
+{
+ size_t todo;
+ ssize_t done = 0;
+
+ todo = event->length - event->done;
+
+ if (event->flags & EVENT_FD_WRITE) {
+ SMB_ASSERT(flags == EVENT_FD_WRITE);
+ done = sys_write(event->fd,
+ &((char *)event->data)[event->done],
+ todo);
+
+ if (done <= 0) {
+ event->flags = 0;
+ event->finished(event->private, False);
+ return;
+ }
+ }
+
+ if (event->flags & EVENT_FD_READ) {
+ SMB_ASSERT(flags == EVENT_FD_READ);
+ done = sys_read(event->fd, &((char *)event->data)[event->done],
+ todo);
- /* In case extra data pointer is NULL */
+ if (done <= 0) {
+ event->flags = 0;
+ event->finished(event->private, False);
+ return;
+ }
+ }
+
+ event->done += done;
+
+ if (event->done == event->length) {
+ event->flags = 0;
+ event->finished(event->private, True);
+ }
+}
+
+/*
+ * Request an async read/write on a fd_event structure. (*finished) is called
+ * when the request is completed or an error had occurred.
+ */
+
+void setup_async_read(struct fd_event *event, void *data, size_t length,
+ void (*finished)(void *private, BOOL success),
+ void *private)
+{
+ SMB_ASSERT(event->flags == 0);
+ event->data = data;
+ event->length = length;
+ event->done = 0;
+ event->handler = rw_callback;
+ event->finished = finished;
+ event->private = private;
+ event->flags = EVENT_FD_READ;
+}
+
+void setup_async_write(struct fd_event *event, void *data, size_t length,
+ void (*finished)(void *private, BOOL success),
+ void *private)
+{
+ SMB_ASSERT(event->flags == 0);
+ event->data = data;
+ event->length = length;
+ event->done = 0;
+ event->handler = rw_callback;
+ event->finished = finished;
+ event->private = private;
+ event->flags = EVENT_FD_WRITE;
+}
+
+/*
+ * This is the main event loop of winbind requests. It goes through a
+ * state-machine of 3 read/write requests, 4 if you have extra data to send.
+ *
+ * An idle winbind client has a read request of 4 bytes outstanding,
+ * finalizing function is request_len_recv, checking the length. request_recv
+ * then processes the packet. The processing function then at some point has
+ * to call request_finished which schedules sending the response.
+ */
+
+static void request_len_recv(void *private, BOOL success);
+static void request_recv(void *private, BOOL success);
+void request_finished(struct winbindd_cli_state *state);
+void request_finished_cont(void *private, BOOL success);
+static void response_main_sent(void *private, BOOL success);
+static void response_extra_sent(void *private, BOOL success);
+
+static void response_extra_sent(void *private, BOOL success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (state->mem_ctx != NULL) {
+ talloc_destroy(state->mem_ctx);
+ state->mem_ctx = NULL;
+ }
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ SAFE_FREE(state->response.extra_data);
+
+ setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
+ request_len_recv, state);
+}
+
+static void response_main_sent(void *private, BOOL success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ if (state->response.length == sizeof(state->response)) {
+ if (state->mem_ctx != NULL) {
+ talloc_destroy(state->mem_ctx);
+ state->mem_ctx = NULL;
+ }
+
+ setup_async_read(&state->fd_event, &state->request,
+ sizeof(uint32), request_len_recv, state);
+ return;
+ }
+
+ setup_async_write(&state->fd_event, state->response.extra_data,
+ state->response.length - sizeof(state->response),
+ response_extra_sent, state);
+}
+
+void request_finished(struct winbindd_cli_state *state)
+{
+ setup_async_write(&state->fd_event, &state->response,
+ sizeof(state->response), response_main_sent, state);
+}
+
+void request_finished_cont(void *private, BOOL success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success)
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+}
+
+static void request_recv(void *private, BOOL success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ process_request(state);
+
+ if (state->response.result != WINBINDD_PENDING)
+ request_finished(state);
+}
+
+static void request_len_recv(void *private, BOOL success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ if (*(uint32 *)(&state->request) != sizeof(state->request)) {
+ DEBUG(0,("process_loop: Invalid request size received: %d\n",
+ *(uint32 *)(&state->request)));
+ state->finished = True;
+ return;
+ }
- if (!state->response.extra_data)
- state->response.length = sizeof(struct winbindd_response);
+ setup_async_read(&state->fd_event, (uint32 *)(&state->request)+1,
+ sizeof(state->request) - sizeof(uint32),
+ request_recv, state);
}
/* Process a new connection by adding it to the client connection list */
@@ -348,16 +588,22 @@ static void new_connection(int listen_sock, BOOL privileged)
/* Create new connection structure */
- if ((state = SMB_MALLOC_P(struct winbindd_cli_state)) == NULL)
+ if ((state = TALLOC_ZERO_P(NULL, struct winbindd_cli_state)) == NULL)
return;
- ZERO_STRUCTP(state);
state->sock = sock;
state->last_access = time(NULL);
state->privileged = privileged;
+ state->fd_event.fd = state->sock;
+ state->fd_event.flags = 0;
+ add_fd_event(&state->fd_event);
+
+ setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
+ request_len_recv, state);
+
/* Add to connection list */
winbindd_add_client(state);
@@ -384,11 +630,18 @@ static void remove_client(struct winbindd_cli_state *state)
client was killed unexpectedly */
SAFE_FREE(state->response.extra_data);
+
+ if (state->mem_ctx != NULL) {
+ talloc_destroy(state->mem_ctx);
+ state->mem_ctx = NULL;
+ }
+
+ remove_fd_event(&state->fd_event);
/* Remove from list and free */
winbindd_remove_client(state);
- SAFE_FREE(state);
+ talloc_free(state);
}
}
@@ -403,7 +656,8 @@ static BOOL remove_idle_client(void)
for (state = winbindd_client_list(); state; state = state->next) {
if (state->read_buf_len == 0 && state->write_buf_len == 0 &&
- !state->getpwent_state && !state->getgrent_state) {
+ state->response.result != WINBINDD_PENDING &&
+ !state->getpwent_state && !state->getgrent_state) {
nidle++;
if (!last_access || state->last_access < last_access) {
last_access = state->last_access;
@@ -432,7 +686,7 @@ void winbind_process_packet(struct winbindd_cli_state *state)
state->request.null_term = '\0';
state->pid = state->request.pid;
-
+
process_request(state);
/* Update client state */
@@ -446,124 +700,6 @@ void winbind_process_packet(struct winbindd_cli_state *state)
}
}
-/* Read some data from a client connection */
-
-void winbind_client_read(struct winbindd_cli_state *state)
-{
- int n;
-
- /* Read data */
-
- n = sys_read(state->sock, state->read_buf_len +
- (char *)&state->request,
- sizeof(state->request) - state->read_buf_len);
-
- DEBUG(10,("client_read: read %d bytes. Need %ld more for a full request.\n", n, (unsigned long)(sizeof(state->request) - n - state->read_buf_len) ));
-
- /* Read failed, kill client */
-
- if (n == -1 || n == 0) {
- DEBUG(5,("read failed on sock %d, pid %lu: %s\n",
- state->sock, (unsigned long)state->pid,
- (n == -1) ? strerror(errno) : "EOF"));
-
- state->finished = True;
- return;
- }
-
- /* Update client state */
-
- state->read_buf_len += n;
- state->last_access = time(NULL);
-}
-
-/* Write some data to a client connection */
-
-static void client_write(struct winbindd_cli_state *state)
-{
- char *data;
- int num_written;
-
- /* Write some data */
- /*
- * The fancy calculation of data below allows us to handle the
- * case where write (sys_write) does not write all the data we
- * gave it. In that case, we will come back through here again
- * because of the loop above us, and we want to pick up where
- * we left off.
- */
-
- 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 = sys_write(state->sock, data, state->write_buf_len);
-
- DEBUG(10,("client_write: wrote %d bytes.\n", num_written ));
-
- /* Write failed, kill cilent */
-
- if (num_written == -1 || num_written == 0) {
-
- DEBUG(3,("write failed on sock %d, pid %lu: %s\n",
- state->sock, (unsigned long)state->pid,
- (num_written == -1) ? strerror(errno) : "EOF"));
-
- state->finished = True;
-
- SAFE_FREE(state->response.extra_data);
-
- return;
- }
-
- /* Update client state */
-
- state->write_buf_len -= num_written;
- state->last_access = time(NULL);
-
- /* 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->write_extra_data = False;
-
- DEBUG(10,("client_write: client_write: complete response written.\n"));
-
- } else if (state->response.length >
- sizeof(struct winbindd_response)) {
-
- /* Start writing extra data */
-
- state->write_buf_len =
- state->response.length -
- sizeof(struct winbindd_response);
-
- DEBUG(10,("client_write: need to write %d extra data bytes.\n", (int)state->write_buf_len));
-
- state->write_extra_data = True;
- }
- }
-}
-
/* Process incoming clients on listen_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
@@ -571,211 +707,182 @@ static void client_write(struct winbindd_cli_state *state)
static void process_loop(void)
{
- /* We'll be doing this a lot */
+ struct winbindd_cli_state *state;
+ struct fd_event *ev;
+ fd_set r_fds, w_fds;
+ int maxfd, listen_sock, listen_priv_sock, selret;
+ struct timeval timeout;
- while (1) {
- struct winbindd_cli_state *state;
- fd_set r_fds, w_fds;
- int maxfd, listen_sock, listen_priv_sock, selret;
- struct timeval timeout;
+ /* We'll be doing this a lot */
- again:
- /* Handle messages */
+ /* Handle messages */
- message_dispatch();
+ message_dispatch();
- /* refresh the trusted domain cache */
+ /* refresh the trusted domain cache */
- rescan_trusted_domains();
-
- /* Free up temporary memory */
+ rescan_trusted_domains();
- lp_talloc_free();
- main_loop_talloc_free();
+ /* Free up temporary memory */
- /* Initialise fd lists for select() */
+ lp_talloc_free();
+ main_loop_talloc_free();
- listen_sock = open_winbindd_socket();
- listen_priv_sock = open_winbindd_priv_socket();
-
- if (listen_sock == -1 || listen_priv_sock == -1) {
- perror("open_winbind_socket");
- exit(1);
- }
+ /* Initialise fd lists for select() */
- maxfd = MAX(listen_sock, listen_priv_sock);
+ listen_sock = open_winbindd_socket();
+ listen_priv_sock = open_winbindd_priv_socket();
- FD_ZERO(&r_fds);
- FD_ZERO(&w_fds);
- FD_SET(listen_sock, &r_fds);
- FD_SET(listen_priv_sock, &r_fds);
-
- timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
- timeout.tv_usec = 0;
-
- if (opt_dual_daemon) {
- maxfd = dual_select_setup(&w_fds, maxfd);
- }
-
- /* Set up client readers and writers */
+ if (listen_sock == -1 || listen_priv_sock == -1) {
+ perror("open_winbind_socket");
+ exit(1);
+ }
- state = winbindd_client_list();
+ maxfd = MAX(listen_sock, listen_priv_sock);
- while (state) {
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+ FD_SET(listen_sock, &r_fds);
+ FD_SET(listen_priv_sock, &r_fds);
- /* Dispose of client connection if it is marked as
- finished */
+ timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
+ timeout.tv_usec = 0;
- if (state->finished) {
- struct winbindd_cli_state *next = state->next;
+ if (opt_dual_daemon) {
+ maxfd = dual_select_setup(&w_fds, maxfd);
+ }
- remove_client(state);
- state = next;
- continue;
- }
+ /* Set up client readers and writers */
- /* Select requires we know the highest fd used */
+ state = winbindd_client_list();
- if (state->sock > maxfd)
- maxfd = state->sock;
+ while (state) {
- /* Add fd for reading */
+ struct winbindd_cli_state *next = state->next;
- if (state->read_buf_len != sizeof(state->request))
- FD_SET(state->sock, &r_fds);
+ /* Dispose of client connection if it is marked as
+ finished */
- /* Add fd for writing */
+ if (state->finished)
+ remove_client(state);
- if (state->write_buf_len)
- FD_SET(state->sock, &w_fds);
+ state = next;
+ }
- state = state->next;
+ for (ev = fd_events; ev; ev = ev->next) {
+ if (ev->flags & EVENT_FD_READ) {
+ FD_SET(ev->fd, &r_fds);
+ maxfd = MAX(ev->fd, maxfd);
+ }
+ if (ev->flags & EVENT_FD_WRITE) {
+ FD_SET(ev->fd, &w_fds);
+ maxfd = MAX(ev->fd, maxfd);
}
+ }
- /* Call select */
+ /* Call select */
- selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+ selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
- if (selret == 0)
- continue;
+ if (selret == 0)
+ goto no_fds_ready;
- 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 listen_sock readable */
+ /* Create a new connection if listen_sock readable */
- if (selret > 0) {
+ if (opt_dual_daemon) {
+ dual_select(&w_fds);
+ }
- if (opt_dual_daemon) {
- dual_select(&w_fds);
- }
+ ev = fd_events;
+ while (ev != NULL) {
+ struct fd_event *next = ev->next;
+ int flags = 0;
+ if (FD_ISSET(ev->fd, &r_fds))
+ flags |= EVENT_FD_READ;
+ if (FD_ISSET(ev->fd, &w_fds))
+ flags |= EVENT_FD_WRITE;
+ if (flags)
+ ev->handler(ev, flags);
+ ev = next;
+ }
- if (FD_ISSET(listen_sock, &r_fds)) {
- while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
- DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
- WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
- if (!remove_idle_client()) {
- DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
- WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
- break;
- }
- }
- /* new, non-privileged connection */
- new_connection(listen_sock, False);
+ if (FD_ISSET(listen_sock, &r_fds)) {
+ while (winbindd_num_clients() >
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+ DEBUG(5,("winbindd: Exceeding %d client "
+ "connections, removing idle "
+ "connection.\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ if (!remove_idle_client()) {
+ DEBUG(0,("winbindd: Exceeding %d "
+ "client connections, no idle "
+ "connection found\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ break;
}
+ }
+ /* new, non-privileged connection */
+ new_connection(listen_sock, False);
+ }
- if (FD_ISSET(listen_priv_sock, &r_fds)) {
- while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
- DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
- WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
- if (!remove_idle_client()) {
- DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
- WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
- break;
- }
- }
- /* new, privileged connection */
- new_connection(listen_priv_sock, True);
- }
-
- /* Process activity on client connections */
-
- for (state = winbindd_client_list(); state;
- state = state->next) {
-
- /* Data available for writing */
-
- if (FD_ISSET(state->sock, &w_fds))
- client_write(state);
- }
-
- for (state = winbindd_client_list(); state;
- state = state->next) {
-
- /* Data available for reading */
-
- if (FD_ISSET(state->sock, &r_fds)) {
-
- /* Read data */
-
- winbind_client_read(state);
-
- /*
- * If we have the start of a
- * packet, then check the
- * length field to make sure
- * the client's not talking
- * Mock Swedish.
- */
-
- if (state->read_buf_len >= sizeof(uint32)
- && *(uint32 *) &state->request != sizeof(state->request)) {
- DEBUG(0,("process_loop: Invalid request size from pid %lu: %d bytes sent, should be %ld\n",
- (unsigned long)state->request.pid, *(uint32 *) &state->request, (unsigned long)sizeof(state->request)));
- DEBUGADD(0, ("This usually means that you are running old wbinfo, pam_winbind or libnss_winbind clients\n"));
-
- remove_client(state);
- break;
- }
-
- /* A request packet might be
- complete */
-
- if (state->read_buf_len ==
- sizeof(state->request)) {
- winbind_process_packet(state);
- winbindd_demote_client(state);
- goto again;
- }
- }
+ if (FD_ISSET(listen_priv_sock, &r_fds)) {
+ while (winbindd_num_clients() >
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+ DEBUG(5,("winbindd: Exceeding %d client "
+ "connections, removing idle "
+ "connection.\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ if (!remove_idle_client()) {
+ DEBUG(0,("winbindd: Exceeding %d "
+ "client connections, no idle "
+ "connection found\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ break;
}
}
+ /* new, privileged connection */
+ new_connection(listen_priv_sock, True);
+ }
+
+ no_fds_ready:
#if 0
- winbindd_check_cache_size(time(NULL));
+ winbindd_check_cache_size(time(NULL));
#endif
- /* Check signal handling things */
+ /* Check signal handling things */
- if (do_sigterm)
- terminate();
+ if (do_sigterm)
+ terminate();
- if (do_sighup) {
+ if (do_sighup) {
- DEBUG(3, ("got SIGHUP\n"));
+ DEBUG(3, ("got SIGHUP\n"));
- msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0);
- do_sighup = False;
- }
+ msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0);
+ do_sighup = False;
+ }
+
+ if (do_sigusr2) {
+ print_winbindd_status();
+ do_sigusr2 = False;
+ }
- if (do_sigusr2) {
- print_winbindd_status();
- do_sigusr2 = False;
+ if (do_sigchld) {
+ pid_t pid;
+
+ do_sigchld = False;
+
+ while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
+ winbind_child_died(pid);
}
}
}
@@ -787,7 +894,6 @@ struct winbindd_state server_state; /* Server state information */
int main(int argc, char **argv)
{
pstring logfile;
- static BOOL interactive = False;
static BOOL Fork = True;
static BOOL log_stdout = False;
struct poptOption long_options[] = {
@@ -886,7 +992,7 @@ int main(int argc, char **argv)
if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) ||
(!idmap_init(lp_idmap_backend())) ) {
DEBUG(1, ("Could not init idmap -- netlogon proxy only\n"));
- idmap_proxyonly();
+ idmap_set_proxyonly();
}
/* Unblock all signals we are interested in as they may have been
@@ -948,9 +1054,12 @@ int main(int argc, char **argv)
init_domain_list();
+ init_idmap_child();
+
/* Loop waiting for requests */
- process_loop();
+ while (1)
+ process_loop();
trustdom_cache_shutdown();
diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h
index aed0c00c9d..c8d2ebf686 100644
--- a/source3/nsswitch/winbindd.h
+++ b/source3/nsswitch/winbindd.h
@@ -32,11 +32,25 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
-/* Client state structure */
+/* bits for fd_event.flags */
+#define EVENT_FD_READ 1
+#define EVENT_FD_WRITE 2
+
+struct fd_event {
+ struct fd_event *next, *prev;
+ int fd;
+ int flags; /* see EVENT_FD_* flags */
+ void (*handler)(struct fd_event *fde, int flags);
+ void *data;
+ size_t length, done;
+ void (*finished)(void *private, BOOL success);
+ void *private;
+};
struct winbindd_cli_state {
struct winbindd_cli_state *prev, *next; /* Linked list pointers */
int sock; /* Open socket from client */
+ struct fd_event fd_event;
pid_t pid; /* pid of client */
int read_buf_len, write_buf_len; /* Indexes in request/response */
BOOL finished; /* Can delete from list */
@@ -44,10 +58,13 @@ struct winbindd_cli_state {
time_t last_access; /* Time of last access (read or write) */
BOOL privileged; /* Is the client 'privileged' */
+ TALLOC_CTX *mem_ctx; /* memory per request */
struct winbindd_request request; /* Request from client */
struct winbindd_response response; /* Respose to client */
- BOOL getpwent_initialized; /* Has getpwent_state been initialized? */
- BOOL getgrent_initialized; /* Has getgrent_state been initialized? */
+ BOOL getpwent_initialized; /* Has getpwent_state been
+ * initialized? */
+ BOOL getgrent_initialized; /* Has getgrent_state been
+ * initialized? */
struct getent_state *getpwent_state; /* State for getpwent() */
struct getent_state *getgrent_state; /* State for getgrent() */
};
@@ -81,15 +98,56 @@ struct winbindd_state {
gid_t gid_low, gid_high; /* Range of gids to allocate */
};
+struct winbindd_dispatch_table {
+ enum winbindd_cmd cmd;
+ enum winbindd_result (*fn)(struct winbindd_cli_state *state);
+ const char *winbindd_cmd_name;
+};
+
extern struct winbindd_state server_state; /* Server information */
typedef struct {
char *acct_name;
char *full_name;
- DOM_SID *user_sid; /* NT user and primary group SIDs */
- DOM_SID *group_sid;
+ DOM_SID user_sid; /* NT user and primary group SIDs */
+ DOM_SID group_sid;
} WINBIND_USERINFO;
+/* Our connection to the DC */
+
+struct winbindd_cm_conn {
+ struct cli_state *cli;
+
+ struct rpc_pipe_client *samr_pipe;
+ POLICY_HND sam_connect_handle, sam_domain_handle;
+
+ struct rpc_pipe_client *lsa_pipe;
+ POLICY_HND lsa_policy;
+
+ /* Auth2 pipe is the pipe used to setup the netlogon schannel key
+ * using rpccli_net_auth2. It needs to be kept open. */
+
+ struct rpc_pipe_client *netlogon_auth2_pipe;
+ unsigned char sess_key[16]; /* Current session key. */
+ DOM_CRED clnt_cred; /* Client NETLOGON credential. */
+ struct rpc_pipe_client *netlogon_pipe;
+};
+
+struct winbindd_async_request;
+
+/* Async child */
+
+struct winbindd_child {
+ struct winbindd_child *next, *prev;
+
+ pid_t pid;
+ struct winbindd_domain *domain;
+ pstring logfilename;
+
+ struct fd_event event;
+ struct winbindd_async_request *requests;
+};
+
/* Structures to hold per domain information */
struct winbindd_domain {
@@ -123,6 +181,14 @@ struct winbindd_domain {
uint32 sequence_number;
NTSTATUS last_status;
+ /* The smb connection */
+
+ struct winbindd_cm_conn conn;
+
+ /* The child pid we're talking to */
+
+ struct winbindd_child child;
+
/* Linked list info */
struct winbindd_domain *prev, *next;
@@ -181,13 +247,14 @@ struct winbindd_methods {
NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,
- uint32 *num_groups, DOM_SID ***user_gids);
+ uint32 *num_groups, DOM_SID **user_gids);
/* Lookup all aliases that the sids delivered are member of. This is
* to implement 'domain local groups' correctly */
NTSTATUS (*lookup_useraliases)(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 num_sids, DOM_SID **sids,
+ uint32 num_sids,
+ const DOM_SID *sids,
uint32 *num_aliases,
uint32 **alias_rids);
@@ -196,7 +263,7 @@ struct winbindd_methods {
TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid,
uint32 *num_names,
- DOM_SID ***sid_mem, char ***names,
+ DOM_SID **sid_mem, char ***names,
uint32 **name_types);
/* return the current global sequence number */
diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c
index 5f23e755d4..0f4dee4f4a 100644
--- a/source3/nsswitch/winbindd_ads.c
+++ b/source3/nsswitch/winbindd_ads.c
@@ -27,8 +27,6 @@
#ifdef HAVE_ADS
-extern struct winbindd_methods msrpc_methods, cache_methods;
-
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -78,6 +76,7 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
status = ads_connect(ads);
if (!ADS_ERR_OK(status) || !ads->config.realm) {
+ extern struct winbindd_methods msrpc_methods, cache_methods;
DEBUG(1,("ads_connect for domain %s failed: %s\n",
domain->name, ads_errstr(status)));
ads_destroy(&ads);
@@ -157,9 +156,6 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
char *name, *gecos;
- DOM_SID sid;
- DOM_SID *sid2;
- DOM_SID *group_sid;
uint32 group;
uint32 atype;
@@ -171,7 +167,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
name = ads_pull_username(ads, mem_ctx, msg);
gecos = ads_pull_string(ads, mem_ctx, msg, "name");
- if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
+ if (!ads_pull_sid(ads, msg, "objectSid",
+ &(*info)[i].user_sid)) {
DEBUG(1,("No sid for %s !?\n", name));
continue;
}
@@ -180,20 +177,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
continue;
}
- sid2 = TALLOC_P(mem_ctx, DOM_SID);
- if (!sid2) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- sid_copy(sid2, &sid);
-
- group_sid = rid_to_talloced_sid(domain, mem_ctx, group);
-
(*info)[i].acct_name = name;
(*info)[i].full_name = gecos;
- (*info)[i].user_sid = sid2;
- (*info)[i].group_sid = group_sid;
+ sid_compose(&(*info)[i].group_sid, &domain->sid, group);
i++;
}
@@ -386,8 +372,6 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
char *sidstr;
uint32 group_rid;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- DOM_SID *sid2;
- fstring sid_string;
DEBUG(3,("ads: query_user\n"));
@@ -404,13 +388,15 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
free(ldap_exp);
free(sidstr);
if (!ADS_ERR_OK(rc) || !msg) {
- DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc)));
+ DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
+ sid_string_static(sid), ads_errstr(rc)));
goto done;
}
count = ads_count_replies(ads, msg);
if (count != 1) {
- DEBUG(1,("query_user(sid=%s): Not found\n", sid_to_string(sid_string, sid)));
+ DEBUG(1,("query_user(sid=%s): Not found\n",
+ sid_string_static(sid)));
goto done;
}
@@ -418,20 +404,13 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
- DEBUG(1,("No primary group for %s !?\n", sid_to_string(sid_string, sid)));
- goto done;
- }
-
- sid2 = TALLOC_P(mem_ctx, DOM_SID);
- if (!sid2) {
- status = NT_STATUS_NO_MEMORY;
+ DEBUG(1,("No primary group for %s !?\n",
+ sid_string_static(sid)));
goto done;
}
- sid_copy(sid2, sid);
-
- info->user_sid = sid2;
- info->group_sid = rid_to_talloced_sid(domain, mem_ctx, group_rid);
+ sid_copy(&info->user_sid, sid);
+ sid_compose(&info->group_sid, &domain->sid, group_rid);
status = NT_STATUS_OK;
@@ -449,7 +428,7 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const char *user_dn,
DOM_SID *primary_group,
- uint32 *num_groups, DOM_SID ***user_gids)
+ uint32 *num_groups, DOM_SID **user_sids)
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -502,34 +481,24 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
goto done;
}
- (*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1);
- (*user_gids)[0] = primary_group;
-
- *num_groups = 1;
-
- for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ *user_sids = NULL;
+ *num_groups = 0;
+
+ add_sid_to_array(mem_ctx, primary_group, user_sids, num_groups);
+
+ for (msg = ads_first_entry(ads, res); msg;
+ msg = ads_next_entry(ads, msg)) {
DOM_SID group_sid;
if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
DEBUG(1,("No sid for this group ?!?\n"));
continue;
}
-
- if (sid_equal(&group_sid, primary_group)) continue;
-
- (*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID);
- if (!(*user_gids)[*num_groups]) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
- sid_copy((*user_gids)[*num_groups], &group_sid);
-
- (*num_groups)++;
-
+ add_sid_to_array(mem_ctx, &group_sid, user_sids, num_groups);
}
- status = NT_STATUS_OK;
+ status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
DEBUG(3,("ads lookup_usergroups (alt) for dn=%s\n", user_dn));
done:
@@ -543,7 +512,7 @@ done:
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *sid,
- uint32 *num_groups, DOM_SID ***user_gids)
+ uint32 *num_groups, DOM_SID **user_sids)
{
ADS_STRUCT *ads = NULL;
const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
@@ -553,7 +522,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
char *user_dn;
DOM_SID *sids;
int i;
- DOM_SID *primary_group;
+ DOM_SID primary_group;
uint32 primary_group_rid;
fstring sid_string;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -596,7 +565,8 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
goto done;
}
- primary_group = rid_to_talloced_sid(domain, mem_ctx, primary_group_rid);
+ sid_copy(&primary_group, &domain->sid);
+ sid_append_rid(&primary_group, primary_group_rid);
count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
@@ -607,30 +577,23 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
unless we are talking to a buggy Win2k server */
if (count == 0) {
return lookup_usergroups_alt(domain, mem_ctx, user_dn,
- primary_group,
- num_groups, user_gids);
+ &primary_group,
+ num_groups, user_sids);
}
- (*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1);
- (*user_gids)[0] = primary_group;
-
- *num_groups = 1;
+ *user_sids = NULL;
+ *num_groups = 0;
+
+ add_sid_to_array(mem_ctx, &primary_group, user_sids, num_groups);
- for (i=0;i<count;i++) {
- if (sid_equal(&sids[i], primary_group)) continue;
-
- (*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID);
- if (!(*user_gids)[*num_groups]) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
+ for (i=0;i<count;i++)
+ add_sid_to_array_unique(mem_ctx, &sids[i],
+ user_sids, num_groups);
- sid_copy((*user_gids)[*num_groups], &sids[i]);
- (*num_groups)++;
- }
+ status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
- status = NT_STATUS_OK;
- DEBUG(3,("ads lookup_usergroups for sid=%s\n", sid_to_string(sid_string, sid)));
+ DEBUG(3,("ads lookup_usergroups for sid=%s\n",
+ sid_to_string(sid_string, sid)));
done:
return status;
}
@@ -641,7 +604,7 @@ done:
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names,
- DOM_SID ***sid_mem, char ***names,
+ DOM_SID **sid_mem, char ***names,
uint32 **name_types)
{
ADS_STATUS rc;
@@ -652,8 +615,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
char *sidstr;
char **members;
- int i;
- size_t num_members;
+ int i, num_members;
fstring sid_string;
BOOL more_values;
const char **attrs;
@@ -753,7 +715,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
the problem is that the members are in the form of distinguised names
*/
- (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, num_members);
+ (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
(*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
(*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
@@ -765,12 +727,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &sid)) {
(*names)[*num_names] = name;
(*name_types)[*num_names] = name_type;
- (*sid_mem)[*num_names] = TALLOC_P(mem_ctx, DOM_SID);
- if (!(*sid_mem)[*num_names]) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
- sid_copy((*sid_mem)[*num_names], &sid);
+ sid_copy(&(*sid_mem)[*num_names], &sid);
(*num_names)++;
}
}
@@ -827,9 +784,9 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
struct ds_domain_trust *domains = NULL;
int count = 0;
int i;
- struct cli_state *cli = NULL;
/* i think we only need our forest and downlevel trusted domains */
uint32 flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND;
+ struct rpc_pipe_client *cli;
DEBUG(3,("ads: trusted_domains\n"));
@@ -837,16 +794,27 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
*alt_names = NULL;
*names = NULL;
*dom_sids = NULL;
-
- if ( !NT_STATUS_IS_OK(result = cm_fresh_connection(domain, PI_NETLOGON, &cli)) ) {
- DEBUG(5, ("trusted_domains: Could not open a connection to %s for PIPE_NETLOGON (%s)\n",
+
+ {
+ unsigned char *session_key;
+ DOM_CRED *creds;
+
+ result = cm_connect_netlogon(domain, mem_ctx, &cli,
+ &session_key, &creds);
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("trusted_domains: Could not open a connection to %s "
+ "for PIPE_NETLOGON (%s)\n",
domain->name, nt_errstr(result)));
return NT_STATUS_UNSUCCESSFUL;
}
if ( NT_STATUS_IS_OK(result) )
- result = cli_ds_enum_domain_trusts( cli, mem_ctx, cli->desthost,
- flags, &domains, (unsigned int *)&count );
+ result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
+ cli->cli->desthost,
+ flags, &domains,
+ (unsigned int *)&count);
if ( NT_STATUS_IS_OK(result) && count) {
@@ -854,20 +822,17 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
DEBUG(0, ("trusted_domains: out of memory\n"));
- result = NT_STATUS_NO_MEMORY;
- goto done;
+ return NT_STATUS_NO_MEMORY;
}
if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
DEBUG(0, ("trusted_domains: out of memory\n"));
- result = NT_STATUS_NO_MEMORY;
- goto done;
+ return NT_STATUS_NO_MEMORY;
}
if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) {
DEBUG(0, ("trusted_domains: out of memory\n"));
- result = NT_STATUS_NO_MEMORY;
- goto done;
+ return NT_STATUS_NO_MEMORY;
}
/* Copy across names and sids */
@@ -882,13 +847,6 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
*num_domains = count;
}
-done:
-
- /* remove connection; This is a special case to the \NETLOGON pipe */
-
- if ( cli )
- cli_shutdown( cli );
-
return result;
}
diff --git a/source3/nsswitch/winbindd_async.c b/source3/nsswitch/winbindd_async.c
new file mode 100644
index 0000000000..9ac2acafd0
--- /dev/null
+++ b/source3/nsswitch/winbindd_async.c
@@ -0,0 +1,1403 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Async helpers for blocking functions
+
+ Copyright (C) Volker Lendecke 2005
+
+ The helpers always consist of three functions:
+
+ * A request setup function that takes the necessary parameters together
+ with a continuation function that is to be called upon completion
+
+ * A private continuation function that is internal only. This is to be
+ called by the lower-level functions in do_async(). Its only task is to
+ properly call the continuation function named above.
+
+ * A worker function that is called inside the appropriate child process.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+struct do_async_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ void (*cont)(TALLOC_CTX *mem_ctx,
+ BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private);
+ void *c, *private;
+};
+
+static void do_async_recv(void *private, BOOL success)
+{
+ struct do_async_state *state =
+ talloc_get_type_abort(private, struct do_async_state);
+
+ state->cont(state->mem_ctx, success, &state->response,
+ state->c, state->private);
+}
+
+static void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+ const struct winbindd_request *request,
+ void (*cont)(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private),
+ void *c, void *private)
+{
+ struct do_async_state *state;
+
+ state = TALLOC_P(mem_ctx, struct do_async_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(mem_ctx, False, NULL, c, private);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->request = *request;
+ state->request.length = sizeof(state->request);
+ state->cont = cont;
+ state->c = c;
+ state->private = private;
+
+ async_request(mem_ctx, child, &state->request,
+ &state->response, do_async_recv, state);
+}
+
+static void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ const struct winbindd_request *request,
+ void (*cont)(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private),
+ void *c, void *private)
+{
+ struct do_async_state *state;
+
+ state = TALLOC_P(mem_ctx, struct do_async_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(mem_ctx, False, NULL, c, private);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->request = *request;
+ state->request.length = sizeof(state->request);
+ state->cont = cont;
+ state->c = c;
+ state->private = private;
+
+ async_domain_request(mem_ctx, domain, &state->request,
+ &state->response, do_async_recv, state);
+}
+
+static void idmap_set_mapping_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger idmap_set_mapping\n"));
+ cont(private, False);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("idmap_set_mapping returned an error\n"));
+ cont(private, False);
+ return;
+ }
+
+ cont(private, True);
+}
+
+void idmap_set_mapping_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ unid_t id, int id_type,
+ void (*cont)(void *private, BOOL success),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_IDMAPSET;
+ if (id_type == ID_USERID)
+ request.data.dual_idmapset.uid = id.uid;
+ else
+ request.data.dual_idmapset.gid = id.gid;
+ request.data.dual_idmapset.type = id_type;
+ sid_to_string(request.data.dual_idmapset.sid, sid);
+
+ do_async(mem_ctx, idmap_child(), &request, idmap_set_mapping_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_idmapset(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ unid_t id;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: dual_idmapset\n", (unsigned long)state->pid));
+
+ if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid))
+ return WINBINDD_ERROR;
+
+ if (state->request.data.dual_idmapset.type == ID_USERID)
+ id.uid = state->request.data.dual_idmapset.uid;
+ else
+ id.gid = state->request.data.dual_idmapset.gid;
+
+ result = idmap_set_mapping(&sid, id,
+ state->request.data.dual_idmapset.type);
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private);
+
+void idmap_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc,
+ void (*cont)(void *private, BOOL success, uid_t uid),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_SID2UID;
+ sid_to_string(request.data.dual_sid2id.sid, sid);
+ request.data.dual_sid2id.alloc = alloc;
+ do_async(mem_ctx, idmap_child(), &request, idmap_sid2uid_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
+ state->request.data.dual_sid2id.sid));
+
+ if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.dual_sid2id.sid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Find uid for this sid and return it, possibly ask the slow remote
+ * idmap */
+
+ result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
+ state->request.data.dual_sid2id.alloc ?
+ 0 : ID_QUERY_ONLY);
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, uid_t uid) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger sid2uid\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("sid2uid returned an error\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ cont(private, True, response->data.uid);
+}
+
+static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private);
+
+void winbindd_uid2name_async(TALLOC_CTX *mem_ctx, uid_t uid,
+ void (*cont)(void *private, BOOL success,
+ const char *name),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_UID2NAME;
+ request.data.uid = uid;
+ do_async(mem_ctx, idmap_child(), &request, uid2name_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_uid2name(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct passwd *pw;
+
+ DEBUG(3, ("[%5lu]: uid2name %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.uid));
+
+ pw = getpwuid(state->request.data.uid);
+ if (pw == NULL) {
+ DEBUG(5, ("User %lu not found\n",
+ (unsigned long)state->request.data.uid));
+ return WINBINDD_ERROR;
+ }
+
+ fstrcpy(state->response.data.name.name, pw->pw_name);
+ return WINBINDD_OK;
+}
+
+static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, const char *name) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger uid2name\n"));
+ cont(private, False, NULL);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("uid2name returned an error\n"));
+ cont(private, False, NULL);
+ return;
+ }
+
+ cont(private, True, response->data.name.name);
+}
+
+static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private);
+
+static void winbindd_name2uid_async(TALLOC_CTX *mem_ctx, const char *name,
+ void (*cont)(void *private, BOOL success,
+ uid_t uid),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_NAME2UID;
+ fstrcpy(request.data.username, name);
+ do_async(mem_ctx, idmap_child(), &request, name2uid_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_name2uid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct passwd *pw;
+
+ /* Ensure null termination */
+ state->request.data.username
+ [sizeof(state->request.data.username)-1] = '\0';
+
+ DEBUG(3, ("[%5lu]: name2uid %s\n", (unsigned long)state->pid,
+ state->request.data.username));
+
+ pw = getpwnam(state->request.data.username);
+ if (pw == NULL) {
+ return WINBINDD_ERROR;
+ }
+
+ state->response.data.uid = pw->pw_uid;
+ return WINBINDD_OK;
+}
+
+static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, uid_t uid) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger name2uid\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("name2uid returned an error\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ cont(private, True, response->data.uid);
+}
+
+static void idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private);
+
+void idmap_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc,
+ void (*cont)(void *private, BOOL success, gid_t gid),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_SID2GID;
+ sid_to_string(request.data.dual_sid2id.sid, sid);
+ request.data.dual_sid2id.alloc = alloc;
+ do_async(mem_ctx, idmap_child(), &request, idmap_sid2gid_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
+ state->request.data.dual_sid2id.sid));
+
+ if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.dual_sid2id.sid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Find gid for this sid and return it, possibly ask the slow remote
+ * idmap */
+
+ result = idmap_sid_to_gid(&sid, &(state->response.data.gid),
+ state->request.data.dual_sid2id.alloc ?
+ 0 : ID_QUERY_ONLY);
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, gid_t gid) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger sid2gid\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("sid2gid returned an error\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ cont(private, True, response->data.gid);
+}
+
+static void gid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, const char *name) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger gid2name\n"));
+ cont(private, False, NULL);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("gid2name returned an error\n"));
+ cont(private, False, NULL);
+ return;
+ }
+
+ cont(private, True, response->data.name.name);
+}
+
+void winbindd_gid2name_async(TALLOC_CTX *mem_ctx, gid_t gid,
+ void (*cont)(void *private, BOOL success,
+ const char *name),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_GID2NAME;
+ request.data.gid = gid;
+ do_async(mem_ctx, idmap_child(), &request, gid2name_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_gid2name(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct group *gr;
+
+ DEBUG(3, ("[%5lu]: gid2name %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.gid));
+
+ gr = getgrgid(state->request.data.gid);
+ if (gr == NULL)
+ return WINBINDD_ERROR;
+
+ fstrcpy(state->response.data.name.name, gr->gr_name);
+ return WINBINDD_OK;
+}
+
+static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private);
+
+static void winbindd_name2gid_async(TALLOC_CTX *mem_ctx, const char *name,
+ void (*cont)(void *private, BOOL success,
+ gid_t gid),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_NAME2GID;
+ fstrcpy(request.data.groupname, name);
+ do_async(mem_ctx, idmap_child(), &request, name2gid_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_name2gid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct group *gr;
+
+ /* Ensure null termination */
+ state->request.data.groupname
+ [sizeof(state->request.data.groupname)-1] = '\0';
+
+ DEBUG(3, ("[%5lu]: name2gid %s\n", (unsigned long)state->pid,
+ state->request.data.groupname));
+
+ gr = getgrnam(state->request.data.groupname);
+ if (gr == NULL) {
+ return WINBINDD_ERROR;
+ }
+
+ state->response.data.gid = gr->gr_gid;
+ return WINBINDD_OK;
+}
+
+static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, gid_t gid) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger name2gid\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("name2gid returned an error\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ cont(private, True, response->data.gid);
+}
+
+
+static void lookupsid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, const char *dom_name,
+ const char *name, enum SID_NAME_USE type) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger lookupsid\n"));
+ cont(private, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("lookupsid returned an error\n"));
+ cont(private, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ cont(private, True, response->data.name.dom_name,
+ response->data.name.name, response->data.name.type);
+}
+
+void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private, BOOL success,
+ const char *dom_name,
+ const char *name,
+ enum SID_NAME_USE type),
+ void *private)
+{
+ struct winbindd_domain *domain;
+ struct winbindd_request request;
+
+ domain = find_lookup_domain_from_sid(sid);
+ if (domain == NULL) {
+ DEBUG(5, ("Could not find domain for sid %s\n",
+ sid_string_static(sid)));
+ cont(private, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_LOOKUPSID;
+ fstrcpy(request.data.sid, sid_string_static(sid));
+
+ do_async_domain(mem_ctx, domain, &request, lookupsid_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ enum SID_NAME_USE type;
+ DOM_SID sid;
+ fstring name;
+ fstring dom_name;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
+
+ /* Lookup sid from PDC using lsa_lookup_sids() */
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(5, ("%s not a SID\n", state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Lookup the sid */
+
+ if (!winbindd_lookup_name_by_sid(state->mem_ctx, &sid, dom_name, name,
+ &type)) {
+ return WINBINDD_ERROR;
+ }
+
+ fstrcpy(state->response.data.name.dom_name, dom_name);
+ fstrcpy(state->response.data.name.name, name);
+ state->response.data.name.type = type;
+
+ return WINBINDD_OK;
+}
+
+static void lookupname_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, const DOM_SID *sid,
+ enum SID_NAME_USE type) = c;
+ DOM_SID sid;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger lookup_name\n"));
+ cont(private, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("lookup_name returned an error\n"));
+ cont(private, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (!string_to_sid(&sid, response->data.sid.sid)) {
+ DEBUG(0, ("Could not convert string %s to sid\n",
+ response->data.sid.sid));
+ cont(private, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ cont(private, True, &sid, response->data.sid.type);
+}
+
+void winbindd_lookupname_async(TALLOC_CTX *mem_ctx, const char *dom_name,
+ const char *name,
+ void (*cont)(void *private, BOOL success,
+ const DOM_SID *sid,
+ enum SID_NAME_USE type),
+ void *private)
+{
+ struct winbindd_request request;
+ struct winbindd_domain *domain;
+
+ domain = find_lookup_domain_from_name(dom_name);
+
+ if (domain == NULL) {
+ DEBUG(5, ("Could not find domain for name %s\n", dom_name));
+ cont(private, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_LOOKUPNAME;
+ fstrcpy(request.data.name.dom_name, dom_name);
+ fstrcpy(request.data.name.name, name);
+
+ do_async_domain(mem_ctx, domain, &request, lookupname_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ enum SID_NAME_USE type;
+ char *name_domain, *name_user;
+ DOM_SID sid;
+ char *p;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.name.dom_name)-1]='\0';
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.name.name)-1]='\0';
+
+ /* cope with the name being a fully qualified name */
+ p = strstr(state->request.data.name.name, lp_winbind_separator());
+ if (p) {
+ *p = 0;
+ name_domain = state->request.data.name.name;
+ name_user = p+1;
+ } else {
+ name_domain = state->request.data.name.dom_name;
+ name_user = state->request.data.name.name;
+ }
+
+ DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
+ name_domain, lp_winbind_separator(), name_user));
+
+ /* Lookup name from PDC using lsa_lookup_names() */
+ if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, name_domain,
+ name_user, &sid, &type)) {
+ return WINBINDD_ERROR;
+ }
+
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = type;
+
+ return WINBINDD_OK;
+}
+
+static BOOL print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
+ int num_sids, char **result)
+{
+ int i;
+ size_t buflen = 0;
+ ssize_t len = 0;
+
+ *result = NULL;
+ for (i=0; i<num_sids; i++) {
+ sprintf_append(mem_ctx, result, &len, &buflen,
+ "%s\n", sid_string_static(&sids[i]));
+ }
+
+ if ((num_sids != 0) && (*result == NULL)) {
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr,
+ DOM_SID **sids, int *num_sids)
+{
+ char *p, *q;
+
+ p = sidstr;
+ if (p == NULL)
+ return True;
+
+ while (p[0] != '\0') {
+ DOM_SID sid;
+ q = strchr(p, '\n');
+ if (q == NULL) {
+ DEBUG(0, ("Got invalid sidstr: %s\n", p));
+ return False;
+ }
+ *q = '\0';
+ q += 1;
+ if (!string_to_sid(&sid, p)) {
+ DEBUG(0, ("Could not parse sid %s\n", p));
+ return False;
+ }
+ add_sid_to_array(mem_ctx, &sid, sids, num_sids);
+ p = q;
+ }
+ return True;
+}
+
+static void getsidaliases_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ,
+ DOM_SID *aliases, int num_aliases) = c;
+ char *aliases_str;
+ DOM_SID *sids = NULL;
+ int num_sids = 0;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger getsidaliases\n"));
+ cont(private, success, NULL, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("getsidaliases returned an error\n"));
+ cont(private, False, NULL, 0);
+ return;
+ }
+
+ aliases_str = response->extra_data;
+
+ if (aliases_str == NULL) {
+ DEBUG(10, ("getsidaliases return 0 SIDs\n"));
+ cont(private, True, NULL, 0);
+ return;
+ }
+
+ if (!parse_sidlist(mem_ctx, aliases_str, &sids, &num_sids)) {
+ DEBUG(0, ("Could not parse sids\n"));
+ cont(private, False, NULL, 0);
+ return;
+ }
+
+ SAFE_FREE(response->extra_data);
+
+ cont(private, True, sids, num_sids);
+}
+
+void winbindd_getsidaliases_async(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sids, int num_sids,
+ void (*cont)(void *private,
+ BOOL success,
+ const DOM_SID *aliases,
+ int num_aliases),
+ void *private)
+{
+ struct winbindd_request request;
+ char *sidstr = NULL;
+ char *keystr;
+
+ if (num_sids == 0) {
+ cont(private, True, NULL, 0);
+ return;
+ }
+
+ if (!print_sidlist(mem_ctx, sids, num_sids, &sidstr)) {
+ cont(private, False, NULL, 0);
+ return;
+ }
+
+ keystr = cache_store_request_data(mem_ctx, sidstr);
+ if (keystr == NULL) {
+ cont(private, False, NULL, 0);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_GETSIDALIASES;
+ fstrcpy(request.domain_name, domain->name);
+ fstrcpy(request.data.dual_sidaliases.cache_key, keystr);
+
+ do_async_domain(mem_ctx, domain, &request, getsidaliases_recv,
+ cont, private);
+}
+
+enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID *sids = NULL;
+ int num_sids = 0;
+ char *key = state->request.data.dual_sidaliases.cache_key;
+ char *sidstr;
+ int i, num_aliases;
+ uint32 *alias_rids;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
+
+ /* Ensure null termination */
+ state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
+ state->request.data.dual_sidaliases.cache_key
+ [sizeof(state->request.data.dual_sidaliases.cache_key)-1]='\0';
+
+ sidstr = cache_retrieve_request_data(state->mem_ctx, key);
+ if (sidstr == NULL)
+ sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
+
+ DEBUG(10, ("Sidlist: %s\n", sidstr));
+
+ if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
+ DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
+ return WINBINDD_ERROR;
+ }
+
+ num_aliases = 0;
+ alias_rids = NULL;
+
+ result = domain->methods->lookup_useraliases(domain,
+ state->mem_ctx,
+ num_sids, sids,
+ &num_aliases,
+ &alias_rids);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("Could not lookup_useraliases: %s\n",
+ nt_errstr(result)));
+ return WINBINDD_ERROR;
+ }
+
+ num_sids = 0;
+ sids = NULL;
+
+ DEBUG(10, ("Got %d aliases\n", num_aliases));
+
+ for (i=0; i<num_aliases; i++) {
+ DOM_SID sid;
+ DEBUGADD(10, (" rid %d\n", alias_rids[i]));
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, alias_rids[i]);
+ add_sid_to_array(state->mem_ctx, &sid, &sids, &num_sids);
+ }
+
+ if (!print_sidlist(NULL, sids, num_sids,
+ (char **)&state->response.extra_data)) {
+ DEBUG(0, ("Could not print_sidlist\n"));
+ return WINBINDD_ERROR;
+ }
+
+ if (state->response.extra_data != NULL) {
+ DEBUG(10, ("aliases_list: %s\n",
+ (char *)state->response.extra_data));
+ state->response.length += strlen(state->response.extra_data)+1;
+ }
+
+ return WINBINDD_OK;
+}
+
+struct gettoken_state {
+ TALLOC_CTX *mem_ctx;
+ DOM_SID user_sid;
+ struct winbindd_domain *alias_domain;
+ struct winbindd_domain *builtin_domain;
+ DOM_SID *sids;
+ int num_sids;
+ void (*cont)(void *private, BOOL success, DOM_SID *sids, int num_sids);
+ void *private;
+};
+
+static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private);
+static void gettoken_recvaliases(void *private, BOOL success,
+ const DOM_SID *aliases,
+ int num_aliases);
+
+
+void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
+ void (*cont)(void *private, BOOL success,
+ DOM_SID *sids, int num_sids),
+ void *private)
+{
+ struct winbindd_domain *domain;
+ struct winbindd_request request;
+ struct gettoken_state *state;
+
+ state = TALLOC_P(mem_ctx, struct gettoken_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(private, False, NULL, 0);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ sid_copy(&state->user_sid, user_sid);
+ state->alias_domain = find_our_domain();
+ state->builtin_domain = find_builtin_domain();
+ state->cont = cont;
+ state->private = private;
+
+ domain = find_domain_from_sid_noinit(user_sid);
+ if (domain == NULL) {
+ DEBUG(5, ("Could not find domain from SID %s\n",
+ sid_string_static(user_sid)));
+ cont(private, False, NULL, 0);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_GETUSERDOMGROUPS;
+ fstrcpy(request.data.sid, sid_string_static(user_sid));
+
+ do_async_domain(mem_ctx, domain, &request, gettoken_recvdomgroups,
+ NULL, state);
+}
+
+static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ struct gettoken_state *state =
+ talloc_get_type_abort(private, struct gettoken_state);
+ char *sids_str;
+
+ if (!success) {
+ DEBUG(10, ("Could not get domain groups\n"));
+ state->cont(state->private, False, NULL, 0);
+ return;
+ }
+
+ sids_str = response->extra_data;
+
+ if (sids_str == NULL) {
+ DEBUG(10, ("Received no domain groups\n"));
+ state->cont(state->private, True, NULL, 0);
+ return;
+ }
+
+ state->sids = NULL;
+ state->num_sids = 0;
+
+ add_sid_to_array(mem_ctx, &state->user_sid, &state->sids,
+ &state->num_sids);
+
+ if (!parse_sidlist(mem_ctx, sids_str, &state->sids,
+ &state->num_sids)) {
+ DEBUG(0, ("Could not parse sids\n"));
+ state->cont(state->private, False, NULL, 0);
+ return;
+ }
+
+ SAFE_FREE(response->extra_data);
+
+ if (state->alias_domain == NULL) {
+ DEBUG(10, ("Don't expand domain local groups\n"));
+ state->cont(state->private, True, state->sids,
+ state->num_sids);
+ return;
+ }
+
+ winbindd_getsidaliases_async(state->alias_domain, mem_ctx,
+ state->sids, state->num_sids,
+ gettoken_recvaliases, state);
+}
+
+static void gettoken_recvaliases(void *private, BOOL success,
+ const DOM_SID *aliases,
+ int num_aliases)
+{
+ struct gettoken_state *state = private;
+ int i;
+
+ if (!success) {
+ DEBUG(10, ("Could not receive domain local groups\n"));
+ state->cont(state->private, False, NULL, 0);
+ return;
+ }
+
+ for (i=0; i<num_aliases; i++)
+ add_sid_to_array(state->mem_ctx, &aliases[i],
+ &state->sids, &state->num_sids);
+
+ if (state->builtin_domain != NULL) {
+ struct winbindd_domain *builtin_domain = state->builtin_domain;
+ DEBUG(10, ("Expanding our own local groups\n"));
+ state->builtin_domain = NULL;
+ winbindd_getsidaliases_async(builtin_domain, state->mem_ctx,
+ state->sids, state->num_sids,
+ gettoken_recvaliases, state);
+ return;
+ }
+
+ state->cont(state->private, True, state->sids, state->num_sids);
+}
+
+struct sid2uid_state {
+ TALLOC_CTX *mem_ctx;
+ DOM_SID sid;
+ char *username;
+ uid_t uid;
+ void (*cont)(void *private, BOOL success, uid_t uid);
+ void *private;
+};
+
+static void sid2uid_lookup_sid_recv(void *private, BOOL success,
+ const char *dom_name, const char *name,
+ enum SID_NAME_USE type);
+static void sid2uid_noalloc_recv(void *private, BOOL success, uid_t uid);
+static void sid2uid_alloc_recv(void *private, BOOL success, uid_t uid);
+static void sid2uid_name2uid_recv(void *private, BOOL success, uid_t uid);
+static void sid2uid_set_mapping_recv(void *private, BOOL success);
+
+void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private, BOOL success,
+ uid_t uid),
+ void *private)
+{
+ struct sid2uid_state *state;
+ NTSTATUS result;
+ uid_t uid;
+
+ if (idmap_proxyonly()) {
+ DEBUG(10, ("idmap proxy only\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ /* Query only the local tdb, everything else might possibly block */
+
+ result = idmap_sid_to_uid(sid, &uid, ID_QUERY_ONLY|ID_CACHE_ONLY);
+
+ if (NT_STATUS_IS_OK(result)) {
+ cont(private, True, uid);
+ return;
+ }
+
+ state = TALLOC_P(mem_ctx, struct sid2uid_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->sid = *sid;
+ state->cont = cont;
+ state->private = private;
+
+ /* Let's see if it's really a user before allocating a uid */
+
+ winbindd_lookupsid_async(mem_ctx, sid, sid2uid_lookup_sid_recv, state);
+}
+
+static void sid2uid_lookup_sid_recv(void *private, BOOL success,
+ const char *dom_name, const char *name,
+ enum SID_NAME_USE type)
+{
+ struct sid2uid_state *state =
+ talloc_get_type_abort(private, struct sid2uid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger lookup_sid\n"));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
+ DEBUG(5, ("SID is not a user\n"));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->username = talloc_strdup(state->mem_ctx, name);
+
+ /* Ask the possibly blocking remote IDMAP */
+
+ idmap_sid2uid_async(state->mem_ctx, &state->sid, False,
+ sid2uid_noalloc_recv, state);
+}
+
+static void sid2uid_noalloc_recv(void *private, BOOL success, uid_t uid)
+{
+ struct sid2uid_state *state =
+ talloc_get_type_abort(private, struct sid2uid_state);
+
+ if (success) {
+ DEBUG(10, ("found uid for sid %s in remote backend\n",
+ sid_string_static(&state->sid)));
+ state->cont(state->private, True, uid);
+ return;
+ }
+
+ if (lp_winbind_trusted_domains_only() &&
+ (sid_compare_domain(&state->sid, &find_our_domain()->sid) == 0)) {
+ DEBUG(10, ("Trying to go via nss\n"));
+ winbindd_name2uid_async(state->mem_ctx, state->username,
+ sid2uid_name2uid_recv, state);
+ return;
+ }
+
+ /* To be done: Here we're going to try the unixinfo pipe */
+
+ /* Now allocate a uid */
+
+ idmap_sid2uid_async(state->mem_ctx, &state->sid, True,
+ sid2uid_alloc_recv, state);
+}
+
+static void sid2uid_alloc_recv(void *private, BOOL success, uid_t uid)
+{
+ struct sid2uid_state *state =
+ talloc_get_type_abort(private, struct sid2uid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not allocate uid\n"));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->cont(state->private, True, uid);
+}
+
+static void sid2uid_name2uid_recv(void *private, BOOL success, uid_t uid)
+{
+ struct sid2uid_state *state =
+ talloc_get_type_abort(private, struct sid2uid_state);
+ unid_t id;
+
+ if (!success) {
+ DEBUG(5, ("Could not find uid for name %s\n",
+ state->username));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->uid = uid;
+
+ id.uid = uid;
+ idmap_set_mapping_async(state->mem_ctx, &state->sid, id, ID_USERID,
+ sid2uid_set_mapping_recv, state);
+}
+
+static void sid2uid_set_mapping_recv(void *private, BOOL success)
+{
+ struct sid2uid_state *state =
+ talloc_get_type_abort(private, struct sid2uid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not set ID mapping for sid %s\n",
+ sid_string_static(&state->sid)));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->cont(state->private, True, state->uid);
+}
+
+struct sid2gid_state {
+ TALLOC_CTX *mem_ctx;
+ DOM_SID sid;
+ char *groupname;
+ gid_t gid;
+ void (*cont)(void *private, BOOL success, gid_t gid);
+ void *private;
+};
+
+static void sid2gid_lookup_sid_recv(void *private, BOOL success,
+ const char *dom_name, const char *name,
+ enum SID_NAME_USE type);
+static void sid2gid_noalloc_recv(void *private, BOOL success, gid_t gid);
+static void sid2gid_alloc_recv(void *private, BOOL success, gid_t gid);
+static void sid2gid_name2gid_recv(void *private, BOOL success, gid_t gid);
+static void sid2gid_set_mapping_recv(void *private, BOOL success);
+
+void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private, BOOL success,
+ gid_t gid),
+ void *private)
+{
+ struct sid2gid_state *state;
+ NTSTATUS result;
+ gid_t gid;
+
+ if (idmap_proxyonly()) {
+ DEBUG(10, ("idmap proxy only\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ /* Query only the local tdb, everything else might possibly block */
+
+ result = idmap_sid_to_gid(sid, &gid, ID_QUERY_ONLY|ID_CACHE_ONLY);
+
+ if (NT_STATUS_IS_OK(result)) {
+ cont(private, True, gid);
+ return;
+ }
+
+ state = TALLOC_P(mem_ctx, struct sid2gid_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(private, False, 0);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->sid = *sid;
+ state->cont = cont;
+ state->private = private;
+
+ /* Let's see if it's really a user before allocating a gid */
+
+ winbindd_lookupsid_async(mem_ctx, sid, sid2gid_lookup_sid_recv, state);
+}
+
+static void sid2gid_lookup_sid_recv(void *private, BOOL success,
+ const char *dom_name, const char *name,
+ enum SID_NAME_USE type)
+{
+ struct sid2gid_state *state =
+ talloc_get_type_abort(private, struct sid2gid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger lookup_sid\n"));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ if (((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
+ (type != SID_NAME_WKN_GRP))) {
+ DEBUG(5, ("SID is not a group\n"));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->groupname = talloc_strdup(state->mem_ctx, name);
+
+ /* Ask the possibly blocking remote IDMAP and allocate */
+
+ idmap_sid2gid_async(state->mem_ctx, &state->sid, False,
+ sid2gid_noalloc_recv, state);
+}
+
+static void sid2gid_noalloc_recv(void *private, BOOL success, gid_t gid)
+{
+ struct sid2gid_state *state =
+ talloc_get_type_abort(private, struct sid2gid_state);
+
+ if (success) {
+ DEBUG(10, ("found gid for sid %s in remote backend\n",
+ sid_string_static(&state->sid)));
+ state->cont(state->private, True, gid);
+ return;
+ }
+
+ if (lp_winbind_trusted_domains_only() &&
+ (sid_compare_domain(&state->sid, &find_our_domain()->sid) == 0)) {
+ DEBUG(10, ("Trying to go via nss\n"));
+ winbindd_name2gid_async(state->mem_ctx, state->groupname,
+ sid2gid_name2gid_recv, state);
+ return;
+ }
+
+ /* To be done: Here we're going to try the unixinfo pipe */
+
+ /* Now allocate a gid */
+
+ idmap_sid2gid_async(state->mem_ctx, &state->sid, True,
+ sid2gid_alloc_recv, state);
+}
+
+static void sid2gid_alloc_recv(void *private, BOOL success, gid_t gid)
+{
+ struct sid2gid_state *state =
+ talloc_get_type_abort(private, struct sid2gid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not allocate gid\n"));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->cont(state->private, True, gid);
+}
+
+static void sid2gid_name2gid_recv(void *private, BOOL success, gid_t gid)
+{
+ struct sid2gid_state *state =
+ talloc_get_type_abort(private, struct sid2gid_state);
+ unid_t id;
+
+ if (!success) {
+ DEBUG(5, ("Could not find gid for name %s\n",
+ state->groupname));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->gid = gid;
+
+ id.gid = gid;
+ idmap_set_mapping_async(state->mem_ctx, &state->sid, id, ID_GROUPID,
+ sid2gid_set_mapping_recv, state);
+}
+
+static void sid2gid_set_mapping_recv(void *private, BOOL success)
+{
+ struct sid2gid_state *state =
+ talloc_get_type_abort(private, struct sid2gid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not set ID mapping for sid %s\n",
+ sid_string_static(&state->sid)));
+ state->cont(state->private, False, 0);
+ return;
+ }
+
+ state->cont(state->private, True, state->gid);
+}
+
+static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
+ struct winbindd_response *response,
+ void *c, void *private)
+{
+ void (*cont)(void *priv, BOOL succ, const char *acct_name,
+ const char *full_name, uint32 group_rid) = c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger query_user\n"));
+ cont(private, False, NULL, NULL, -1);
+ return;
+ }
+
+ cont(private, True, response->data.user_info.acct_name,
+ response->data.user_info.full_name,
+ response->data.user_info.group_rid);
+}
+
+void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ const DOM_SID *sid,
+ void (*cont)(void *private, BOOL success,
+ const char *acct_name,
+ const char *full_name,
+ uint32 group_rid),
+ void *private)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_USERINFO;
+ sid_to_string(request.data.sid, sid);
+ do_async_domain(mem_ctx, domain, &request, query_user_recv,
+ cont, private);
+}
+
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index e036de72a7..90ccb43a6e 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -26,12 +26,6 @@
#include "includes.h"
#include "winbindd.h"
-extern BOOL opt_nocache;
-extern struct winbindd_methods msrpc_methods;
-extern struct winbindd_methods ads_methods;
-extern BOOL opt_dual_daemon;
-extern BOOL background_process;
-
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -53,6 +47,8 @@ static struct winbind_cache *wcache;
/* flush the cache */
void wcache_flush_cache(void)
{
+ extern BOOL opt_nocache;
+
if (!wcache)
return;
if (wcache->tdb) {
@@ -106,9 +102,11 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
struct winbind_cache *ret = wcache;
if (!domain->backend) {
+ extern struct winbindd_methods reconnect_methods;
switch (lp_security()) {
#ifdef HAVE_ADS
case SEC_ADS: {
+ extern struct winbindd_methods ads_methods;
/* always obey the lp_security parameter for our domain */
if (domain->primary) {
domain->backend = &ads_methods;
@@ -132,7 +130,7 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
default:
DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n",
domain->name));
- domain->backend = &msrpc_methods;
+ domain->backend = &reconnect_methods;
}
}
@@ -212,7 +210,10 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
smb_panic("centry_string");
}
- ret = TALLOC(mem_ctx, len+1);
+ if (mem_ctx != NULL)
+ ret = TALLOC(mem_ctx, len+1);
+ else
+ ret = SMB_MALLOC(len+1);
if (!ret) {
smb_panic("centry_string out of memory\n");
}
@@ -225,20 +226,15 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
/* pull a string from a cache entry, using the supplied
talloc context
*/
-static DOM_SID *centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
+static BOOL centry_sid(struct cache_entry *centry, DOM_SID *sid)
{
- DOM_SID *sid;
char *sid_string;
-
- sid = TALLOC_P(mem_ctx, DOM_SID);
- if (!sid)
- return NULL;
-
- sid_string = centry_string(centry, mem_ctx);
+ sid_string = centry_string(centry, NULL);
if (!string_to_sid(sid, sid_string)) {
- return NULL;
+ return False;
}
- return sid;
+ SAFE_FREE(sid_string);
+ return True;
}
/* the server is considered down if it can't give us a sequence number */
@@ -471,11 +467,13 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
centry->sequence_number = centry_uint32(centry);
if (centry_expired(domain, kstr, centry)) {
+ extern BOOL opt_dual_daemon;
DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
kstr, domain->name ));
if (opt_dual_daemon) {
+ extern BOOL background_process;
background_process = True;
DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n",
kstr, domain->name ));
@@ -654,9 +652,9 @@ static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WI
return;
centry_put_string(centry, info->acct_name);
centry_put_string(centry, info->full_name);
- centry_put_sid(centry, info->user_sid);
- centry_put_sid(centry, info->group_sid);
- centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_sid));
+ centry_put_sid(centry, &info->user_sid);
+ centry_put_sid(centry, &info->group_sid);
+ centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
centry_free(centry);
}
@@ -691,8 +689,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
for (i=0; i<(*num_entries); i++) {
(*info)[i].acct_name = centry_string(centry, mem_ctx);
(*info)[i].full_name = centry_string(centry, mem_ctx);
- (*info)[i].user_sid = centry_sid(centry, mem_ctx);
- (*info)[i].group_sid = centry_sid(centry, mem_ctx);
+ centry_sid(centry, &(*info)[i].user_sid);
+ centry_sid(centry, &(*info)[i].group_sid);
}
do_cached:
@@ -729,10 +727,12 @@ do_query:
status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
if (!NT_STATUS_IS_OK(status))
- DEBUG(3, ("query_user_list: returned 0x%08x, retrying\n", NT_STATUS_V(status)));
- if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL)) {
- DEBUG(3, ("query_user_list: flushing connection cache\n"));
- winbindd_cm_flush();
+ DEBUG(3, ("query_user_list: returned 0x%08x, "
+ "retrying\n", NT_STATUS_V(status)));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
+ DEBUG(3, ("query_user_list: flushing "
+ "connection cache\n"));
+ invalidate_cm_connection(&domain->conn);
}
} while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
@@ -747,17 +747,17 @@ do_query:
for (i=0; i<(*num_entries); i++) {
centry_put_string(centry, (*info)[i].acct_name);
centry_put_string(centry, (*info)[i].full_name);
- centry_put_sid(centry, (*info)[i].user_sid);
- centry_put_sid(centry, (*info)[i].group_sid);
+ centry_put_sid(centry, &(*info)[i].user_sid);
+ centry_put_sid(centry, &(*info)[i].group_sid);
if (domain->backend->consistent) {
/* when the backend is consistent we can pre-prime some mappings */
wcache_save_name_to_sid(domain, NT_STATUS_OK,
domain->name,
(*info)[i].acct_name,
- (*info)[i].user_sid,
+ &(*info)[i].user_sid,
SID_NAME_USER);
wcache_save_sid_to_name(domain, NT_STATUS_OK,
- (*info)[i].user_sid,
+ &(*info)[i].user_sid,
domain->name,
(*info)[i].acct_name,
SID_NAME_USER);
@@ -939,7 +939,6 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
struct cache_entry *centry = NULL;
NTSTATUS status;
fstring uname;
- DOM_SID *sid2;
if (!cache->tdb)
goto do_query;
@@ -950,13 +949,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
if (!centry)
goto do_query;
*type = (enum SID_NAME_USE)centry_uint32(centry);
- sid2 = centry_sid(centry, mem_ctx);
- if (!sid2) {
- ZERO_STRUCTP(sid);
- } else {
- sid_copy(sid, sid2);
- }
-
+ centry_sid(centry, sid);
status = centry->status;
DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",
@@ -1089,8 +1082,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
info->acct_name = centry_string(centry, mem_ctx);
info->full_name = centry_string(centry, mem_ctx);
- info->user_sid = centry_sid(centry, mem_ctx);
- info->group_sid = centry_sid(centry, mem_ctx);
+ centry_sid(centry, &info->user_sid);
+ centry_sid(centry, &info->group_sid);
status = centry->status;
DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n",
@@ -1124,7 +1117,7 @@ do_query:
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,
- uint32 *num_groups, DOM_SID ***user_gids)
+ uint32 *num_groups, DOM_SID **user_gids)
{
struct winbind_cache *cache = get_cache(domain);
struct cache_entry *centry = NULL;
@@ -1157,11 +1150,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
if (*num_groups == 0)
goto do_cached;
- (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups);
+ (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
if (! (*user_gids))
smb_panic("lookup_usergroups out of memory");
for (i=0; i<(*num_groups); i++) {
- (*user_gids)[i] = centry_sid(centry, mem_ctx);
+ centry_sid(centry, &(*user_gids)[i]);
}
do_cached:
@@ -1194,7 +1187,7 @@ do_query:
goto skip_save;
centry_put_uint32(centry, *num_groups);
for (i=0; i<(*num_groups); i++) {
- centry_put_sid(centry, (*user_gids)[i]);
+ centry_put_sid(centry, &(*user_gids)[i]);
}
centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
centry_free(centry);
@@ -1205,7 +1198,7 @@ skip_save:
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 num_sids, DOM_SID **sids,
+ uint32 num_sids, const DOM_SID *sids,
uint32 *num_aliases, uint32 **alias_rids)
{
struct winbind_cache *cache = get_cache(domain);
@@ -1228,7 +1221,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
for (i=0; i<num_sids; i++) {
sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
- sid_string_static(sids[i]));
+ sid_string_static(&sids[i]));
if (sidlist == NULL)
return NT_STATUS_NO_MEMORY;
}
@@ -1265,7 +1258,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
if (!NT_STATUS_IS_OK(domain->last_status))
return domain->last_status;
- DEBUG(10,("lookup_useraliases: [Cached] - doing backend query for info "
+ DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
"for domain %s\n", domain->name ));
status = domain->backend->lookup_useraliases(domain, mem_ctx,
@@ -1291,7 +1284,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names,
- DOM_SID ***sid_mem, char ***names,
+ DOM_SID **sid_mem, char ***names,
uint32 **name_types)
{
struct winbind_cache *cache = get_cache(domain);
@@ -1312,7 +1305,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
if (*num_names == 0)
goto do_cached;
- (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_names);
+ (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
(*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
(*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
@@ -1321,7 +1314,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
}
for (i=0; i<(*num_names); i++) {
- (*sid_mem)[i] = centry_sid(centry, mem_ctx);
+ centry_sid(centry, &(*sid_mem)[i]);
(*names)[i] = centry_string(centry, mem_ctx);
(*name_types)[i] = centry_uint32(centry);
}
@@ -1359,7 +1352,7 @@ do_query:
goto skip_save;
centry_put_uint32(centry, *num_names);
for (i=0; i<(*num_names); i++) {
- centry_put_sid(centry, (*sid_mem)[i]);
+ centry_put_sid(centry, &(*sid_mem)[i]);
centry_put_string(centry, (*names)[i]);
centry_put_uint32(centry, (*name_types)[i]);
}
@@ -1466,3 +1459,166 @@ struct winbindd_methods cache_methods = {
trusted_domains,
alternate_name
};
+
+static BOOL init_wcache(void)
+{
+ if (wcache == NULL) {
+ wcache = SMB_XMALLOC_P(struct winbind_cache);
+ ZERO_STRUCTP(wcache);
+ }
+
+ if (wcache->tdb != NULL)
+ return True;
+
+ wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000,
+ TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600);
+
+ if (wcache->tdb == NULL) {
+ DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
+ return False;
+ }
+
+ return True;
+}
+
+void cache_store_response(pid_t pid, struct winbindd_response *response)
+{
+ fstring key_str;
+
+ if (!init_wcache())
+ return;
+
+ DEBUG(10, ("Storing response for pid %d, len %d\n",
+ pid, response->length));
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ if (tdb_store(wcache->tdb, string_tdb_data(key_str),
+ make_tdb_data((void *)response, sizeof(*response)),
+ TDB_REPLACE) == -1)
+ return;
+
+ if (response->length == sizeof(*response))
+ return;
+
+ /* There's extra data */
+
+ DEBUG(10, ("Storing extra data: len=%d\n",
+ response->length - sizeof(*response)));
+
+ fstr_sprintf(key_str, "DE/%d", pid);
+ if (tdb_store(wcache->tdb, string_tdb_data(key_str),
+ make_tdb_data(response->extra_data,
+ response->length - sizeof(*response)),
+ TDB_REPLACE) == 0)
+ return;
+
+ /* We could not store the extra data, make sure the tdb does not
+ * contain a main record with wrong dangling extra data */
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ tdb_delete(wcache->tdb, string_tdb_data(key_str));
+
+ return;
+}
+
+BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
+{
+ TDB_DATA data;
+ fstring key_str;
+
+ if (!init_wcache())
+ return False;
+
+ DEBUG(10, ("Retrieving response for pid %d\n", pid));
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
+
+ if (data.dptr == NULL)
+ return False;
+
+ if (data.dsize != sizeof(*response))
+ return False;
+
+ memcpy(response, data.dptr, data.dsize);
+ SAFE_FREE(data.dptr);
+
+ if (response->length == sizeof(*response)) {
+ response->extra_data = NULL;
+ return True;
+ }
+
+ /* There's extra data */
+
+ DEBUG(10, ("Retrieving extra data length=%d\n",
+ response->length - sizeof(*response)));
+
+ fstr_sprintf(key_str, "DE/%d", pid);
+ data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
+
+ if (data.dptr == NULL) {
+ DEBUG(0, ("Did not find extra data\n"));
+ return False;
+ }
+
+ if (data.dsize != (response->length - sizeof(*response))) {
+ DEBUG(0, ("Invalid extra data length: %d\n", data.dsize));
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+
+ response->extra_data = data.dptr;
+ return True;
+}
+
+char *cache_store_request_data(TALLOC_CTX *mem_ctx, char *request_string)
+{
+ int i;
+
+ if (!init_wcache())
+ return NULL;
+
+ for (i=0; i<2; i++) {
+ char *key = talloc_strdup(mem_ctx, generate_random_str(16));
+ if (key == NULL)
+ return NULL;
+ DEBUG(10, ("Storing request key %s\n", key));
+ if (tdb_store_bystring(wcache->tdb, key,
+ string_tdb_data(request_string),
+ TDB_INSERT) == 0)
+ return key;
+ }
+ return NULL;
+}
+
+char *cache_retrieve_request_data(TALLOC_CTX *mem_ctx, char *key)
+{
+ TDB_DATA data;
+ char *result = NULL;
+
+ if (!init_wcache())
+ return NULL;
+
+ DEBUG(10, ("Retrieving key %s\n", key));
+
+ data = tdb_fetch_bystring(wcache->tdb, key);
+ if (data.dptr == NULL)
+ return NULL;
+
+ if (strnlen(data.dptr, data.dsize) != (data.dsize)) {
+ DEBUG(0, ("Received invalid request string\n"));
+ goto done;
+ }
+ result = TALLOC_ARRAY(mem_ctx, char, data.dsize+1);
+ if (result != NULL) {
+ memcpy(result, data.dptr, data.dsize);
+ result[data.dsize] = '\0';
+ }
+ if (tdb_delete_bystring(wcache->tdb, key) != 0) {
+ DEBUG(0, ("Could not delete key %s\n", key));
+ result = NULL;
+ }
+ done:
+ SAFE_FREE(data.dptr);
+ return result;
+}
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index c5cf1d5f46..a6f09f4bf2 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -3,8 +3,10 @@
Winbind daemon connection manager
- Copyright (C) Tim Potter 2001
- Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Gerald (Jerry) Carter 2003-2005.
+ Copyright (C) Volker Lendecke 2004-2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -65,21 +67,6 @@
/* Global list of connections. Initially a DLIST but can become a hash
table or whatever later. */
-struct winbindd_cm_conn {
- struct winbindd_cm_conn *prev, *next;
- fstring domain;
- fstring controller;
- fstring pipe_name;
- struct cli_state *cli;
- POLICY_HND pol;
-};
-
-static struct winbindd_cm_conn *cm_conns = NULL;
-
-static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain,
- const char *pipe_name,
- struct winbindd_cm_conn **conn_out);
-
/* Choose between anonymous or authenticated connections. We need to use
an authenticated connection if DCs have the RestrictAnonymous registry
entry set > 0, or the "Additional restrictions for anonymous
@@ -113,75 +100,45 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password)
}
}
-/*
- setup for schannel on any pipes opened on this connection
-*/
-static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
-{
- NTSTATUS ret;
- uchar trust_password[16];
- uint32 sec_channel_type;
- DOM_SID sid;
- time_t lct;
-
- /* use the domain trust password if we're on a DC
- and this is not our domain */
-
- if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
- char *pass = NULL;
-
- if ( !secrets_fetch_trusted_domain_password( domain,
- &pass, &sid, &lct) )
- {
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- sec_channel_type = SEC_CHAN_DOMAIN;
- E_md4hash(pass, trust_password);
- SAFE_FREE( pass );
-
- } else {
- if (!secrets_fetch_trust_account_password(lp_workgroup(),
- trust_password, NULL, &sec_channel_type))
- {
- return NT_STATUS_UNSUCCESSFUL;
- }
- }
-
- ret = cli_nt_setup_netsec(cli, sec_channel_type,
- AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
-
- return ret;
-}
-
static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
fstring dcname, struct in_addr *dc_ip)
{
struct winbindd_domain *our_domain;
NTSTATUS result;
- struct winbindd_cm_conn *conn;
+ struct rpc_pipe_client *cli;
TALLOC_CTX *mem_ctx;
fstring tmp;
char *p;
+ /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
+ * moment.... */
+
if (IS_DC)
return False;
if (domain->primary)
return False;
- if ((our_domain = find_our_domain()) == NULL)
- return False;
+ our_domain = find_our_domain();
- result = get_connection_from_cache(our_domain, PIPE_NETLOGON, &conn);
- if (!NT_STATUS_IS_OK(result))
+ if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
return False;
- if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
+ {
+ /* These var's can be ignored -- we're not requesting
+ anything in the credential chain here */
+ unsigned char *session_key;
+ DOM_CRED *creds;
+ result = cm_connect_netlogon(our_domain, mem_ctx, &cli,
+ &session_key, &creds);
+ }
+
+ if (!NT_STATUS_IS_OK(result))
return False;
- result = cli_netlogon_getdcname(conn->cli, mem_ctx, domain->name, tmp);
+ result = rpccli_netlogon_getdcname(cli, mem_ctx, domain->dcname,
+ domain->name, tmp);
talloc_destroy(mem_ctx);
@@ -208,7 +165,6 @@ static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
const int sockfd,
- const int pipe_index,
const char *controller,
struct cli_state **cli,
BOOL *retry)
@@ -376,33 +332,11 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
got_mutex = False;
*retry = False;
- /* Windows 2003 SP1 does not lie LsaOpenPolicy() over schannel.
- Returns RPC_NT_CANNOT_SUPPPORT (0xc0020041) for that call.
- So just drop it on the lsarpc pipe */
-
- if ( (domain->primary || IS_DC) && (pipe_index!=PI_LSARPC) ) {
- NTSTATUS status = setup_schannel( *cli, domain->name );
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3,("schannel refused - continuing without "
- "schannel (%s)\n", nt_errstr(status)));
- }
- }
-
/* set the domain if empty; needed for schannel connections */
if ( !*(*cli)->domain )
fstrcpy( (*cli)->domain, domain->name );
- if ( !cli_nt_session_open (*cli, pipe_index) ) {
-
- result = NT_STATUS_PIPE_NOT_AVAILABLE;
-
- /* This might be a NT4 DC */
- if ( is_win2k_pipe(pipe_index) )
- add_failed_connection = False;
-
- cli_shutdown(*cli);
- goto done;
- }
+ (*cli)->pipe_auth_flags = 0;
result = NT_STATUS_OK;
add_failed_connection = False;
@@ -463,18 +397,158 @@ static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
return True;
}
+static void mailslot_name(struct in_addr dc_ip, fstring name)
+{
+ fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
+}
+
+static BOOL send_getdc_request(struct in_addr dc_ip,
+ const char *domain_name,
+ const DOM_SID *sid)
+{
+ pstring outbuf;
+ char *p;
+ fstring my_acct_name;
+ fstring my_mailslot;
+
+ mailslot_name(dc_ip, my_mailslot);
+
+ memset(outbuf, '\0', sizeof(outbuf));
+
+ p = outbuf;
+
+ SCVAL(p, 0, SAMLOGON);
+ p++;
+
+ SCVAL(p, 0, 0); /* Count pointer ... */
+ p++;
+
+ SIVAL(p, 0, 0); /* The sender's token ... */
+ p += 2;
+
+ p += dos_PutUniCode(p, global_myname(), sizeof(pstring), True);
+ fstr_sprintf(my_acct_name, "%s$", global_myname());
+ p += dos_PutUniCode(p, my_acct_name, sizeof(pstring), True);
+
+ memcpy(p, my_mailslot, strlen(my_mailslot)+1);
+ p += strlen(my_mailslot)+1;
+
+ SIVAL(p, 0, 0x80);
+ p+=4;
+
+ SIVAL(p, 0, sid_size(sid));
+ p+=4;
+
+ p = ALIGN4(p, outbuf);
+
+ sid_linearize(p, sid_size(sid), sid);
+ p += sid_size(sid);
+
+ SIVAL(p, 0, 1);
+ SSVAL(p, 4, 0xffff);
+ SSVAL(p, 6, 0xffff);
+ p+=8;
+
+ return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
+ outbuf, PTR_DIFF(p, outbuf),
+ global_myname(), 0, domain_name, 0x1c,
+ dc_ip);
+}
+
+static BOOL receive_getdc_response(struct in_addr dc_ip,
+ const char *domain_name,
+ fstring dc_name)
+{
+ struct packet_struct *packet;
+ fstring my_mailslot;
+ char *buf, *p;
+ fstring dcname, user, domain;
+ int len;
+
+ mailslot_name(dc_ip, my_mailslot);
+
+ packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
+
+ if (packet == NULL) {
+ DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
+ return False;
+ }
+
+ DEBUG(5, ("Received packet for %s\n", my_mailslot));
+
+ buf = packet->packet.dgram.data;
+ len = packet->packet.dgram.datasize;
+
+ if (len < 70) {
+ /* 70 is a completely arbitrary value to make sure
+ the SVAL below does not read uninitialized memory */
+ DEBUG(3, ("GetDC got short response\n"));
+ return False;
+ }
+
+ /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
+ p = buf+SVAL(buf, smb_vwv10);
+
+ if (CVAL(p,0) != SAMLOGON_R) {
+ DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
+ return False;
+ }
+
+ p+=2;
+ pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
+ STR_TERMINATE|STR_NOALIGN);
+ p = skip_unibuf(p, PTR_DIFF(buf+len, p));
+ pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
+ STR_TERMINATE|STR_NOALIGN);
+ p = skip_unibuf(p, PTR_DIFF(buf+len, p));
+ pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
+ STR_TERMINATE|STR_NOALIGN);
+ p = skip_unibuf(p, PTR_DIFF(buf+len, p));
+
+ if (!strequal(domain, domain_name)) {
+ DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
+ domain_name, domain));
+ return False;
+ }
+
+ p = dcname;
+ if (*p == '\\') p += 1;
+ if (*p == '\\') p += 1;
+
+ fstrcpy(dc_name, p);
+
+ DEBUG(10, ("GetDC gave name %s for domain %s\n",
+ dc_name, domain));
+
+ return True;
+}
+
/*******************************************************************
convert an ip to a name
*******************************************************************/
-static void dcip_to_name( const char *domainname, const char *realm, struct in_addr ip, fstring name )
+static void dcip_to_name( const char *domainname, const char *realm,
+ const DOM_SID *sid, struct in_addr ip, fstring name )
{
- /* try node status request first */
+ int i;
+
+ /* try GETDC requests first */
+
+ send_getdc_request(ip, domainname, sid);
+ smb_msleep(100);
+
+ for (i=0; i<5; i++) {
+ if (receive_getdc_response(ip, domainname, name))
+ return;
+ smb_msleep(500);
+ }
+
+ /* try node status request */
if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
return;
- /* backup in case the ads stuff fails */
+ /* backup in case the netbios stuff fails */
fstrcpy( name, inet_ntoa(ip) );
@@ -510,7 +584,6 @@ static void dcip_to_name( const char *domainname, const char *realm, struct in_a
return;
}
-
/*******************************************************************
Retreive a list of IP address for domain controllers. Fill in
the dcs[] with results.
@@ -553,6 +626,8 @@ static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
if ( iplist_size==0 && lp_security() == SEC_ADS )
get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
+ /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
+
/* now add to the dc array. We'll wait until the last minute
to look up the name of the DC. But we fill in the char* for
the ip now in to make the failed connection cache work */
@@ -616,7 +691,7 @@ static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
the name, now try to get the name */
if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
- dcip_to_name( domain->name, domain->alt_name, addr->sin_addr, dcname );
+ dcip_to_name( domain->name, domain->alt_name, &domain->sid, addr->sin_addr, dcname );
else
fstrcpy(dcname, dcnames[fd_index]);
@@ -624,7 +699,6 @@ static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
}
static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
- const int pipe_index,
struct winbindd_cm_conn *new_conn)
{
TALLOC_CTX *mem_ctx;
@@ -659,17 +733,8 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
new_conn->cli = NULL;
- result = cm_prepare_connection(domain, fd, pipe_index,
- domain->dcname,
- &new_conn->cli, &retry);
-
- if (NT_STATUS_IS_OK(result)) {
- fstrcpy(new_conn->domain, domain->name);
- /* Initialise SMB connection */
- fstrcpy(new_conn->pipe_name,
- get_pipe_name_from_index(pipe_index));
- break;
- }
+ result = cm_prepare_connection(domain, fd, domain->dcname,
+ &new_conn->cli, &retry);
if (!retry)
break;
@@ -679,121 +744,86 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
return result;
}
-/************************************************************************
- Wrapper around statuc cm_open_connection to retreive a freshly
- setup cli_state struct
-************************************************************************/
-
-NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
- struct cli_state **cli)
-{
- NTSTATUS result;
- struct winbindd_cm_conn conn;
-
- result = cm_open_connection( domain, pipe_index, &conn );
-
- if ( NT_STATUS_IS_OK(result) )
- *cli = conn.cli;
-
- return result;
-}
-
/* Return true if a connection is still alive */
-static BOOL connection_ok(struct winbindd_cm_conn *conn)
+void invalidate_cm_connection(struct winbindd_cm_conn *conn)
{
- if (!conn) {
- smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
- return False;
+ if (conn->samr_pipe != NULL) {
+ cli_rpc_close(conn->samr_pipe);
+ conn->samr_pipe = NULL;
}
- if (!conn->cli) {
- DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
- conn->controller, conn->domain, conn->pipe_name));
- return False;
+ if (conn->lsa_pipe != NULL) {
+ cli_rpc_close(conn->lsa_pipe);
+ conn->lsa_pipe = NULL;
}
- if (!conn->cli->initialised) {
- DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
- conn->controller, conn->domain, conn->pipe_name));
- return False;
+ if (conn->netlogon_auth2_pipe != NULL) {
+ cli_rpc_close(conn->netlogon_auth2_pipe);
+ conn->netlogon_auth2_pipe = NULL;
}
- if (conn->cli->fd == -1) {
- DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
- conn->controller, conn->domain, conn->pipe_name));
- return False;
+ if (conn->netlogon_pipe != NULL) {
+ cli_rpc_close(conn->netlogon_pipe);
+ conn->netlogon_pipe = NULL;
}
-
- return True;
-}
-/* Search the cache for a connection. If there is a broken one,
- shut it down properly and return NULL. */
+ if (conn->cli)
+ cli_shutdown(conn->cli);
+
+ conn->cli = NULL;
+}
-static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
- struct winbindd_cm_conn **conn_out)
+void close_conns_after_fork(void)
{
- struct winbindd_cm_conn *conn;
+ struct winbindd_domain *domain;
- for (conn = cm_conns; conn; ) {
- if (strequal(conn->domain, domain->name) &&
- strequal(conn->pipe_name, pipe_name)) {
- if (!connection_ok(conn)) {
- /* Dead connection - remove it. */
- struct winbindd_cm_conn *conn_temp = conn->next;
- if (conn->cli)
- cli_shutdown(conn->cli);
- DLIST_REMOVE(cm_conns, conn);
- SAFE_FREE(conn);
- conn = conn_temp; /* Keep the loop moving */
- continue;
- } else {
- break;
- }
- }
- conn = conn->next;
- }
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->conn.cli == NULL)
+ continue;
- *conn_out = conn;
-}
+ if (domain->conn.cli->fd == -1)
+ continue;
-/* Initialize a new connection up to the RPC BIND. */
+ close(domain->conn.cli->fd);
+ domain->conn.cli->fd = -1;
+ }
+}
-static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
- struct winbindd_cm_conn **conn_out)
+static BOOL connection_ok(struct winbindd_domain *domain)
{
- struct winbindd_cm_conn *conn;
- NTSTATUS result;
+ if (domain->conn.cli == NULL) {
+ DEBUG(8, ("Connection to %s for domain %s has NULL "
+ "cli!\n", domain->dcname, domain->name));
+ return False;
+ }
- if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
- return NT_STATUS_NO_MEMORY;
-
- ZERO_STRUCTP(conn);
-
- if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
- DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
- domain->name, pipe_name, nt_errstr(result)));
- SAFE_FREE(conn);
- return result;
+ if (!domain->conn.cli->initialised) {
+ DEBUG(3, ("Connection to %s for domain %s was never "
+ "initialised!\n", domain->dcname, domain->name));
+ return False;
}
- DLIST_ADD(cm_conns, conn);
- *conn_out = conn;
- return NT_STATUS_OK;
-}
+ if (domain->conn.cli->fd == -1) {
+ DEBUG(3, ("Connection to %s for domain %s has died or was "
+ "never started (fd == -1)\n",
+ domain->dcname, domain->name));
+ return False;
+ }
-/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
+ return True;
+}
+
+/* Initialize a new connection up to the RPC BIND. */
-static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
- struct winbindd_cm_conn **conn_out)
+static NTSTATUS init_dc_connection(struct winbindd_domain *domain)
{
- find_cm_connection(domain, pipe_name, conn_out);
-
- if (*conn_out != NULL)
+ if (connection_ok(domain))
return NT_STATUS_OK;
- return new_cm_connection(domain, pipe_name, conn_out);
+ invalidate_cm_connection(&domain->conn);
+
+ return cm_open_connection(domain, &domain->conn);
}
/**********************************************************************************
@@ -806,11 +836,15 @@ static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const
void set_dc_type_and_flags( struct winbindd_domain *domain )
{
NTSTATUS result;
- struct winbindd_cm_conn conn;
DS_DOMINFO_CTR ctr;
TALLOC_CTX *mem_ctx = NULL;
+ struct rpc_pipe_client *cli;
+ POLICY_HND pol;
- ZERO_STRUCT( conn );
+ char *domain_name = NULL;
+ char *dns_name = NULL;
+ DOM_SID *dom_sid = NULL;
+
ZERO_STRUCT( ctr );
domain->native_mode = False;
@@ -820,100 +854,100 @@ void set_dc_type_and_flags( struct winbindd_domain *domain )
domain->initialized = True;
return;
}
-
- if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
- DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
+
+ result = init_dc_connection(domain);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("set_dc_type_and_flags: Could not open a connection "
+ "to %s: (%s)\n", domain->name, nt_errstr(result)));
+ domain->initialized = True;
+ return;
+ }
+
+ cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC_DS);
+
+ if (cli == NULL) {
+ DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
+ "PI_LSARPC_DS on domain %s: (%s)\n",
domain->name, nt_errstr(result)));
domain->initialized = True;
return;
}
-
- if ( conn.cli ) {
- if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
- conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
- goto done;
- }
+
+ result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
+ DsRolePrimaryDomainInfoBasic,
+ &ctr);
+ cli_rpc_close(cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ domain->initialized = True;
+ return;
}
-
- if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING)
- && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
+
+ if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
+ !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
domain->native_mode = True;
- /* Cheat - shut down the DS pipe, and open LSA */
+ cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC);
- cli_nt_session_close(conn.cli);
-
- if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
- char *domain_name = NULL;
- char *dns_name = NULL;
- DOM_SID *dom_sid = NULL;
+ if (cli == NULL) {
+ domain->initialized = True;
+ return;
+ }
- mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
- if (!mem_ctx) {
- DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
- return;
- }
+ mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
+ domain->name);
+ if (!mem_ctx) {
+ DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
+ return;
+ }
- result = cli_lsa_open_policy2(conn.cli, mem_ctx, True,
- SEC_RIGHTS_MAXIMUM_ALLOWED,
- &conn.pol);
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
- if (NT_STATUS_IS_OK(result)) {
- /* This particular query is exactly what Win2k clients use
- to determine that the DC is active directory */
- result = cli_lsa_query_info_policy2(conn.cli, mem_ctx,
- &conn.pol,
- 12, &domain_name,
- &dns_name, NULL,
- NULL, &dom_sid);
- }
+ if (NT_STATUS_IS_OK(result)) {
+ /* This particular query is exactly what Win2k clients use
+ to determine that the DC is active directory */
+ result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
+ 12, &domain_name,
+ &dns_name, NULL,
+ NULL, &dom_sid);
+ }
+
+ if (NT_STATUS_IS_OK(result)) {
+ if (domain_name)
+ fstrcpy(domain->name, domain_name);
+
+ if (dns_name)
+ fstrcpy(domain->alt_name, dns_name);
+
+ if (dom_sid)
+ sid_copy(&domain->sid, dom_sid);
+ domain->active_directory = True;
+ } else {
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_query_info_policy(cli, mem_ctx,
+ &pol, 5, &domain_name,
+ &dom_sid);
+
if (NT_STATUS_IS_OK(result)) {
if (domain_name)
fstrcpy(domain->name, domain_name);
-
- if (dns_name)
- fstrcpy(domain->alt_name, dns_name);
if (dom_sid)
sid_copy(&domain->sid, dom_sid);
-
- domain->active_directory = True;
- } else {
-
- result = cli_lsa_open_policy(conn.cli, mem_ctx, True,
- SEC_RIGHTS_MAXIMUM_ALLOWED,
- &conn.pol);
-
- if (!NT_STATUS_IS_OK(result))
- goto done;
-
- result = cli_lsa_query_info_policy(conn.cli, mem_ctx,
- &conn.pol, 5, &domain_name,
- &dom_sid);
-
- if (NT_STATUS_IS_OK(result)) {
- if (domain_name)
- fstrcpy(domain->name, domain_name);
-
- if (dom_sid)
- sid_copy(&domain->sid, dom_sid);
- }
}
}
-
done:
-
- DEBUG(3,("add_trusted_domain: %s is an %s %s domain\n", domain->name,
- domain->active_directory ? "ADS" : "NT4",
- domain->native_mode ? "native mode" :
- ((domain->active_directory && !domain->native_mode) ? "mixed mode" : "")));
- /* close the connection; no other calls use this pipe and it is called only
- on reestablishing the domain list --jerry */
-
- if ( conn.cli )
- cli_shutdown( conn.cli );
+ cli_rpc_close(cli);
talloc_destroy(mem_ctx);
@@ -922,264 +956,278 @@ done:
return;
}
+static BOOL cm_get_schannel_key(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ unsigned char **session_key)
+{
+ struct rpc_pipe_client *cli;
+ DOM_CRED *credentials;
+ if (lp_client_schannel() == False)
+ return False;
-/* Return a LSA policy handle on a domain */
+ return NT_STATUS_IS_OK(cm_connect_netlogon(domain, mem_ctx,
+ &cli, session_key,
+ &credentials));
+}
-NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
+NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
{
struct winbindd_cm_conn *conn;
- uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
NTSTATUS result;
- static CLI_POLICY_HND hnd;
- /* Look for existing connections */
-
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
+ result = init_dc_connection(domain);
+ if (!NT_STATUS_IS_OK(result))
return result;
- /* This *shitty* code needs scrapping ! JRA */
-
- if (policy_handle_is_valid(&conn->pol)) {
- hnd.pol = conn->pol;
- hnd.cli = conn->cli;
- *return_hnd = &hnd;
+ conn = &domain->conn;
- return NT_STATUS_OK;
- }
-
- result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
- des_access, &conn->pol);
+ if (conn->samr_pipe == NULL) {
+ unsigned char *session_key;
- if (!NT_STATUS_IS_OK(result)) {
- /* Hit the cache code again. This cleans out the old connection and gets a new one */
- if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
- return result;
+ if (cm_get_schannel_key(domain, mem_ctx, &session_key))
+ conn->samr_pipe = cli_rpc_open_schannel(conn->cli,
+ PI_SAMR,
+ session_key,
+ domain->name);
+ else
+ conn->samr_pipe = cli_rpc_open_noauth(conn->cli,
+ PI_SAMR);
- result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
- des_access, &conn->pol);
+ if (conn->samr_pipe == NULL) {
+ result = NT_STATUS_PIPE_NOT_AVAILABLE;
+ goto done;
}
- if (!NT_STATUS_IS_OK(result)) {
- cli_shutdown(conn->cli);
- DLIST_REMOVE(cm_conns, conn);
- SAFE_FREE(conn);
- return result;
- }
- }
+ result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->sam_connect_handle);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
- hnd.pol = conn->pol;
- hnd.cli = conn->cli;
+ result = rpccli_samr_open_domain(conn->samr_pipe,
+ mem_ctx,
+ &conn->sam_connect_handle,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &domain->sid,
+ &conn->sam_domain_handle);
+ }
- *return_hnd = &hnd;
+ done:
+ if (!NT_STATUS_IS_OK(result)) {
+ invalidate_cm_connection(conn);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- return NT_STATUS_OK;
+ *cli = conn->samr_pipe;
+ *sam_handle = conn->sam_domain_handle;
+ return result;
}
-/* Return a SAM policy handle on a domain */
-
-NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
-{
+NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
+{
struct winbindd_cm_conn *conn;
- uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
NTSTATUS result;
- static CLI_POLICY_HND hnd;
- /* Look for existing connections */
-
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
+ result = init_dc_connection(domain);
+ if (!NT_STATUS_IS_OK(result))
return result;
-
- /* This *shitty* code needs scrapping ! JRA */
-
- if (policy_handle_is_valid(&conn->pol)) {
- hnd.pol = conn->pol;
- hnd.cli = conn->cli;
-
- *return_hnd = &hnd;
- return NT_STATUS_OK;
- }
-
- result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
- des_access, &conn->pol);
+ conn = &domain->conn;
- if (!NT_STATUS_IS_OK(result)) {
- /* Hit the cache code again. This cleans out the old connection and gets a new one */
- if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
-
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
- return result;
+ if (conn->lsa_pipe == NULL) {
+ unsigned char *session_key;
- result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
- des_access, &conn->pol);
- }
+ if (cm_get_schannel_key(domain, mem_ctx, &session_key))
+ conn->lsa_pipe = cli_rpc_open_schannel(conn->cli,
+ PI_LSARPC,
+ session_key,
+ domain->name);
+ else
+ conn->lsa_pipe = cli_rpc_open_noauth(conn->cli,
+ PI_LSARPC);
- if (!NT_STATUS_IS_OK(result)) {
-
- cli_shutdown(conn->cli);
- DLIST_REMOVE(cm_conns, conn);
- SAFE_FREE(conn);
-
- /* log a message for possible Windows 2003 SP1 DC's */
- if ( NT_STATUS_EQUAL(result,NT_STATUS_ACCESS_DENIED) && (lp_security() == SEC_DOMAIN) ) {
- DEBUG(0,("samr_connect() received NT_STATUS_ACCESS_DENIED. If you are connecting \n"));
- DEBUGADD(0,("to a Windows 2003 SP1 DC, this is a known issue. There are two current \n"));
- DEBUGADD(0,("workarounds:\n"));
- DEBUGADD(0,("(a) Move your configuration to security = ads, or\n"));
- DEBUGADD(0,("(b) set 'client schannel = no' in smb.conf and use 'wbinfo --set-auth-user'\n"));
- DEBUGADD(0,(" to define the credentials when connecting to the DC\n"));
- }
-
- return result;
+ if (conn->lsa_pipe == NULL) {
+ result = NT_STATUS_PIPE_NOT_AVAILABLE;
+ goto done;
}
- }
- hnd.pol = conn->pol;
- hnd.cli = conn->cli;
+ result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->lsa_policy);
+ }
- *return_hnd = &hnd;
+ done:
+ if (!NT_STATUS_IS_OK(result)) {
+ invalidate_cm_connection(conn);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- return NT_STATUS_OK;
+ *cli = conn->lsa_pipe;
+ *lsa_policy = conn->lsa_policy;
+ return result;
}
-/* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
- netlogon pipe as no handle is returned. */
+/*******************************************************************
+ wrapper around retrieving the trust account password
+*******************************************************************/
-NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain,
- const unsigned char *trust_passwd,
- uint32 sec_channel_type,
- BOOL fresh,
- struct cli_state **cli)
+static BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
+ uint32 *channel)
{
- NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
- struct winbindd_cm_conn *conn;
- fstring lock_name;
- BOOL got_mutex;
-
- if (!cli)
- return NT_STATUS_INVALID_PARAMETER;
+ DOM_SID sid;
+ char *pwd;
+ time_t last_set_time;
- /* Open an initial conection - keep the mutex. */
+ /* if we are a DC and this is not our domain, then lookup an account
+ for the domain trust */
- find_cm_connection(domain, PIPE_NETLOGON, &conn);
+ if ( IS_DC && !strequal(domain, lp_workgroup()) &&
+ lp_allow_trusted_domains() ) {
- if ( fresh && (conn != NULL) ) {
- cli_shutdown(conn->cli);
- conn->cli = NULL;
+ if (!secrets_fetch_trusted_domain_password(domain, &pwd, &sid,
+ &last_set_time)) {
+ DEBUG(0, ("get_trust_pw: could not fetch trust "
+ "account password for trusted domain %s\n",
+ domain));
+ return False;
+ }
- conn = NULL;
+ *channel = SEC_CHAN_DOMAIN;
+ E_md4hash(pwd, ret_pwd);
+ SAFE_FREE(pwd);
- /* purge connection from cache */
- find_cm_connection(domain, PIPE_NETLOGON, &conn);
- if (conn != NULL) {
- DEBUG(0,("Could not purge connection\n"));
- return NT_STATUS_UNSUCCESSFUL;
- }
+ return True;
}
- if (conn != NULL) {
- *cli = conn->cli;
- return NT_STATUS_OK;
- }
+ /* Just get the account for the requested domain. In the future this
+ * might also cover to be member of more than one domain. */
- result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
+ if (secrets_fetch_trust_account_password(domain, ret_pwd,
+ &last_set_time, channel))
+ return True;
- if (!NT_STATUS_IS_OK(result))
- return result;
-
- fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
+ DEBUG(5, ("get_trust_pw: could not fetch trust account "
+ "password for domain %s\n", domain));
+ return False;
+}
- if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
- DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
- }
-
- if ( sec_channel_type == SEC_CHAN_DOMAIN )
- fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
-
- /* This must be the remote domain (not ours) for schannel */
+NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli,
+ unsigned char **session_key,
+ DOM_CRED **credentials)
+{
+ struct winbindd_cm_conn *conn;
+ NTSTATUS result;
- fstrcpy( conn->cli->domain, domain->name);
-
- result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
-
- if (got_mutex)
- secrets_named_mutex_release(lock_name);
-
- if (!NT_STATUS_IS_OK(result)) {
- cli_shutdown(conn->cli);
- DLIST_REMOVE(cm_conns, conn);
- SAFE_FREE(conn);
+ uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
+ uint8 mach_pwd[16];
+ uint32 sec_chan_type;
+ DOM_CHAL clnt_chal, srv_chal, rcv_chal;
+ const char *server_name;
+ const char *account_name;
+ UTIME zerotime;
+
+ result = init_dc_connection(domain);
+ if (!NT_STATUS_IS_OK(result))
return result;
- }
- *cli = conn->cli;
+ conn = &domain->conn;
- return result;
-}
+ if (conn->netlogon_pipe != NULL) {
+ *cli = conn->netlogon_pipe;
+ *session_key = (unsigned char *)&conn->sess_key;
+ *credentials = &conn->clnt_cred;
+ return NT_STATUS_OK;
+ }
-/* Dump the current connection status */
+ if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type))
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-static void dump_conn_list(void)
-{
- struct winbindd_cm_conn *con;
+ conn->netlogon_auth2_pipe = cli_rpc_open_noauth(conn->cli,
+ PI_NETLOGON);
+ if (conn->netlogon_auth2_pipe == NULL)
+ return NT_STATUS_UNSUCCESSFUL;
- DEBUG(0, ("\tDomain Controller Pipe\n"));
+ if (lp_client_schannel() != False)
+ neg_flags |= NETLOGON_NEG_SCHANNEL;
- for(con = cm_conns; con; con = con->next) {
- char *msg;
+ generate_random_buffer(clnt_chal.data, 8);
- /* Display pipe info */
-
- if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
- DEBUG(0, ("Error: not enough memory!\n"));
- } else {
- DEBUG(0, ("%s\n", msg));
- SAFE_FREE(msg);
- }
- }
-}
+ server_name = talloc_asprintf(mem_ctx, "\\\\%s", domain->dcname);
+ account_name = talloc_asprintf(mem_ctx, "%s$",
+ domain->primary ?
+ global_myname() : domain->name);
-void winbindd_cm_status(void)
-{
- /* List open connections */
+ if ((server_name == NULL) || (account_name == NULL))
+ return NT_STATUS_NO_MEMORY;
- DEBUG(0, ("winbindd connection manager status:\n"));
+ result = rpccli_net_req_chal(conn->netlogon_auth2_pipe, server_name,
+ global_myname(), &clnt_chal, &srv_chal);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- if (cm_conns)
- dump_conn_list();
- else
- DEBUG(0, ("\tNo active connections\n"));
-}
+ /**************** Long-term Session key **************/
-/* Close all cached connections */
+ /* calculate the session key */
+ cred_session_key(&clnt_chal, &srv_chal, mach_pwd, conn->sess_key);
+ memset((char *)conn->sess_key+8, '\0', 8);
-void winbindd_cm_flush(void)
-{
- struct winbindd_cm_conn *conn, tmp;
+ /* calculate auth2 credentials */
+ zerotime.time = 0;
+ cred_create(conn->sess_key, &clnt_chal, zerotime,
+ &conn->clnt_cred.challenge);
- /* Flush connection cache */
+ result = rpccli_net_auth2(conn->netlogon_auth2_pipe, server_name,
+ account_name, sec_chan_type, global_myname(),
+ &conn->clnt_cred.challenge, &neg_flags,
+ &rcv_chal);
- for (conn = cm_conns; conn; conn = conn->next) {
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- if (!connection_ok(conn))
- continue;
+ zerotime.time = 0;
+ if (!cred_assert(&rcv_chal, conn->sess_key, &srv_chal, zerotime)) {
+ DEBUG(0, ("Server replied with bad credential\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
- DEBUG(10, ("Closing connection to %s on %s\n",
- conn->pipe_name, conn->controller));
+ if ((lp_client_schannel() == True) &&
+ ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+ DEBUG(3, ("Server did not offer schannel\n"));
+ cli_rpc_close(conn->netlogon_auth2_pipe);
+ conn->netlogon_auth2_pipe = NULL;
+ return NT_STATUS_ACCESS_DENIED;
+ }
- if (conn->cli)
- cli_shutdown(conn->cli);
+ if ((lp_client_schannel() == False) ||
+ ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+ /* keep the existing connection to NETLOGON open */
+ conn->netlogon_pipe = conn->netlogon_auth2_pipe;
+ conn->netlogon_auth2_pipe = NULL;
+ *cli = conn->netlogon_pipe;
+ *session_key = (unsigned char *)&conn->sess_key;
+ *credentials = &conn->clnt_cred;
+ return NT_STATUS_OK;
+ }
- tmp.next = conn->next;
+ conn->netlogon_pipe = cli_rpc_open_schannel(conn->cli, PI_NETLOGON,
+ conn->sess_key,
+ domain->name);
- DLIST_REMOVE(cm_conns, conn);
- SAFE_FREE(conn);
- conn = &tmp;
+ if (conn->netlogon_pipe == NULL) {
+ DEBUG(3, ("Could not open schannel'ed NETLOGON pipe\n"));
+ cli_rpc_close(conn->netlogon_auth2_pipe);
+ conn->netlogon_auth2_pipe = NULL;
+ return NT_STATUS_ACCESS_DENIED;
}
- /* Flush failed connection cache */
-
- flush_negative_conn_cache();
+ *cli = conn->netlogon_pipe;
+ *session_key = (unsigned char *)&conn->sess_key;
+ *credentials = &conn->clnt_cred;
+
+ return NT_STATUS_OK;
}
diff --git a/source3/nsswitch/winbindd_dual.c b/source3/nsswitch/winbindd_dual.c
index 587507ee29..f8b802dafa 100644
--- a/source3/nsswitch/winbindd_dual.c
+++ b/source3/nsswitch/winbindd_dual.c
@@ -4,6 +4,7 @@
Winbind background daemon
Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Volker Lendecke 2004,2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -51,6 +52,39 @@ struct dual_list {
static struct dual_list *dual_list;
static struct dual_list *dual_list_end;
+/* Read some data from a client connection */
+
+static void dual_client_read(struct winbindd_cli_state *state)
+{
+ int n;
+
+ /* Read data */
+
+ n = sys_read(state->sock, state->read_buf_len +
+ (char *)&state->request,
+ sizeof(state->request) - state->read_buf_len);
+
+ DEBUG(10,("client_read: read %d bytes. Need %ld more for a full "
+ "request.\n", n, (unsigned long)(sizeof(state->request) - n -
+ state->read_buf_len) ));
+
+ /* Read failed, kill client */
+
+ if (n == -1 || n == 0) {
+ DEBUG(5,("read failed on sock %d, pid %lu: %s\n",
+ state->sock, (unsigned long)state->pid,
+ (n == -1) ? strerror(errno) : "EOF"));
+
+ state->finished = True;
+ return;
+ }
+
+ /* Update client state */
+
+ state->read_buf_len += n;
+ state->last_access = time(NULL);
+}
+
/*
setup a select() including the dual daemon pipe
*/
@@ -176,7 +210,7 @@ void do_dual_daemon(void)
main_loop_talloc_free();
/* fetch a request from the main daemon */
- winbind_client_read(&state);
+ dual_client_read(&state);
if (state.finished) {
/* we lost contact with our parent */
@@ -212,3 +246,412 @@ void do_dual_daemon(void)
}
}
+/*
+ * Machinery for async requests sent to children. You set up a
+ * winbindd_request, select a child to query, and issue a async_request
+ * call. When the request is completed, the callback function you specified is
+ * called back with the private pointer you gave to async_request.
+ */
+
+struct winbindd_async_request {
+ struct winbindd_async_request *next, *prev;
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_child *child;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ void (*continuation)(void *private, BOOL success);
+ void *private;
+};
+
+static void async_request_sent(void *private, BOOL success);
+static void async_reply_recv(void *private, BOOL success);
+static void schedule_async_request(struct winbindd_child *child);
+
+void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ void (*continuation)(void *private, BOOL success),
+ void *private)
+{
+ struct winbindd_async_request *state, *tmp;
+
+ SMB_ASSERT(continuation != NULL);
+
+ state = TALLOC_P(mem_ctx, struct winbindd_async_request);
+
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ continuation(private, False);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->child = child;
+ state->request = request;
+ state->response = response;
+ state->continuation = continuation;
+ state->private = private;
+
+ DLIST_ADD_END(child->requests, state, tmp);
+
+ schedule_async_request(child);
+
+ return;
+}
+
+static void async_request_sent(void *private, BOOL success)
+{
+ struct winbindd_async_request *state =
+ talloc_get_type_abort(private, struct winbindd_async_request);
+
+ if (!success) {
+ DEBUG(5, ("Could not send async request\n"));
+
+ state->response->length = sizeof(struct winbindd_response);
+ state->response->result = WINBINDD_ERROR;
+ state->continuation(state->private, False);
+ return;
+ }
+
+ /* Request successfully sent to the child, setup the wait for reply */
+
+ setup_async_read(&state->child->event,
+ &state->response->result,
+ sizeof(state->response->result),
+ async_reply_recv, state);
+}
+
+static void async_reply_recv(void *private, BOOL success)
+{
+ struct winbindd_async_request *state =
+ talloc_get_type_abort(private, struct winbindd_async_request);
+ struct winbindd_child *child = state->child;
+
+ state->response->length = sizeof(struct winbindd_response);
+
+ if (!success) {
+ DEBUG(5, ("Could not receive async reply\n"));
+ state->response->result = WINBINDD_ERROR;
+ }
+
+ if (state->response->result == WINBINDD_OK)
+ SMB_ASSERT(cache_retrieve_response(child->pid,
+ state->response));
+
+ DLIST_REMOVE(child->requests, state);
+
+ schedule_async_request(child);
+
+ state->continuation(state->private, True);
+}
+
+static BOOL fork_domain_child(struct winbindd_child *child);
+
+static void schedule_async_request(struct winbindd_child *child)
+{
+ struct winbindd_async_request *request = child->requests;
+
+ if (request == NULL) {
+ return;
+ }
+
+ if (child->event.flags != 0) {
+ return; /* Busy */
+ }
+
+ if ((child->pid == 0) && (!fork_domain_child(child))) {
+ /* Cancel all outstanding requests */
+
+ while (request != NULL) {
+ /* request might be free'd in the continuation */
+ struct winbindd_async_request *next = request->next;
+ request->continuation(request->private, False);
+ request = next;
+ }
+ return;
+ }
+
+ setup_async_write(&child->event, request->request,
+ sizeof(*request->request),
+ async_request_sent, request);
+ return;
+}
+
+struct domain_request_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_domain *domain;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ void (*continuation)(void *private, BOOL success);
+ void *private;
+};
+
+static void domain_init_recv(void *private, BOOL success);
+
+void async_domain_request(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ void (*continuation)(void *private, BOOL success),
+ void *private)
+{
+ struct domain_request_state *state;
+
+ if (domain->initialized) {
+ async_request(mem_ctx, &domain->child, request, response,
+ continuation, private);
+ return;
+ }
+
+ state = TALLOC_P(mem_ctx, struct domain_request_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ continuation(private, False);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->domain = domain;
+ state->request = request;
+ state->response = response;
+ state->continuation = continuation;
+ state->private = private;
+
+ init_child_connection(domain, domain_init_recv, state);
+}
+
+static void domain_init_recv(void *private, BOOL success)
+{
+ struct domain_request_state *state =
+ talloc_get_type_abort(private, struct domain_request_state);
+
+ if (!success) {
+ DEBUG(5, ("Domain init returned an error\n"));
+ state->continuation(state->private, False);
+ return;
+ }
+
+ async_request(state->mem_ctx, &state->domain->child,
+ state->request, state->response,
+ state->continuation, state->private);
+}
+
+struct winbindd_child_dispatch_table {
+ enum winbindd_cmd cmd;
+ enum winbindd_result (*fn)(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+ const char *winbindd_cmd_name;
+};
+
+static struct winbindd_child_dispatch_table child_dispatch_table[] = {
+
+ { WINBINDD_LOOKUPSID, winbindd_dual_lookupsid, "LOOKUPSID" },
+ { WINBINDD_LOOKUPNAME, winbindd_dual_lookupname, "LOOKUPNAME" },
+ { WINBINDD_LIST_TRUSTDOM, winbindd_dual_list_trusted_domains,
+ "LIST_TRUSTDOM" },
+ { WINBINDD_INIT_CONNECTION, winbindd_dual_init_connection,
+ "INIT_CONNECTION" },
+ { WINBINDD_GETDCNAME, winbindd_dual_getdcname, "GETDCNAME" },
+ { WINBINDD_SHOW_SEQUENCE, winbindd_dual_show_sequence,
+ "SHOW_SEQUENCE" },
+ { WINBINDD_PAM_AUTH, winbindd_dual_pam_auth, "PAM_AUTH" },
+ { WINBINDD_PAM_AUTH_CRAP, winbindd_dual_pam_auth_crap, "AUTH_CRAP" },
+ { WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct,
+ "CHECK_MACHACC" },
+ { WINBINDD_DUAL_SID2UID, winbindd_dual_sid2uid, "DUAL_SID2UID" },
+ { WINBINDD_DUAL_SID2GID, winbindd_dual_sid2gid, "DUAL_SID2GID" },
+ { WINBINDD_DUAL_UID2NAME, winbindd_dual_uid2name, "DUAL_UID2NAME" },
+ { WINBINDD_DUAL_NAME2UID, winbindd_dual_name2uid, "DUAL_NAME2UID" },
+ { WINBINDD_DUAL_GID2NAME, winbindd_dual_gid2name, "DUAL_GID2NAME" },
+ { WINBINDD_DUAL_NAME2GID, winbindd_dual_name2gid, "DUAL_NAME2GID" },
+ { WINBINDD_DUAL_IDMAPSET, winbindd_dual_idmapset, "DUAL_IDMAPSET" },
+ { WINBINDD_DUAL_USERINFO, winbindd_dual_userinfo, "DUAL_USERINFO" },
+ { WINBINDD_ALLOCATE_RID, winbindd_dual_allocate_rid, "ALLOCATE_RID" },
+ { WINBINDD_ALLOCATE_RID_AND_GID, winbindd_dual_allocate_rid_and_gid,
+ "ALLOCATE_RID_AND_GID" },
+ { WINBINDD_GETUSERDOMGROUPS, winbindd_dual_getuserdomgroups,
+ "GETUSERDOMGROUPS" },
+ { WINBINDD_DUAL_GETSIDALIASES, winbindd_dual_getsidaliases,
+ "GETSIDALIASES" },
+ /* End of list */
+
+ { WINBINDD_NUM_CMDS, NULL, "NONE" }
+};
+
+static void child_process_request(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct winbindd_child_dispatch_table *table;
+
+ /* Free response data - we may be interrupted and receive another
+ command before being able to send this data off. */
+
+ state->response.result = WINBINDD_ERROR;
+ state->response.length = sizeof(struct winbindd_response);
+
+ state->mem_ctx = talloc_init("winbind request");
+ if (state->mem_ctx == NULL)
+ return;
+
+ /* Process command */
+
+ for (table = child_dispatch_table; table->fn; table++) {
+ if (state->request.cmd == table->cmd) {
+ DEBUG(10,("process_request: request fn %s\n",
+ table->winbindd_cmd_name ));
+ state->response.result = table->fn(domain, state);
+ break;
+ }
+ }
+
+ if (!table->fn) {
+ DEBUG(10,("process_request: unknown request fn number %d\n",
+ (int)state->request.cmd ));
+ state->response.result = WINBINDD_ERROR;
+ }
+
+ talloc_destroy(state->mem_ctx);
+}
+
+void setup_domain_child(struct winbindd_domain *domain,
+ struct winbindd_child *child,
+ const char *explicit_logfile)
+{
+ if (explicit_logfile != NULL) {
+ pstr_sprintf(child->logfilename, "%s/log.winbindd-%s",
+ dyn_LOGFILEBASE, explicit_logfile);
+ } else if (domain != NULL) {
+ pstr_sprintf(child->logfilename, "%s/log.wb-%s",
+ dyn_LOGFILEBASE, domain->name);
+ } else {
+ smb_panic("Internal error: domain == NULL && "
+ "explicit_logfile == NULL");
+ }
+
+ child->domain = domain;
+}
+
+struct winbindd_child *children = NULL;
+
+void winbind_child_died(pid_t pid)
+{
+ struct winbindd_child *child;
+
+ for (child = children; child != NULL; child = child->next) {
+ if (child->pid == pid) {
+ break;
+ }
+ }
+
+ if (child == NULL) {
+ DEBUG(0, ("Unknown child %d died!\n", pid));
+ return;
+ }
+
+ remove_fd_event(&child->event);
+ close(child->event.fd);
+ child->event.fd = 0;
+ child->event.flags = 0;
+ child->pid = 0;
+
+ schedule_async_request(child);
+}
+
+static BOOL fork_domain_child(struct winbindd_child *child)
+{
+ int fdpair[2];
+ struct winbindd_cli_state state;
+ extern BOOL override_logfile;
+
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fdpair) != 0) {
+ DEBUG(0, ("Could not open child pipe: %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ ZERO_STRUCT(state);
+ state.pid = getpid();
+
+ child->pid = sys_fork();
+
+ if (child->pid == -1) {
+ DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
+ return False;
+ }
+
+ if (child->pid != 0) {
+ /* Parent */
+ close(fdpair[0]);
+ child->next = child->prev = NULL;
+ DLIST_ADD(children, child);
+ child->event.fd = fdpair[1];
+ child->event.flags = 0;
+ child->requests = NULL;
+ add_fd_event(&child->event);
+ return True;
+ }
+
+ /* Child */
+
+ state.sock = fdpair[0];
+ close(fdpair[1]);
+
+ /* tdb needs special fork handling */
+ if (tdb_reopen_all() == -1) {
+ DEBUG(0,("tdb_reopen_all failed.\n"));
+ _exit(0);
+ }
+
+ close_conns_after_fork();
+
+ if (!override_logfile) {
+ lp_set_logfile(child->logfilename);
+ reopen_logs();
+ }
+
+ dual_daemon_pipe = -1;
+ opt_dual_daemon = False;
+
+ while (1) {
+ /* free up any talloc memory */
+ lp_talloc_free();
+ main_loop_talloc_free();
+
+ /* fetch a request from the main daemon */
+ dual_client_read(&state);
+
+ if (state.finished) {
+ /* we lost contact with our parent */
+ exit(0);
+ }
+
+ /* process full rquests */
+ if (state.read_buf_len == sizeof(state.request)) {
+ DEBUG(4,("child daemon request %d\n",
+ (int)state.request.cmd));
+
+ state.request.null_term = '\0';
+ child_process_request(child->domain, &state);
+
+ if (state.response.result == WINBINDD_OK)
+ cache_store_response(sys_getpid(),
+ &state.response);
+
+ SAFE_FREE(state.response.extra_data);
+
+ /* We just send the result code back, the result
+ * structure needs to be fetched via the
+ * winbindd_cache. Hmm. That needs fixing... */
+
+ if (write_data(state.sock,
+ (void *)&state.response.result,
+ sizeof(state.response.result)) !=
+ sizeof(state.response.result)) {
+ DEBUG(0, ("Could not write result\n"));
+ exit(1);
+ }
+
+ state.read_buf_len = 0;
+ }
+ }
+}
diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c
index c431e32cc1..1138762cc4 100644
--- a/source3/nsswitch/winbindd_group.c
+++ b/source3/nsswitch/winbindd_group.c
@@ -61,7 +61,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
enum SID_NAME_USE group_name_type,
int *num_gr_mem, char **gr_mem, int *gr_mem_len)
{
- DOM_SID **sid_mem = NULL;
+ DOM_SID *sid_mem = NULL;
uint32 num_names = 0;
uint32 *name_types = NULL;
unsigned int buf_len, buf_ndx, i;
@@ -112,7 +112,8 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
if (DEBUGLEVEL >= 10) {
for (i = 0; i < num_names; i++)
- DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
+ DEBUG(10, ("\t%20s %s %d\n", names[i],
+ sid_string_static(&sid_mem[i]),
name_types[i]));
}
@@ -222,7 +223,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
parse_domain_user(tmp, name_domain, name_group);
- /* if no domain or our local domain, default to our local domain for aliases */
+ /* if no domain or our local domain and no local tdb group, default to
+ * our local domain for aliases */
if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
fstrcpy(name_domain, get_global_sam_name());
@@ -245,8 +247,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
/* Get rid and name type from name */
- if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid,
- &name_type)) {
+ if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
+ name_group, &group_sid, &name_type)) {
DEBUG(1, ("group %s in domain %s does not exist\n",
name_group, name_domain));
return WINBINDD_ERROR;
@@ -306,7 +308,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
return WINBINDD_ERROR;
/* Get rid from gid */
- if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
+ if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid, 0))) {
DEBUG(1, ("could not convert gid %lu to rid\n",
(unsigned long)state->request.data.gid));
return WINBINDD_ERROR;
@@ -314,14 +316,15 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
/* Get name from sid */
- if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
+ if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
+ group_name, &name_type)) {
DEBUG(1, ("could not lookup sid\n"));
return WINBINDD_ERROR;
}
/* Fill in group structure */
- domain = find_domain_from_sid(&group_sid);
+ domain = find_domain_from_sid_noinit(&group_sid);
if (!domain) {
DEBUG(1,("Can't find domain from sid\n"));
@@ -793,10 +796,6 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
if ( *which_domain && !strequal(which_domain, domain->name) )
continue;
-
- if ( !domain->initialized )
- set_dc_type_and_flags( domain );
-
ZERO_STRUCT(groups);
@@ -856,323 +855,155 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
-static BOOL enum_alias_memberships(const DOM_SID *member_sid,
- DOM_SID **aliases, int *num_aliases)
-{
- TALLOC_CTX *mem_ctx = talloc_init("enum_alias_memberships");
-
- uint32 *rids = NULL;
- int i, num_rids = 0;
-
- BOOL result = False;
-
- if (mem_ctx == NULL)
- return False;
-
- *aliases = NULL;
- *num_aliases = 0;
-
- if (!pdb_enum_alias_memberships(mem_ctx, get_global_sam_sid(),
- member_sid, 1, &rids, &num_rids))
- goto done;
-
- for (i=0; i<num_rids; i++) {
- DOM_SID alias_sid;
- sid_copy(&alias_sid, get_global_sam_sid());
- sid_append_rid(&alias_sid, rids[i]);
- add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
- }
-
- if (!pdb_enum_alias_memberships(mem_ctx, &global_sid_Builtin,
- member_sid, 1, &rids, &num_rids))
- goto done;
-
- for (i=0; i<num_rids; i++) {
- DOM_SID alias_sid;
- sid_copy(&alias_sid, &global_sid_Builtin);
- sid_append_rid(&alias_sid, rids[i]);
- add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
- }
-
- result = True;
- done:
- if (mem_ctx != NULL)
- talloc_destroy(mem_ctx);
-
- return result;
-}
-
-static void add_local_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
-{
- gid_t gid;
- DOM_SID *aliases;
- int j, num_aliases;
-
- DEBUG(10, ("Adding local gids from SID: %s\n",
- sid_string_static(sid)));
-
- /* Don't expand aliases if not explicitly activated -- for now
- -- jerry */
-
- if (!lp_winbind_nested_groups())
- return;
-
- /* Add nested group memberships */
-
- if (!enum_alias_memberships(sid, &aliases, &num_aliases))
- return;
-
- for (j=0; j<num_aliases; j++) {
- enum SID_NAME_USE type;
-
- if (!local_sid_to_gid(&gid, &aliases[j], &type)) {
- DEBUG(1, ("Got an alias membership with no alias\n"));
- continue;
- }
-
- if ((type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) {
- DEBUG(1, ("Got an alias membership in a non-alias\n"));
- continue;
- }
-
- add_gid_to_array_unique(NULL, gid, gids, num);
- }
- SAFE_FREE(aliases);
-}
-
-static void add_gids_from_user_sid(DOM_SID *sid, gid_t **gids, int *num)
-{
- DEBUG(10, ("Adding gids from user SID: %s\n",
- sid_string_static(sid)));
-
- add_local_gids_from_sid(sid, gids, num);
-}
-
-static void add_gids_from_group_sid(DOM_SID *sid, gid_t **gids, int *num)
-{
- gid_t gid;
-
- DEBUG(10, ("Adding gids from group SID: %s\n",
- sid_string_static(sid)));
-
- if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0)))
- add_gid_to_array_unique(NULL, gid, gids, num);
-
- add_local_gids_from_sid(sid, gids, num);
-}
-
/* Get user supplementary groups. This is much quicker than trying to
invert the groups database. We merge the groups from the gids and
other_sids info3 fields as trusted domain, universal group
memberships, and nested groups (win2k native mode only) are not
returned by the getgroups RPC call but are present in the info3. */
+struct getgroups_state {
+ struct winbindd_cli_state *state;
+ struct winbindd_domain *domain;
+ char *domname;
+ char *username;
+ DOM_SID user_sid;
+
+ const DOM_SID *token_sids;
+ int i, num_token_sids;
+
+ gid_t *token_gids;
+ int num_token_gids;
+};
+
+static void getgroups_usersid_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type);
+static void getgroups_tokensids_recv(void *private, BOOL success,
+ DOM_SID *token_sids, int num_token_sids);
+static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid);
+
enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
{
- fstring name_domain, name_user;
- DOM_SID user_sid, group_sid;
- enum SID_NAME_USE name_type;
- uint32 num_groups = 0;
- uint32 num_gids = 0;
- NTSTATUS status;
- DOM_SID **user_grpsids;
- struct winbindd_domain *domain;
- enum winbindd_result result = WINBINDD_ERROR;
- gid_t *gid_list = NULL;
- unsigned int i;
- TALLOC_CTX *mem_ctx;
- NET_USER_INFO_3 *info3 = NULL;
-
+ struct getgroups_state *s;
+
/* Ensure null termination */
- state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+ state->request.data.username
+ [sizeof(state->request.data.username)-1]='\0';
DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
state->request.data.username));
- if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
- state->request.data.username)))
- return WINBINDD_ERROR;
-
/* Parse domain and username */
- parse_domain_user(state->request.data.username,
- name_domain, name_user);
-
- /* Get info for the domain */
-
- if ((domain = find_domain_from_name(name_domain)) == NULL) {
- DEBUG(7, ("could not find domain entry for domain %s\n",
- name_domain));
- goto done;
+ s = TALLOC_P(state->mem_ctx, struct getgroups_state);
+ if (s == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return WINBINDD_ERROR;
}
- if ( domain->primary && lp_winbind_trusted_domains_only()) {
- DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
- "getgroups() for %s\\%s.\n", name_domain, name_user));
+ s->state = state;
+
+ if (!parse_domain_user_talloc(state->mem_ctx,
+ state->request.data.username,
+ &s->domname, &s->username)) {
+ DEBUG(0, ("Could not parse domain user: %s\n",
+ state->request.data.username));
return WINBINDD_ERROR;
- }
+ }
- /* Get rid and name type from name. The following costs 1 packet */
+ /* Get info for the domain */
- if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid,
- &name_type)) {
- DEBUG(4, ("user '%s' does not exist\n", name_user));
- goto done;
- }
+ s->domain = find_domain_from_name_noinit(s->domname);
- if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) {
- DEBUG(1, ("name '%s' is not a user name: %d\n",
- name_user, name_type));
- goto done;
+ if (s->domain == NULL) {
+ DEBUG(7, ("could not find domain entry for domain %s\n",
+ s->domname));
+ return WINBINDD_ERROR;
}
- add_gids_from_user_sid(&user_sid, &gid_list, &num_gids);
-
- /* Treat the info3 cache as authoritative as the
- lookup_usergroups() function may return cached data. */
-
- if ( !opt_nocache && (info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) {
-
- struct winbindd_domain *our_domain = find_our_domain();
-
- if (our_domain == NULL) {
- DEBUG(0, ("Could not find our domain\n"));
- goto done;
- }
-
- DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n",
- info3->num_groups2, info3->num_other_sids));
-
- num_groups = info3->num_other_sids + info3->num_groups2;
-
- /* Go through each other sid and convert it to a gid */
-
- for (i = 0; i < info3->num_other_sids; i++) {
- DOM_SID *sid = &info3->other_sids[i].sid;
- fstring name;
- fstring dom_name;
- enum SID_NAME_USE sid_type;
-
- /* Is this sid known to us? It can either be
- a trusted domain sid or a foreign sid. */
-
- if (!winbindd_lookup_name_by_sid( sid, dom_name,
- name, &sid_type)) {
- DEBUG(10, ("winbindd_getgroups: could not "
- "lookup name for %s\n",
- sid_string_static(sid)));
- continue;
- }
-
- /* Check it is a domain group or an alias (domain
- local group) in a win2k native mode domain. */
-
- if (!((sid_type==SID_NAME_DOM_GRP) ||
- ((sid_type==SID_NAME_ALIAS) &&
- (our_domain->active_directory) &&
- (our_domain->native_mode) &&
- (sid_compare_domain(sid, &our_domain->sid)
- == 0)))) {
- DEBUG(10, ("winbindd_getgroups: sid type %d "
- "for %s is not a domain group\n",
- sid_type, sid_string_static(sid)));
- continue;
- }
-
- add_gids_from_group_sid(sid, &gid_list, &num_gids);
- }
-
- for (i = 0; i < info3->num_groups2; i++) {
-
- /* create the group SID */
-
- sid_copy( &group_sid, &domain->sid );
- sid_append_rid( &group_sid, info3->gids[i].g_rid );
-
- add_gids_from_group_sid(&group_sid, &gid_list,
- &num_gids);
- }
+ if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
+ DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
+ "getgroups() for %s\\%s.\n", s->domname,
+ s->username));
+ return WINBINDD_ERROR;
+ }
- SAFE_FREE(info3);
+ /* Get rid and name type from name. The following costs 1 packet */
- } else {
- status = domain->methods->lookup_usergroups(domain, mem_ctx,
- &user_sid, &num_groups,
- &user_grpsids);
- if (!NT_STATUS_IS_OK(status))
- goto done;
+ winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
+ getgroups_usersid_recv, s);
+ return WINBINDD_PENDING;
+}
- if (state->response.extra_data)
- goto done;
+static void getgroups_usersid_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type)
+{
+ struct getgroups_state *s = private;
- for (i = 0; i < num_groups; i++) {
- add_gids_from_group_sid(user_grpsids[i],
- &gid_list, &num_gids);
- }
+ if ((!success) ||
+ ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(s->state);
+ return;
}
- /* We want at least one group... */
- if (gid_list == NULL)
- goto done;
-
- remove_duplicate_gids( &num_gids, gid_list );
-
- /* Send data back to client */
+ sid_copy(&s->user_sid, sid);
- 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:
-
- talloc_destroy(mem_ctx);
-
- return result;
+ winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
+ getgroups_tokensids_recv, s);
}
-static void add_sid_to_parray_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- DOM_SID ***sids, int *num_sids)
+static void getgroups_tokensids_recv(void *private, BOOL success,
+ DOM_SID *token_sids, int num_token_sids)
{
- int i;
+ struct getgroups_state *s = private;
- for (i=0; i<(*num_sids); i++) {
- if (sid_compare(sid, (*sids)[i]) == 0)
- return;
+ /* We need at least the user sid and the primary group in the token,
+ * otherwise it's an error */
+
+ if ((!success) || (num_token_sids < 2)) {
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(s->state);
+ return;
}
- *sids = TALLOC_REALLOC_ARRAY(mem_ctx, *sids, DOM_SID *, *num_sids+1);
+ s->token_sids = token_sids;
+ s->num_token_sids = num_token_sids;
+ s->i = 0;
- if (*sids == NULL)
- return;
+ s->token_gids = NULL;
+ s->num_token_gids = 0;
- (*sids)[*num_sids] = TALLOC_P(mem_ctx, DOM_SID);
- sid_copy((*sids)[*num_sids], sid);
- *num_sids += 1;
- return;
+ getgroups_sid2gid_recv(s, False, 0);
}
-static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
- DOM_SID ***user_grpsids,
- int *num_groups)
+static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid)
{
- DOM_SID *aliases = NULL;
- int i, num_aliases = 0;
+ struct getgroups_state *s = private;
- if (!enum_alias_memberships(sid, &aliases, &num_aliases))
- return;
+ if (success)
+ add_gid_to_array_unique(NULL, gid,
+ &s->token_gids,
+ &s->num_token_gids);
- if (num_aliases == 0)
- return;
+ if (s->i < s->num_token_sids) {
+ const DOM_SID *sid = &s->token_sids[s->i];
+ s->i += 1;
- for (i=0; i<num_aliases; i++)
- add_sid_to_parray_unique(mem_ctx, &aliases[i], user_grpsids,
- num_groups);
+ if (sid_equal(sid, &s->user_sid)) {
+ getgroups_sid2gid_recv(s, False, 0);
+ return;
+ }
- SAFE_FREE(aliases);
+ winbindd_sid2gid_async(s->state->mem_ctx, sid,
+ getgroups_sid2gid_recv, s);
+ return;
+ }
- return;
+ s->state->response.data.num_entries = s->num_token_gids;
+ s->state->response.extra_data = s->token_gids;
+ s->state->response.length += s->num_token_gids * sizeof(gid_t);
+ s->state->response.result = WINBINDD_OK;
+ request_finished(s->state);
}
/* Get user supplementary sids. This is equivalent to the
@@ -1186,106 +1017,50 @@ static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
you pass in another type of SID then you may get unpredictable
results.
*/
+
+static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
+ int num_sids);
+
enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
{
- DOM_SID user_sid;
- NTSTATUS status;
- DOM_SID **user_grpsids;
- struct winbindd_domain *domain;
- enum winbindd_result result = WINBINDD_ERROR;
- unsigned int i;
- TALLOC_CTX *mem_ctx;
- char *ret = NULL;
- uint32 num_groups;
- unsigned ofs, ret_size = 0;
+ DOM_SID *user_sid;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
- if (!string_to_sid(&user_sid, state->request.data.sid)) {
- DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
+ user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
+ if (user_sid == NULL) {
+ DEBUG(1, ("talloc failed\n"));
return WINBINDD_ERROR;
}
- if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)",
- state->request.data.username))) {
+ if (!string_to_sid(user_sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
return WINBINDD_ERROR;
}
- /* Get info for the domain */
- if ((domain = find_domain_from_sid(&user_sid)) == NULL) {
- DEBUG(0,("could not find domain entry for sid %s\n",
- sid_string_static(&user_sid)));
- goto done;
- }
-
- status = domain->methods->lookup_usergroups(domain, mem_ctx,
- &user_sid, &num_groups,
- &user_grpsids);
- if (!NT_STATUS_IS_OK(status))
- goto done;
+ winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
+ state);
+ return WINBINDD_PENDING;
+}
- if (num_groups == 0) {
- goto no_groups;
- }
+static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
+ int num_sids)
+{
+ struct winbindd_cli_state *state = private;
+ char *ret = NULL;
+ unsigned ofs, ret_size = 0;
+ int i;
- domain = find_our_domain();
+ state->response.result = WINBINDD_ERROR;
- if (domain == NULL) {
- DEBUG(0, ("Could not find our domain\n"));
+ if (!success)
goto done;
- }
-
- /* Note that I do not check for AD or its mode. XP in a real NT4
- * domain also asks for this info. -- vl */
-
- if (!IS_DC) {
- uint32 *alias_rids = NULL;
- int num_aliases;
-
- /* We need to include the user SID to expand */
- user_grpsids = TALLOC_REALLOC_ARRAY(mem_ctx, user_grpsids,
- DOM_SID *, num_groups+1);
- user_grpsids[num_groups] = &user_sid;
-
- status = domain->methods->lookup_useraliases(domain, mem_ctx,
- num_groups+1,
- user_grpsids,
- &num_aliases,
- &alias_rids);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3, ("Could not expand alias sids: %s\n",
- nt_errstr(status)));
- goto done;
- }
-
- for (i=0; i<num_aliases; i++) {
- DOM_SID sid;
- sid_copy(&sid, &domain->sid);
- sid_append_rid(&sid, alias_rids[i]);
- add_sid_to_parray_unique(mem_ctx, &sid, &user_grpsids,
- &num_groups);
- }
- }
-
- if (lp_winbind_nested_groups()) {
- int k;
- /* num_groups is changed during the loop, that's why we have
- to count down here.*/
-
- for (k=num_groups-1; k>=0; k--) {
- add_local_sids_from_sid(mem_ctx, user_grpsids[k],
- &user_grpsids, &num_groups);
- }
-
- add_local_sids_from_sid(mem_ctx, &user_sid, &user_grpsids,
- &num_groups);
- }
/* work out the response size */
- for (i = 0; i < num_groups; i++) {
- const char *s = sid_string_static(user_grpsids[i]);
+ for (i = 0; i < num_sids; i++) {
+ const char *s = sid_string_static(&sids[i]);
ret_size += strlen(s) + 1;
}
@@ -1293,22 +1068,94 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
ret = SMB_MALLOC(ret_size);
if (!ret) goto done;
ofs = 0;
- for (i = 0; i < num_groups; i++) {
- const char *s = sid_string_static(user_grpsids[i]);
+ for (i = 0; i < num_sids; i++) {
+ const char *s = sid_string_static(&sids[i]);
safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
ofs += strlen(ret+ofs) + 1;
}
-no_groups:
/* Send data back to client */
- state->response.data.num_entries = num_groups;
+ state->response.data.num_entries = num_sids;
state->response.extra_data = ret;
state->response.length += ret_size;
- result = WINBINDD_OK;
+ state->response.result = WINBINDD_OK;
done:
- talloc_destroy(mem_ctx);
+ request_finished(state);
+}
- return result;
+enum winbindd_result winbindd_getuserdomgroups(struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ struct winbindd_domain *domain;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ if (!string_to_sid(&user_sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Get info for the domain */
+ if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
+ DEBUG(0,("could not find domain entry for sid %s\n",
+ sid_string_static(&user_sid)));
+ return WINBINDD_ERROR;
+ }
+
+ async_domain_request(state->mem_ctx, domain, &state->request,
+ &state->response, request_finished_cont, state);
+ return WINBINDD_PENDING;
}
+enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ NTSTATUS status;
+
+ int i, num_groups, len, bufsize;
+ DOM_SID *groups;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ if (!string_to_sid(&user_sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
+ &user_sid, &num_groups,
+ &groups);
+ if (!NT_STATUS_IS_OK(status))
+ return WINBINDD_ERROR;
+
+ if (num_groups == 0) {
+ state->response.data.num_entries = 0;
+ state->response.extra_data = NULL;
+ return WINBINDD_OK;
+ }
+
+ len=bufsize=0;
+ state->response.extra_data = NULL;
+
+ for (i=0; i<num_groups; i++) {
+ sprintf_append(NULL, (char **)&state->response.extra_data,
+ &len, &bufsize,
+ "%s\n", sid_string_static(&groups[i]));
+ }
+
+ if (state->response.extra_data == NULL) {
+ /* Hmmm. Allocation failed somewhere */
+ return WINBINDD_ERROR;
+ }
+
+ state->response.data.num_entries = num_groups;
+ state->response.length += len+1;
+
+ return WINBINDD_OK;
+}
diff --git a/source3/nsswitch/winbindd_ldap.c b/source3/nsswitch/winbindd_ldap.c
new file mode 100644
index 0000000000..4eedf0ce9f
--- /dev/null
+++ b/source3/nsswitch/winbindd_ldap.c
@@ -0,0 +1,646 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ winbind ldap proxy code
+
+ Copyright (C) Volker Lendecke
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+/* This rw-buf api is made to avoid memcpy. For now do that like mad... The
+ idea is to write into a circular list of buffers where the ideal case is
+ that a read(2) holds a complete request that is then thrown away
+ completely. */
+
+struct ldap_message_queue {
+ struct ldap_message_queue *prev, *next;
+ struct ldap_message *msg;
+};
+
+struct rw_buffer {
+ uint8_t *data;
+ size_t ofs, length;
+};
+
+struct winbind_ldap_client {
+ struct winbind_ldap_client *next, *prev;
+ int sock;
+ BOOL finished;
+ struct rw_buffer in_buffer, out_buffer;
+};
+
+static struct winbind_ldap_client *ldap_clients;
+
+struct winbind_ldap_server {
+ struct winbind_ldap_server *next, *prev;
+ int sock;
+ BOOL ready; /* Bind successful? */
+ BOOL finished;
+ struct rw_buffer in_buffer, out_buffer;
+ int messageid;
+};
+
+static struct winbind_ldap_server *ldap_servers;
+
+struct pending_ldap_message {
+ struct pending_ldap_message *next, *prev;
+ struct ldap_message *msg; /* The message the client sent us */
+ int our_msgid; /* The messageid we used */
+ struct winbind_ldap_client *client;
+};
+
+struct pending_ldap_message *pending_messages;
+
+static BOOL append_to_buf(struct rw_buffer *buf, uint8_t *data, size_t length)
+{
+ buf->data = SMB_REALLOC(buf->data, buf->length+length);
+
+ if (buf->data == NULL)
+ return False;
+
+ memcpy(buf->data+buf->length, data, length);
+
+ buf->length += length;
+ return True;
+}
+
+static BOOL read_into_buf(int fd, struct rw_buffer *buf)
+{
+ char tmp_buf[1024];
+ int len;
+
+ len = read(fd, tmp_buf, sizeof(tmp_buf));
+ if (len == 0)
+ return False;
+
+ return append_to_buf(buf, tmp_buf, len);
+}
+
+static void peek_into_buf(struct rw_buffer *buf, uint8_t **out,
+ size_t *out_length)
+{
+ *out = buf->data;
+ *out_length = buf->length;
+}
+
+static void consumed_from_buf(struct rw_buffer *buf, size_t length)
+{
+ uint8_t *new = memdup(buf->data+length, buf->length-length);
+ free(buf->data);
+ buf->data = new;
+ buf->length -= length;
+}
+
+static BOOL write_out_of_buf(int fd, struct rw_buffer *buf)
+{
+ uint8_t *tmp;
+ size_t tmp_length, written;
+
+ peek_into_buf(buf, &tmp, &tmp_length);
+ if (tmp_length == 0)
+ return True;
+
+ written = write(fd, tmp, tmp_length);
+ if (written < 0)
+ return False;
+
+ consumed_from_buf(buf, written);
+ return True;
+}
+
+static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
+{
+ DATA_BLOB blob;
+ BOOL res;
+
+ if (!ldap_encode(msg, &blob))
+ return False;
+
+ res = append_to_buf(buf, blob.data, blob.length);
+
+ data_blob_free(&blob);
+ return res;
+}
+
+static void new_ldap_client(int listen_sock)
+{
+ struct sockaddr_un sunaddr;
+ struct winbind_ldap_client *client;
+ socklen_t len;
+ int sock;
+
+ /* Accept connection */
+
+ len = sizeof(sunaddr);
+
+ do {
+ sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);
+ } while (sock == -1 && errno == EINTR);
+
+ if (sock == -1)
+ return;
+
+ DEBUG(6,("accepted socket %d\n", sock));
+
+ /* Create new connection structure */
+
+ client = SMB_MALLOC_P(struct winbind_ldap_client);
+
+ if (client == NULL)
+ return;
+
+ ZERO_STRUCTP(client);
+
+ client->sock = sock;
+ client->finished = False;
+
+ DLIST_ADD(ldap_clients, client);
+}
+
+static struct ldap_message *get_msg_from_buf(struct rw_buffer *buffer,
+ BOOL *error)
+{
+ uint8_t *buf;
+ int buf_length, msg_length;
+ DATA_BLOB blob;
+ ASN1_DATA data;
+ struct ldap_message *msg;
+
+ DEBUG(10,("ldapsrv_recv\n"));
+
+ *error = False;
+
+ peek_into_buf(buffer, &buf, &buf_length);
+
+ if (buf_length < 8) {
+ /* Arbitrary heuristics: ldap messages are longer than eight
+ * bytes, and their tag length fits into the eight bytes */
+ return NULL;
+ }
+
+ /* LDAP Messages are always SEQUENCES */
+
+ if (!asn1_object_length(buf, buf_length, ASN1_SEQUENCE(0),
+ &msg_length))
+ goto disconnect;
+
+ if (buf_length < msg_length) {
+ /* Not enough yet */
+ return NULL;
+ }
+
+ /* We've got a complete LDAP request in the in-buffer */
+
+ blob.data = buf;
+ blob.length = msg_length;
+
+ if (!asn1_load(&data, blob))
+ goto disconnect;
+
+ msg = new_ldap_message();
+
+ if ((msg == NULL) || !ldap_decode(&data, msg)) {
+ asn1_free(&data);
+ goto disconnect;
+ }
+
+ asn1_free(&data);
+
+ consumed_from_buf(buffer, msg_length);
+
+ return msg;
+
+ disconnect:
+
+ *error = True;
+ return NULL;
+}
+
+static int send_msg_to_server(struct ldap_message *msg,
+ struct winbind_ldap_server *server)
+{
+ int cli_messageid;
+
+ cli_messageid = msg->messageid;
+ msg->messageid = ldap_servers->messageid;
+
+ if (!ldap_append_to_buf(msg, &ldap_servers->out_buffer))
+ return -1;
+
+ msg->messageid = cli_messageid;
+ return ldap_servers->messageid++;
+}
+
+static int send_msg(struct ldap_message *msg)
+{
+ /* This is the scheduling routine that should decide where to send
+ * stuff. The first attempt is easy: We only have one server. This
+ * will change once we handle referrals etc. */
+
+ SMB_ASSERT(ldap_servers != NULL);
+
+ if (!ldap_servers->ready)
+ return -1;
+
+ return send_msg_to_server(msg, ldap_servers);
+}
+
+static void fake_bind_response(struct winbind_ldap_client *client,
+ int messageid)
+{
+ struct ldap_message *msg = new_ldap_message();
+
+ if (msg == NULL) {
+ client->finished = True;
+ return;
+ }
+
+ msg->messageid = messageid;
+ msg->type = LDAP_TAG_BindResponse;
+ msg->r.BindResponse.response.resultcode = 0;
+ msg->r.BindResponse.response.dn = "";
+ msg->r.BindResponse.response.dn = "";
+ msg->r.BindResponse.response.errormessage = "";
+ msg->r.BindResponse.response.referral = "";
+ ldap_append_to_buf(msg, &client->out_buffer);
+ destroy_ldap_message(msg);
+}
+
+static int open_ldap_socket(void)
+{
+ static int fd = -1;
+
+ if (fd >= 0)
+ return fd;
+
+ fd = create_pipe_sock(get_winbind_priv_pipe_dir(), "ldapi", 0750);
+ return fd;
+}
+
+static BOOL do_sigterm = False;
+
+static void ldap_termination_handler(int signum)
+{
+ do_sigterm = True;
+ sys_select_signal();
+}
+
+static BOOL handled_locally(struct ldap_message *msg,
+ struct winbind_ldap_server *server)
+{
+ struct ldap_Result *r = &msg->r.BindResponse.response;
+
+ if (msg->type != LDAP_TAG_BindResponse)
+ return False;
+
+ if (r->resultcode != 0) {
+ destroy_ldap_message(msg);
+ server->finished = True;
+ }
+ destroy_ldap_message(msg);
+ server->ready = True;
+ return True;
+}
+
+static void client_has_data(struct winbind_ldap_client *client)
+{
+
+ struct ldap_message *msg;
+
+ if (!read_into_buf(client->sock, &client->in_buffer)) {
+ client->finished = True;
+ return;
+ }
+
+ while ((msg = get_msg_from_buf(&client->in_buffer,
+ &client->finished))) {
+ struct pending_ldap_message *pending;
+
+ if (msg->type == LDAP_TAG_BindRequest) {
+ fake_bind_response(client, msg->messageid);
+ destroy_ldap_message(msg);
+ continue;
+ }
+
+ if (msg->type == LDAP_TAG_UnbindRequest) {
+ destroy_ldap_message(msg);
+ client->finished = True;
+ break;
+ }
+
+ pending = SMB_MALLOC_P(struct pending_ldap_message);
+ if (pending == NULL)
+ continue;
+
+ pending->msg = msg;
+ pending->client = client;
+ pending->our_msgid = send_msg(msg);
+
+ if (pending->our_msgid < 0) {
+ /* could not send */
+ client->finished = True;
+ free(pending);
+ }
+ DLIST_ADD(pending_messages, pending);
+ }
+}
+
+static struct ldap_Result *ldap_msg2result(struct ldap_message *msg)
+{
+ switch(msg->type) {
+ case LDAP_TAG_BindResponse:
+ return &msg->r.BindResponse.response;
+ case LDAP_TAG_SearchResultDone:
+ return &msg->r.SearchResultDone;
+ case LDAP_TAG_ModifyResponse:
+ return &msg->r.ModifyResponse;
+ case LDAP_TAG_AddResponse:
+ return &msg->r.AddResponse;
+ case LDAP_TAG_DelResponse:
+ return &msg->r.DelResponse;
+ case LDAP_TAG_ModifyDNResponse:
+ return &msg->r.ModifyDNResponse;
+ case LDAP_TAG_CompareResponse:
+ return &msg->r.CompareResponse;
+ case LDAP_TAG_ExtendedResponse:
+ return &msg->r.ExtendedResponse.response;
+ }
+ return NULL;
+}
+
+static void server_has_data(struct winbind_ldap_server *server)
+{
+ struct ldap_message *msg;
+
+ if (!read_into_buf(server->sock, &server->in_buffer)) {
+ server->finished = True;
+ return;
+ }
+
+ while ((msg = get_msg_from_buf(&server->in_buffer,
+ &server->finished))) {
+ struct pending_ldap_message *pending;
+ struct rw_buffer *buf;
+ struct ldap_Result *res;
+
+ if (handled_locally(msg, server))
+ continue;
+
+ res = ldap_msg2result(msg);
+
+ if ( (res != NULL) && (res->resultcode == 10) )
+ DEBUG(5, ("Got Referral %s\n", res->referral));
+
+ for (pending = pending_messages;
+ pending != NULL;
+ pending = pending->next) {
+ if (pending->our_msgid == msg->messageid)
+ break;
+ }
+
+ if (pending == NULL) {
+ talloc_destroy(msg->mem_ctx);
+ continue;
+ }
+
+ msg->messageid = pending->msg->messageid;
+
+ buf = &pending->client->out_buffer;
+ ldap_append_to_buf(msg, buf);
+
+ if ( (msg->type != LDAP_TAG_SearchResultEntry) &&
+ (msg->type != LDAP_TAG_SearchResultReference) ) {
+ destroy_ldap_message(pending->msg);
+ DLIST_REMOVE(pending_messages,
+ pending);
+ SAFE_FREE(pending);
+ }
+ destroy_ldap_message(msg);
+ }
+}
+
+static void process_ldap_loop(void)
+{
+ struct winbind_ldap_client *client;
+ struct winbind_ldap_server *server;
+ fd_set r_fds, w_fds;
+ int maxfd, listen_sock, selret;
+ struct timeval timeout;
+
+ /* Free up temporary memory */
+
+ lp_talloc_free();
+ main_loop_talloc_free();
+
+ if (do_sigterm) {
+#if 0
+ TALLOC_CTX *mem_ctx = talloc_init("describe");
+ DEBUG(0, ("%s\n", talloc_describe_all(mem_ctx)));
+ talloc_destroy(mem_ctx);
+#endif
+ exit(0);
+ }
+
+ /* Initialise fd lists for select() */
+
+ listen_sock = open_ldap_socket();
+
+ if (listen_sock == -1) {
+ perror("open_ldap_socket");
+ exit(1);
+ }
+
+ maxfd = listen_sock;
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+ FD_SET(listen_sock, &r_fds);
+
+ timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
+ timeout.tv_usec = 0;
+
+ /* Set up client readers and writers */
+
+ client = ldap_clients;
+
+ while (client != NULL) {
+
+ if (client->finished) {
+ struct winbind_ldap_client *next = client->next;
+ DLIST_REMOVE(ldap_clients, client);
+ close(client->sock);
+ SAFE_FREE(client->in_buffer.data);
+ SAFE_FREE(client->out_buffer.data);
+ SAFE_FREE(client);
+ client = next;
+ continue;
+ }
+
+ if (client->sock > maxfd)
+ maxfd = client->sock;
+
+ FD_SET(client->sock, &r_fds);
+
+ if (client->out_buffer.length > 0)
+ FD_SET(client->sock, &w_fds);
+
+ client = client->next;
+ }
+
+ /* And now the servers */
+
+ server = ldap_servers;
+
+ while (server != NULL) {
+
+ if (server->finished) {
+ struct winbind_ldap_server *next = server->next;
+ DLIST_REMOVE(ldap_servers, server);
+ close(server->sock);
+ SAFE_FREE(server);
+ server = next;
+ continue;
+ }
+
+ if (server->sock > maxfd)
+ maxfd = server->sock;
+
+ FD_SET(server->sock, &r_fds);
+
+ if (server->out_buffer.length > 0)
+ FD_SET(server->sock, &w_fds);
+
+ server = server->next;
+ }
+
+ selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+
+ if (selret == 0)
+ return;
+
+ if (selret == -1 && errno != EINTR) {
+ perror("select");
+ exit(1);
+ }
+
+ if (FD_ISSET(listen_sock, &r_fds))
+ new_ldap_client(listen_sock);
+
+ for (client = ldap_clients; client != NULL; client = client->next) {
+
+ if (FD_ISSET(client->sock, &r_fds))
+ client_has_data(client);
+
+ if ((!client->finished) && FD_ISSET(client->sock, &w_fds))
+ write_out_of_buf(client->sock, &client->out_buffer);
+ }
+
+ for (server = ldap_servers; server != NULL; server = server->next) {
+
+ if (FD_ISSET(server->sock, &r_fds))
+ server_has_data(server);
+
+ if (!server->finished && FD_ISSET(server->sock, &w_fds))
+ write_out_of_buf(server->sock, &server->out_buffer);
+ }
+}
+
+static BOOL setup_ldap_serverconn(void)
+{
+ char *host;
+ uint16 port;
+ BOOL ldaps;
+ struct hostent *hp;
+ struct in_addr ip;
+ TALLOC_CTX *mem_ctx = talloc_init("server");
+ struct ldap_message *msg;
+ char *dn, *pw;
+
+ ldap_servers = SMB_MALLOC_P(struct winbind_ldap_server);
+
+ if ((ldap_servers == NULL) || (mem_ctx == NULL))
+ return False;
+
+ if (!ldap_parse_basic_url(mem_ctx, "ldap://192.168.234.1:3899/",
+ &host, &port, &ldaps))
+ return False;
+
+ hp = sys_gethostbyname(host);
+
+ if ((hp == NULL) || (hp->h_addr == NULL))
+ return False;
+
+ putip((char *)&ip, (char *)hp->h_addr);
+
+ ZERO_STRUCTP(ldap_servers);
+ ldap_servers->sock = open_socket_out(SOCK_STREAM, &ip, port, 10000);
+ ldap_servers->messageid = 1;
+
+ if (!fetch_ldap_pw(&dn, &pw))
+ return False;
+
+ msg = new_ldap_simple_bind_msg(dn, pw);
+
+ SAFE_FREE(dn);
+ SAFE_FREE(pw);
+
+ if (msg == NULL)
+ return False;
+
+ msg->messageid = ldap_servers->messageid++;
+
+ ldap_append_to_buf(msg, &ldap_servers->out_buffer);
+
+ destroy_ldap_message(msg);
+
+ return (ldap_servers->sock >= 0);
+}
+
+void do_ldap_proxy(void)
+{
+ int ldap_child;
+
+ ldap_child = sys_fork();
+
+ if (ldap_child != 0)
+ return;
+
+ /* tdb needs special fork handling */
+ if (tdb_reopen_all() == -1) {
+ DEBUG(0,("tdb_reopen_all failed.\n"));
+ _exit(0);
+ }
+
+ if (!message_init()) {
+ DEBUG(0, ("message_init failed\n"));
+ _exit(0);
+ }
+
+ CatchSignal(SIGINT, ldap_termination_handler);
+ CatchSignal(SIGQUIT, ldap_termination_handler);
+ CatchSignal(SIGTERM, ldap_termination_handler);
+
+ if (!setup_ldap_serverconn())
+ return;
+
+ while (1)
+ process_ldap_loop();
+
+ return;
+}
diff --git a/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c
index bb30a7029e..9cfa4c6fcc 100644
--- a/source3/nsswitch/winbindd_misc.c
+++ b/source3/nsswitch/winbindd_misc.c
@@ -31,11 +31,20 @@
enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state)
{
+ DEBUG(3, ("[%5lu]: check machine account\n",
+ (unsigned long)state->pid));
+
+ async_domain_request(state->mem_ctx, find_our_domain(),
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
- uchar trust_passwd[16];
int num_retries = 0;
- struct cli_state *cli;
- uint32 sec_channel_type;
struct winbindd_domain *contact_domain;
DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
@@ -43,26 +52,22 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat
/* Get trust account password */
again:
- if (!secrets_fetch_trust_account_password(
- lp_workgroup(), trust_passwd, NULL, &sec_channel_type)) {
- result = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
-
contact_domain = find_our_domain();
- if (!contact_domain) {
- result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
- DEBUG(1, ("Cannot find our own domain!\n"));
- goto done;
- }
/* This call does a cli_nt_setup_creds() which implicitly checks
the trust account password. */
- /* Don't shut this down - it belongs to the connection cache code */
-
- result = cm_get_netlogon_cli(contact_domain,
- trust_passwd, sec_channel_type, True, &cli);
+
+ invalidate_cm_connection(&contact_domain->conn);
+
+ {
+ struct rpc_pipe_client *cli;
+ unsigned char *session_key;
+ DOM_CRED *creds;
+
+ result = cm_connect_netlogon(contact_domain, state->mem_ctx,
+ &cli, &session_key, &creds);
+ }
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
@@ -100,108 +105,256 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
-enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
- *state)
+enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state *state)
{
- struct winbindd_domain *domain;
- int total_entries = 0, extra_data_len = 0;
- char *ted, *extra_data = NULL;
+ DEBUG(3, ("[%5lu]: list trusted domains\n",
+ (unsigned long)state->pid));
+
+ async_domain_request(state->mem_ctx, find_our_domain(),
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+}
- DEBUG(3, ("[%5lu]: list trusted domains\n", (unsigned long)state->pid));
+enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ uint32 i, num_domains;
+ char **names, **alt_names;
+ DOM_SID *sids;
+ int extra_data_len = 0;
+ char *extra_data;
+ NTSTATUS result;
- /* We need to refresh the trusted domain list as the domains may
- have changed since we last looked. There may be a sequence
- number or something we should use but I haven't found it yet. */
+ DEBUG(3, ("[%5lu]: list trusted domains\n",
+ (unsigned long)state->pid));
- if (!init_domain_list()) {
- DEBUG(1, ("winbindd_list_trusted_domains: could not "
- "refresh trusted domain list\n"));
- return WINBINDD_ERROR;
+ result = domain->methods->trusted_domains(domain, state->mem_ctx,
+ &num_domains, &names,
+ &alt_names, &sids);
+
+ extra_data = talloc_strdup(state->mem_ctx, "");
+
+ if (num_domains > 0)
+ extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
+ names[0], alt_names[0],
+ sid_string_static(&sids[0]));
+
+ for (i=1; i<num_domains; i++)
+ extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
+ extra_data,
+ names[i], alt_names[i],
+ sid_string_static(&sids[i]));
+
+ /* This is a bit excessive, but the extra data sooner or later will be
+ talloc'ed */
+
+ extra_data_len = strlen(extra_data);
+
+ if (extra_data_len > 0) {
+ state->response.extra_data = SMB_STRDUP(extra_data);
+ state->response.length += extra_data_len+1;
}
- for(domain = domain_list(); domain; domain = domain->next) {
+ return WINBINDD_OK;
+}
- /* Skip own domain */
+enum winbindd_result winbindd_getdcname(struct winbindd_cli_state *state)
+{
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1] = '\0';
- if (domain->primary) continue;
+ DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
+ state->request.domain_name));
- /* Add domain to list */
+ async_domain_request(state->mem_ctx, find_our_domain(),
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+}
- total_entries++;
- ted = SMB_REALLOC(extra_data, sizeof(fstring) *
- total_entries);
+enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ fstring dcname_slash;
+ char *p;
+ struct rpc_pipe_client *cli;
+ NTSTATUS result;
- if (!ted) {
- DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n"));
- SAFE_FREE(extra_data);
- return WINBINDD_ERROR;
- } else
- extra_data = ted;
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1] = '\0';
- memcpy(&extra_data[extra_data_len], domain->name,
- strlen(domain->name));
+ DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
+ state->request.domain_name));
+
+ {
+ /* These var's can be ignored -- we're not requesting
+ anything in the credential chain here */
+ unsigned char *session_key;
+ DOM_CRED *creds;
+ result = cm_connect_netlogon(domain, state->mem_ctx, &cli,
+ &session_key, &creds);
+ }
- extra_data_len += strlen(domain->name);
- extra_data[extra_data_len++] = ',';
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1, ("Can't contact our the NETLOGON pipe\n"));
+ return WINBINDD_ERROR;
}
- if (extra_data) {
- if (extra_data_len > 1)
- extra_data[extra_data_len - 1] = '\0';
- state->response.extra_data = extra_data;
- state->response.length += extra_data_len;
+ result = rpccli_netlogon_getdcname(cli, state->mem_ctx, domain->dcname,
+ state->request.domain_name,
+ dcname_slash);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("Error requesting DCname: %s\n", nt_errstr(result)));
+ return WINBINDD_ERROR;
}
+ p = dcname_slash;
+ if (*p == '\\') p+=1;
+ if (*p == '\\') p+=1;
+
+ fstrcpy(state->response.data.dc_name, p);
+
return WINBINDD_OK;
}
+struct sequence_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_cli_state *cli_state;
+ struct winbindd_domain *domain;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ char *extra_data;
+};
+
+static void sequence_recv(void *private, BOOL success);
enum winbindd_result winbindd_show_sequence(struct winbindd_cli_state *state)
{
- struct winbindd_domain *domain;
- char *extra_data = NULL;
- const char *which_domain;
+ struct sequence_state *seq;
+
+ /* Ensure null termination */
+ state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
+
+ if (strlen(state->request.domain_name) > 0) {
+ struct winbindd_domain *domain;
+ domain = find_domain_from_name_noinit(
+ state->request.domain_name);
+ if (domain == NULL)
+ return WINBINDD_ERROR;
+ async_domain_request(state->mem_ctx, domain,
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+ }
+
+ /* Ask all domains in sequence, collect the results in sequence_recv */
+ seq = TALLOC_P(state->mem_ctx, struct sequence_state);
+ if (seq == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ seq->mem_ctx = state->mem_ctx;
+ seq->cli_state = state;
+ seq->domain = domain_list();
+ if (seq->domain == NULL) {
+ DEBUG(0, ("domain list empty\n"));
+ return WINBINDD_ERROR;
+ }
+ seq->request = TALLOC_ZERO_P(state->mem_ctx,
+ struct winbindd_request);
+ seq->response = TALLOC_ZERO_P(state->mem_ctx,
+ struct winbindd_response);
+ seq->extra_data = talloc_strdup(state->mem_ctx, "");
+
+ if ((seq->request == NULL) || (seq->response == NULL) ||
+ (seq->extra_data == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ seq->request->length = sizeof(*seq->request);
+ seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
+ fstrcpy(seq->request->domain_name, seq->domain->name);
+
+ async_domain_request(state->mem_ctx, seq->domain,
+ seq->request, seq->response,
+ sequence_recv, seq);
+ return WINBINDD_PENDING;
+}
+
+static void sequence_recv(void *private, BOOL success)
+{
+ struct sequence_state *state = private;
+ uint32 seq = DOM_SEQUENCE_NONE;
+
+ if ((success) && (state->response->result == WINBINDD_OK))
+ seq = state->response->data.domain_info.sequence_number;
+
+ if (seq == DOM_SEQUENCE_NONE) {
+ state->extra_data = talloc_asprintf(state->mem_ctx,
+ "%s%s : DISCONNECTED\n",
+ state->extra_data,
+ state->domain->name);
+ } else {
+ state->extra_data = talloc_asprintf(state->mem_ctx,
+ "%s%s : %d\n",
+ state->extra_data,
+ state->domain->name, seq);
+ }
+
+ state->domain->sequence_number = seq;
+
+ state->domain = state->domain->next;
+
+ if (state->domain == NULL) {
+ struct winbindd_cli_state *cli_state = state->cli_state;
+ cli_state->response.result = WINBINDD_OK;
+ cli_state->response.length =
+ sizeof(cli_state->response) +
+ strlen(state->extra_data) + 1;
+ cli_state->response.extra_data =
+ SMB_STRDUP(state->extra_data);
+ request_finished(cli_state);
+ return;
+ }
+
+ /* Ask the next domain */
+ fstrcpy(state->request->domain_name, state->domain->name);
+ async_domain_request(state->mem_ctx, state->domain,
+ state->request, state->response,
+ sequence_recv, state);
+}
+
+/* This is the child-only version of --sequence. It only allows for a single
+ * domain (ie "our" one) to be displayed. */
+
+enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
/* Ensure null termination */
- state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
- which_domain = state->request.domain_name;
-
- extra_data = SMB_STRDUP("");
-
- /* this makes for a very simple data format, and is easily parsable as well
- if that is ever needed */
- for (domain = domain_list(); domain; domain = domain->next) {
- char *s;
-
- /* if we have a domain name restricting the request and this
- one in the list doesn't match, then just bypass the remainder
- of the loop */
-
- if ( *which_domain && !strequal(which_domain, domain->name) )
- continue;
-
- domain->methods->sequence_number(domain, &domain->sequence_number);
-
- if (DOM_SEQUENCE_NONE == (unsigned)domain->sequence_number) {
- asprintf(&s,"%s%s : DISCONNECTED\n", extra_data,
- domain->name);
- } else {
- asprintf(&s,"%s%s : %u\n", extra_data,
- domain->name, (unsigned)domain->sequence_number);
- }
- free(extra_data);
- extra_data = s;
- }
+ state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
- state->response.extra_data = extra_data;
- /* must add one to length to copy the 0 for string termination */
- state->response.length += strlen(extra_data) + 1;
+ domain->methods->sequence_number(domain, &domain->sequence_number);
+
+ state->response.data.domain_info.sequence_number =
+ domain->sequence_number;
return WINBINDD_OK;
}
+struct domain_info_state {
+ struct winbindd_domain *domain;
+ struct winbindd_cli_state *cli_state;
+};
+
+static void domain_info_init_recv(void *private, BOOL success);
+
enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
{
struct winbindd_domain *domain;
@@ -209,7 +362,7 @@ enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
state->request.domain_name));
- domain = find_domain_from_name(state->request.domain_name);
+ domain = find_domain_from_name_noinit(state->request.domain_name);
if (domain == NULL) {
DEBUG(3, ("Did not find domain [%s]\n",
@@ -217,21 +370,78 @@ enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
return WINBINDD_ERROR;
}
- fstrcpy(state->response.data.domain_info.name, domain->name);
- fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
+ if (!domain->initialized) {
+ struct domain_info_state *istate;
+
+ istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
+ if (istate == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ istate->cli_state = state;
+ istate->domain = domain;
+
+ init_child_connection(domain, domain_info_init_recv, istate);
+
+ return WINBINDD_PENDING;
+ }
+
+ fstrcpy(state->response.data.domain_info.name,
+ domain->name);
+ fstrcpy(state->response.data.domain_info.alt_name,
+ domain->alt_name);
fstrcpy(state->response.data.domain_info.sid,
sid_string_static(&domain->sid));
- state->response.data.domain_info.native_mode = domain->native_mode;
- state->response.data.domain_info.active_directory = domain->active_directory;
- state->response.data.domain_info.primary = domain->primary;
-
+ state->response.data.domain_info.native_mode =
+ domain->native_mode;
+ state->response.data.domain_info.active_directory =
+ domain->active_directory;
+ state->response.data.domain_info.primary =
+ domain->primary;
state->response.data.domain_info.sequence_number =
domain->sequence_number;
return WINBINDD_OK;
}
+static void domain_info_init_recv(void *private, BOOL success)
+{
+ struct domain_info_state *istate = private;
+ struct winbindd_cli_state *state = istate->cli_state;
+ struct winbindd_domain *domain = istate->domain;
+
+ DEBUG(10, ("Got back from child init: %d\n", success));
+
+ if ((!success) || (!domain->initialized)) {
+ DEBUG(5, ("Could not init child for domain %s\n",
+ domain->name));
+ state->response.result = WINBINDD_ERROR;
+ request_finished_cont(state, False);
+ return;
+ }
+
+ fstrcpy(state->response.data.domain_info.name,
+ domain->name);
+ fstrcpy(state->response.data.domain_info.alt_name,
+ domain->alt_name);
+ fstrcpy(state->response.data.domain_info.sid,
+ sid_string_static(&domain->sid));
+
+ state->response.data.domain_info.native_mode =
+ domain->native_mode;
+ state->response.data.domain_info.active_directory =
+ domain->active_directory;
+ state->response.data.domain_info.primary =
+ domain->primary;
+ state->response.data.domain_info.sequence_number =
+ domain->sequence_number;
+
+ state->response.result = WINBINDD_OK;
+ request_finished_cont(state, True);
+}
+
enum winbindd_result winbindd_ping(struct winbindd_cli_state
*state)
{
diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h
index 88645e093b..b249b62d69 100644
--- a/source3/nsswitch/winbindd_nss.h
+++ b/source3/nsswitch/winbindd_nss.h
@@ -34,7 +34,7 @@
/* Update this when you change the interface. */
-#define WINBIND_INTERFACE_VERSION 10
+#define WINBIND_INTERFACE_VERSION 11
/* Socket commands */
@@ -83,6 +83,7 @@ enum winbindd_cmd {
WINBINDD_UID_TO_SID,
WINBINDD_GID_TO_SID,
WINBINDD_ALLOCATE_RID,
+ WINBINDD_ALLOCATE_RID_AND_GID,
/* Miscellaneous other stuff */
@@ -93,6 +94,7 @@ enum winbindd_cmd {
WINBINDD_DOMAIN_INFO, /* Most of what we know from
struct winbindd_domain */
+ WINBINDD_GETDCNAME, /* Issue a GetDCName Request */
WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
@@ -110,9 +112,29 @@ enum winbindd_cmd {
WINBINDD_PRIV_PIPE_DIR,
/* return a list of group sids for a user sid */
- WINBINDD_GETUSERSIDS,
+ WINBINDD_GETUSERSIDS,
+
+ /* Return the domain groups a user is in */
+ WINBINDD_GETUSERDOMGROUPS,
+
+ /* Initialize connection in a child */
+ WINBINDD_INIT_CONNECTION,
+
+ /* Blocking calls that are not allowed on the main winbind pipe, only
+ * between parent and children */
+ WINBINDD_DUAL_SID2UID,
+ WINBINDD_DUAL_SID2GID,
+ WINBINDD_DUAL_IDMAPSET,
+
+ /* Wrapper around possibly blocking unix nss calls */
+ WINBINDD_DUAL_UID2NAME,
+ WINBINDD_DUAL_NAME2UID,
+ WINBINDD_DUAL_GID2NAME,
+ WINBINDD_DUAL_NAME2GID,
+
+ WINBINDD_DUAL_USERINFO,
+ WINBINDD_DUAL_GETSIDALIASES,
- /* Placeholder for end of cmd list */
WINBINDD_NUM_CMDS
};
@@ -148,6 +170,9 @@ typedef struct winbindd_gr {
#define WBFLAG_PAM_AFS_TOKEN 0x0100
#define WBFLAG_PAM_NT_STATUS_SQUASH 0x0200
+/* This is a flag that can only be sent from parent to child */
+#define WBFLAG_IS_PRIVILEGED 0x0400
+
/* Winbind request structure */
struct winbindd_request {
@@ -156,6 +181,7 @@ struct winbindd_request {
pid_t pid; /* pid of calling process */
uint32 flags; /* flags relavant to a given request */
fstring domain_name; /* name of domain for which the request applies */
+ int msgid;
union {
fstring winsreq; /* WINS request */
@@ -197,6 +223,24 @@ struct winbindd_request {
fstring username;
fstring groupname;
} acct_mgt;
+ struct {
+ BOOL is_primary;
+ fstring dcname;
+ } init_conn;
+ struct {
+ fstring sid;
+ fstring name;
+ BOOL alloc;
+ } dual_sid2id;
+ struct {
+ int type;
+ uid_t uid;
+ gid_t gid;
+ fstring sid;
+ } dual_idmapset;
+ struct {
+ fstring cache_key;
+ } dual_sidaliases;
} data;
char null_term;
};
@@ -205,6 +249,7 @@ struct winbindd_request {
enum winbindd_result {
WINBINDD_ERROR,
+ WINBINDD_PENDING,
WINBINDD_OK
};
@@ -250,6 +295,7 @@ struct winbindd_response {
} info;
fstring domain_name;
fstring netbios_name;
+ fstring dc_name;
struct auth_reply {
uint32 nt_status;
@@ -261,6 +307,10 @@ struct winbindd_response {
} auth;
uint32 rid; /* create user or group or allocate rid */
struct {
+ uint32 rid;
+ gid_t gid;
+ } rid_and_gid;
+ struct {
fstring name;
fstring alt_name;
fstring sid;
@@ -269,6 +319,11 @@ struct winbindd_response {
BOOL primary;
uint32 sequence_number;
} domain_info;
+ struct {
+ fstring acct_name;
+ fstring full_name;
+ uint32 group_rid;
+ } user_info;
} data;
/* Variable length return data */
diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c
index 9061391118..97dc35c0e7 100644
--- a/source3/nsswitch/winbindd_pam.c
+++ b/source3/nsswitch/winbindd_pam.c
@@ -145,24 +145,99 @@ static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
return NT_STATUS_LOGON_FAILURE;
}
+static struct winbindd_domain *find_auth_domain(const char *domain_name)
+{
+ struct winbindd_domain *domain;
+
+ if (IS_DC) {
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ DEBUG(3, ("Authentication for domain [%s] "
+ "as it is not a trusted domain\n",
+ domain_name));
+ }
+ return domain;
+ }
+
+ if (is_myname(domain_name)) {
+ DEBUG(3, ("Authentication for domain %s (local domain "
+ "to this server) not supported at this "
+ "stage\n", domain_name));
+ return NULL;
+ }
+
+ return find_our_domain();
+}
+
+static void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
+{
+ resp->data.auth.nt_status = NT_STATUS_V(result);
+ fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
+
+ /* we might have given a more useful error above */
+ if (*resp->data.auth.error_string == '\0')
+ fstrcpy(resp->data.auth.error_string,
+ get_friendly_nt_error_msg(result));
+ resp->data.auth.pam_error = nt_status_to_pam(result);
+}
+
/**********************************************************************
Authenticate a user with a clear text password
**********************************************************************/
-enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
+enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring name_domain, name_user;
+
+ /* Ensure null termination */
+ state->request.data.auth.user
+ [sizeof(state->request.data.auth.user)-1]='\0';
+
+ /* Ensure null termination */
+ state->request.data.auth.pass
+ [sizeof(state->request.data.auth.pass)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
+ state->request.data.auth.user));
+
+ /* Parse domain and username */
+
+ parse_domain_user(state->request.data.auth.user,
+ name_domain, name_user);
+
+ domain = find_auth_domain(name_domain);
+
+ if (domain == NULL) {
+ set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
+ DEBUG(5, ("Plain text authentication for %s returned %s "
+ "(PAM: %d)\n",
+ state->request.data.auth.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+ return WINBINDD_ERROR;
+ }
+
+ async_domain_request(state->mem_ctx, domain,
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
{
NTSTATUS result;
fstring name_domain, name_user;
- unsigned char trust_passwd[16];
- time_t last_change_time;
- uint32 sec_channel_type;
+ const char *srv_name_slash;
NET_USER_INFO_3 info3;
- struct cli_state *cli = NULL;
+ unsigned char *session_key;
+ struct rpc_pipe_client *pipe_cli;
uchar chal[8];
- TALLOC_CTX *mem_ctx = NULL;
DATA_BLOB lm_resp;
DATA_BLOB nt_resp;
DOM_CRED ret_creds;
+ DOM_CRED *credentials;
int attempts = 0;
unsigned char local_lm_response[24];
unsigned char local_nt_response[24];
@@ -178,12 +253,6 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
state->request.data.auth.user));
- if (!(mem_ctx = talloc_init("winbind pam auth for %s", state->request.data.auth.user))) {
- DEBUG(0, ("winbindd_pam_auth: could not talloc_init()!\n"));
- result = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
/* Parse domain and username */
parse_domain_user(state->request.data.auth.user, name_domain, name_user);
@@ -197,7 +266,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
DATA_BLOB names_blob;
DATA_BLOB nt_response;
DATA_BLOB lm_response;
- server_chal = data_blob_talloc(mem_ctx, chal, 8);
+ server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
/* note that the 'workgroup' here is a best guess - we don't know
the server's domain at this point. The 'server name' is also
@@ -218,8 +287,10 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
}
data_blob_free(&names_blob);
data_blob_free(&server_chal);
- lm_resp = data_blob_talloc(mem_ctx, lm_response.data, lm_response.length);
- nt_resp = data_blob_talloc(mem_ctx, nt_response.data, nt_response.length);
+ lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
+ lm_response.length);
+ nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
+ nt_response.length);
data_blob_free(&lm_response);
data_blob_free(&nt_response);
@@ -228,7 +299,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
&& SMBencrypt(state->request.data.auth.pass,
chal,
local_lm_response)) {
- lm_resp = data_blob_talloc(mem_ctx,
+ lm_resp = data_blob_talloc(state->mem_ctx,
local_lm_response,
sizeof(local_lm_response));
} else {
@@ -238,7 +309,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
chal,
local_nt_response);
- nt_resp = data_blob_talloc(mem_ctx,
+ nt_resp = data_blob_talloc(state->mem_ctx,
local_nt_response,
sizeof(local_nt_response));
}
@@ -261,80 +332,95 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
goto done;
}
- if (!(contact_domain = find_our_domain())) {
- DEBUG(1, ("Authentication for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n",
- state->request.data.auth.user, name_domain, name_user));
- result = NT_STATUS_NO_SUCH_USER;
- goto done;
- }
+ contact_domain = find_our_domain();
}
- if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) {
- result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
- goto done;
+ srv_name_slash = talloc_asprintf(state->mem_ctx, "\\\\%s",
+ contact_domain->dcname);
+ if (srv_name_slash == NULL) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ return WINBINDD_ERROR;
}
-
+
/* check authentication loop */
do {
+ DOM_CRED clnt_creds;
+
ZERO_STRUCT(info3);
ZERO_STRUCT(ret_creds);
retry = False;
-
- /* Don't shut this down - it belongs to the connection cache code */
- result = cm_get_netlogon_cli(contact_domain, trust_passwd,
- sec_channel_type, False, &cli);
+
+ result = cm_connect_netlogon(contact_domain, state->mem_ctx,
+ &pipe_cli, &session_key,
+ &credentials);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
goto done;
}
- result = cli_netlogon_sam_network_logon(cli, mem_ctx,
- &ret_creds,
- name_user, name_domain,
- global_myname(), chal,
- lm_resp, nt_resp,
- &info3);
+ credentials->timestamp.time = time(NULL);
+ memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
+
+ /* Calculate the new credentials. */
+ cred_create(session_key, &credentials->challenge,
+ clnt_creds.timestamp, &(clnt_creds.challenge));
+
+ result = rpccli_netlogon_sam_network_logon(pipe_cli,
+ state->mem_ctx,
+ srv_name_slash,
+ &clnt_creds,
+ &ret_creds,
+ name_user,
+ name_domain,
+ global_myname(),
+ chal, lm_resp,
+ nt_resp, &info3,
+ session_key);
attempts += 1;
-
- /* We have to try a second time as cm_get_netlogon_cli
+
+ /* We have to try a second time as cm_connect_netlogon
might not yet have noticed that the DC has killed
our connection. */
- if ( cli->fd == -1 ) {
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
retry = True;
continue;
- }
+ }
- /* if we get access denied, a possible cuase was that we had and open
- connection to the DC, but someone changed our machine account password
- out from underneath us using 'net rpc changetrustpw' */
+ /* if we get access denied, a possible cause was that we had
+ and open connection to the DC, but someone changed our
+ machine account password out from underneath us using 'net
+ rpc changetrustpw' */
- if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) {
- DEBUG(3,("winbindd_pam_auth: sam_logon returned ACCESS_DENIED. Maybe the trust account "
- "password was changed and we didn't know it. Killing connections to domain %s\n",
+ if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+ DEBUG(3,("winbindd_pam_auth: sam_logon returned "
+ "ACCESS_DENIED. Maybe the trust account "
+ "password was changed and we didn't know it. "
+ "Killing connections to domain %s\n",
name_domain));
- winbindd_cm_flush();
+ invalidate_cm_connection(&contact_domain->conn);
retry = True;
- cli = NULL;
}
} while ( (attempts < 2) && retry );
- if (cli != NULL) {
- /* We might have come out of the loop above with cli == NULL,
- so don't dereference that. */
- clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
+ if (NT_STATUS_IS_OK(result) &&
+ (!clnt_deal_with_creds(session_key, credentials,
+ &ret_creds))) {
+ DEBUG(3, ("DC %s sent wrong credentials\n",
+ pipe_cli->cli->srv_name_slash));
+ result = NT_STATUS_ACCESS_DENIED;
}
-
+
if (NT_STATUS_IS_OK(result)) {
- netsamlogon_cache_store( cli->mem_ctx, name_user, &info3 );
+ netsamlogon_cache_store(state->mem_ctx, name_user, &info3);
wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
/* Check if the user is in the right group */
- if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth.require_membership_of_sid))) {
+ if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3, state->request.data.auth.require_membership_of_sid))) {
DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
state->request.data.auth.user,
state->request.data.auth.require_membership_of_sid));
@@ -407,9 +493,6 @@ done:
SAFE_FREE(afsname);
}
- if (mem_ctx)
- talloc_destroy(mem_ctx);
-
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
@@ -417,15 +500,79 @@ done:
Challenge Response Authentication Protocol
**********************************************************************/
-enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
+enum winbindd_result winbindd_crap_auth(struct winbindd_cli_state *state)
{
+ struct winbindd_domain *domain = NULL;
+ const char *domain_name = NULL;
NTSTATUS result;
- unsigned char trust_passwd[16];
- time_t last_change_time;
- uint32 sec_channel_type;
+
+ if (!state->privileged) {
+ char *error_string = NULL;
+ DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
+ "denied. !\n"));
+ DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
+ "on %s are set correctly.\n",
+ get_winbind_priv_pipe_dir()));
+ /* send a better message than ACCESS_DENIED */
+ error_string = talloc_asprintf(state->mem_ctx,
+ "winbind client not authorized "
+ "to use winbindd_pam_auth_crap."
+ " Ensure permissions on %s "
+ "are set correctly.",
+ get_winbind_priv_pipe_dir());
+ fstrcpy(state->response.data.auth.error_string, error_string);
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* Ensure null termination */
+ state->request.data.auth_crap.user
+ [sizeof(state->request.data.auth_crap.user)-1]=0;
+ state->request.data.auth_crap.domain
+ [sizeof(state->request.data.auth_crap.domain)-1]=0;
+
+ DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
+ (unsigned long)state->pid,
+ state->request.data.auth_crap.domain,
+ state->request.data.auth_crap.user));
+
+ if (*state->request.data.auth_crap.domain != '\0') {
+ domain_name = state->request.data.auth_crap.domain;
+ } else if (lp_winbind_use_default_domain()) {
+ domain_name = lp_workgroup();
+ }
+
+ if (domain_name != NULL)
+ domain = find_auth_domain(domain_name);
+
+ if (domain != NULL) {
+ async_domain_request(state->mem_ctx, domain,
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+ }
+
+ result = NT_STATUS_NO_SUCH_USER;
+
+ done:
+ set_auth_errors(&state->response, result);
+ DEBUG(5, ("CRAP authentication for %s returned %s (PAM: %d)\n",
+ state->request.data.auth.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+ return WINBINDD_ERROR;
+}
+
+
+enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result;
+ const char *srv_name_slash;
NET_USER_INFO_3 info3;
- struct cli_state *cli = NULL;
- TALLOC_CTX *mem_ctx = NULL;
+ unsigned char *session_key;
+ struct rpc_pipe_client *pipe_cli;
+ DOM_CRED *credentials;
const char *name_user = NULL;
const char *name_domain = NULL;
const char *workstation;
@@ -436,30 +583,13 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
DATA_BLOB lm_resp, nt_resp;
- if (!state->privileged) {
- char *error_string = NULL;
- DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access denied. !\n"));
- DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions on %s are set correctly.\n",
- get_winbind_priv_pipe_dir()));
- /* send a better message than ACCESS_DENIED */
- asprintf(&error_string, "winbind client not authorized to use winbindd_pam_auth_crap. Ensure permissions on %s are set correctly.",
- get_winbind_priv_pipe_dir());
- fstrcpy(state->response.data.auth.error_string, error_string);
- SAFE_FREE(error_string);
- result = NT_STATUS_ACCESS_DENIED;
- goto done;
- }
+ /* This is child-only, so no check for privileged access is needed
+ anymore */
/* Ensure null termination */
state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
- if (!(mem_ctx = talloc_init("winbind pam auth crap for %s", state->request.data.auth_crap.user))) {
- DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
- result = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
name_user = state->request.data.auth_crap.user;
if (*state->request.data.auth_crap.domain) {
@@ -491,8 +621,8 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
goto done;
}
- lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
- nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
+ lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
+ nt_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
/* what domain should we contact? */
@@ -512,26 +642,25 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
goto done;
}
- if (!(contact_domain = find_our_domain())) {
- DEBUG(1, ("Authenticatoin for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n",
- state->request.data.auth_crap.user, name_domain, name_user));
- result = NT_STATUS_NO_SUCH_USER;
- goto done;
- }
- }
-
- if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) {
- result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
- goto done;
+ contact_domain = find_our_domain();
}
+ srv_name_slash = talloc_asprintf(state->mem_ctx, "\\\\%s",
+ contact_domain->dcname);
+ if (srv_name_slash == NULL) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ return WINBINDD_ERROR;
+ }
+
do {
+ DOM_CRED clnt_creds;
ZERO_STRUCT(info3);
ZERO_STRUCT(ret_creds);
retry = False;
- /* Don't shut this down - it belongs to the connection cache code */
- result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli);
+ result = cm_connect_netlogon(contact_domain, state->mem_ctx,
+ &pipe_cli, &session_key,
+ &credentials);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
@@ -539,51 +668,66 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
goto done;
}
- result = cli_netlogon_sam_network_logon(cli, mem_ctx,
- &ret_creds,
- name_user, name_domain,
- workstation,
- state->request.data.auth_crap.chal,
- lm_resp, nt_resp,
- &info3);
+ credentials->timestamp.time = time(NULL);
+ memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
+
+ /* Calculate the new credentials. */
+ cred_create(session_key, &credentials->challenge,
+ clnt_creds.timestamp, &(clnt_creds.challenge));
+
+ result = rpccli_netlogon_sam_network_logon(pipe_cli,
+ state->mem_ctx,
+ srv_name_slash,
+ &clnt_creds,
+ &ret_creds,
+ name_user,
+ name_domain,
+ global_myname(),
+ state->request.data.auth_crap.chal,
+ lm_resp,
+ nt_resp, &info3,
+ session_key);
attempts += 1;
- /* We have to try a second time as cm_get_netlogon_cli
+ /* We have to try a second time as cm_connect_netlogon
might not yet have noticed that the DC has killed
our connection. */
- if ( cli->fd == -1 ) {
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
retry = True;
continue;
- }
+ }
/* if we get access denied, a possible cause was that we had and open
connection to the DC, but someone changed our machine account password
out from underneath us using 'net rpc changetrustpw' */
- if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) {
- DEBUG(3,("winbindd_pam_auth_crap: sam_logon returned ACCESS_DENIED. Maybe the trust account "
- "password was changed and we didn't know it. Killing connections to domain %s\n",
- contact_domain->name));
- winbindd_cm_flush();
+ if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+ DEBUG(3,("winbindd_pam_auth: sam_logon returned "
+ "ACCESS_DENIED. Maybe the trust account "
+ "password was changed and we didn't know it. "
+ "Killing connections to domain %s\n",
+ name_domain));
+ invalidate_cm_connection(&contact_domain->conn);
retry = True;
- cli = NULL;
}
-
+
} while ( (attempts < 2) && retry );
- if (cli != NULL) {
- /* We might have come out of the loop above with cli == NULL,
- so don't dereference that. */
- clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
+ if (NT_STATUS_IS_OK(result) &&
+ (!clnt_deal_with_creds(session_key, credentials,
+ &ret_creds))) {
+ DEBUG(3, ("DC %s sent wrong credentials\n",
+ pipe_cli->cli->srv_name_slash));
+ result = NT_STATUS_ACCESS_DENIED;
}
if (NT_STATUS_IS_OK(result)) {
- netsamlogon_cache_store( cli->mem_ctx, name_user, &info3 );
+ netsamlogon_cache_store( state->mem_ctx, name_user, &info3 );
wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
- if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth_crap.require_membership_of_sid))) {
+ if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3, state->request.data.auth_crap.require_membership_of_sid))) {
DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
state->request.data.auth_crap.user,
state->request.data.auth_crap.require_membership_of_sid));
@@ -591,19 +735,19 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
}
if (state->request.flags & WBFLAG_PAM_INFO3_NDR) {
- result = append_info3_as_ndr(mem_ctx, state, &info3);
+ result = append_info3_as_ndr(state->mem_ctx, state, &info3);
} else if (state->request.flags & WBFLAG_PAM_UNIX_NAME) {
/* ntlm_auth should return the unix username, per
'winbind use default domain' settings and the like */
fstring username_out;
const char *nt_username, *nt_domain;
- if (!(nt_username = unistr2_tdup(mem_ctx, &(info3.uni_user_name)))) {
+ if (!(nt_username = unistr2_tdup(state->mem_ctx, &(info3.uni_user_name)))) {
/* If the server didn't give us one, just use the one we sent them */
nt_username = name_user;
}
- if (!(nt_domain = unistr2_tdup(mem_ctx, &(info3.uni_logon_dom)))) {
+ if (!(nt_domain = unistr2_tdup(state->mem_ctx, &(info3.uni_logon_dom)))) {
/* If the server didn't give us one, just use the one we sent them */
nt_domain = name_domain;
}
@@ -653,9 +797,6 @@ done:
state->response.data.auth.nt_status_string,
state->response.data.auth.pam_error));
- if (mem_ctx)
- talloc_destroy(mem_ctx);
-
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
@@ -666,20 +807,13 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
NTSTATUS result;
char *oldpass, *newpass;
fstring domain, user;
- CLI_POLICY_HND *hnd;
- TALLOC_CTX *mem_ctx;
+ POLICY_HND dom_pol;
struct winbindd_domain *contact_domain;
+ struct rpc_pipe_client *cli;
DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
state->request.data.chauthtok.user));
- if (!(mem_ctx = talloc_init("winbind password change for %s",
- state->request.data.chauthtok.user))) {
- DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
- result = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
/* Setup crap */
if (state == NULL)
@@ -701,12 +835,15 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
/* Get sam handle */
- if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(contact_domain, &hnd)) ) {
+ result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
+ &dom_pol);
+ if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
goto done;
}
- result = cli_samr_chgpasswd_user(hnd->cli, mem_ctx, user, newpass, oldpass);
+ result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass,
+ oldpass);
done:
state->response.data.auth.nt_status = NT_STATUS_V(result);
@@ -721,8 +858,5 @@ done:
state->response.data.auth.nt_status_string,
state->response.data.auth.pam_error));
- if (mem_ctx)
- talloc_destroy(mem_ctx);
-
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
diff --git a/source3/nsswitch/winbindd_passdb.c b/source3/nsswitch/winbindd_passdb.c
index f0484d35ee..4b22712e0a 100644
--- a/source3/nsswitch/winbindd_passdb.c
+++ b/source3/nsswitch/winbindd_passdb.c
@@ -57,7 +57,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
enum SID_NAME_USE type;
uint32 num_names;
- DOM_SID **sid_mem;
+ DOM_SID *sid_mem;
char **names;
uint32 *types;
@@ -126,7 +126,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
for (i=0; i<num_names; i++) {
DEBUG(10, ("Adding group member SID %s\n",
- sid_string_static(sid_mem[i])));
+ sid_string_static(&sid_mem[i])));
if (types[i] != SID_NAME_USER) {
DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
@@ -297,24 +297,29 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,
- uint32 *num_groups, DOM_SID ***user_gids)
+ uint32 *num_groups, DOM_SID **user_gids)
{
return NT_STATUS_NO_SUCH_USER;
}
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 num_sids, DOM_SID **sids,
- uint32 *num_aliases, uint32 **aliases)
+ uint32 num_sids, const DOM_SID *sids,
+ uint32 *num_aliases, uint32 **rids)
{
- return NT_STATUS_NO_SUCH_USER;
+ BOOL result;
+
+ result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
+ sids, num_sids, rids, num_aliases);
+
+ return result ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
}
/* Lookup group membership given a rid. */
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names,
- DOM_SID ***sid_mem, char ***names,
+ DOM_SID **sid_mem, char ***names,
uint32 **name_types)
{
return NT_STATUS_OK;
diff --git a/source3/nsswitch/winbindd_reconnect.c b/source3/nsswitch/winbindd_reconnect.c
new file mode 100644
index 0000000000..1a90717db3
--- /dev/null
+++ b/source3/nsswitch/winbindd_reconnect.c
@@ -0,0 +1,273 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Wrapper around winbindd_rpc.c to centralize retry logic.
+
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern struct winbindd_methods msrpc_methods;
+
+/* List all users */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.query_user_list(domain, mem_ctx,
+ num_entries, info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.query_user_list(domain, mem_ctx,
+ num_entries, info);
+ return result;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
+ num_entries, info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
+ num_entries, info);
+ return result;
+}
+
+/* List all domain groups */
+
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.enum_local_groups(domain, mem_ctx,
+ num_entries, info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.enum_local_groups(domain, mem_ctx,
+ num_entries, info);
+
+ return result;
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum SID_NAME_USE *type)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.name_to_sid(domain, mem_ctx,
+ domain_name, name,
+ sid, type);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.name_to_sid(domain, mem_ctx,
+ domain_name, name,
+ sid, type);
+
+ return result;
+}
+
+/*
+ convert a domain SID to a user or group name
+*/
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **domain_name,
+ char **name,
+ enum SID_NAME_USE *type)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
+ domain_name, name, type);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
+ domain_name, name, type);
+
+ return result;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *user_info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
+ user_info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
+ user_info);
+
+ return result;
+}
+
+/* Lookup groups a user is a member of. I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID **user_gids)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
+ user_sid, num_groups,
+ user_gids);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
+ user_sid, num_groups,
+ user_gids);
+
+ return result;
+}
+
+static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 num_sids, const DOM_SID *sids,
+ uint32 *num_aliases, uint32 **alias_rids)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
+ num_sids, sids,
+ num_aliases,
+ alias_rids);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
+ num_sids, sids,
+ num_aliases,
+ alias_rids);
+
+ return result;
+}
+
+/* Lookup group membership given a rid. */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
+ group_sid, num_names,
+ sid_mem, names,
+ name_types);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
+ group_sid, num_names,
+ sid_mem, names,
+ name_types);
+
+ return result;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.sequence_number(domain, seq);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.sequence_number(domain, seq);
+
+ return result;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.trusted_domains(domain, mem_ctx,
+ num_domains, names,
+ alt_names, dom_sids);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.trusted_domains(domain, mem_ctx,
+ num_domains, names,
+ alt_names, dom_sids);
+
+ return result;
+}
+
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.alternate_name(domain);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.alternate_name(domain);
+
+ return result;
+}
+
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods reconnect_methods = {
+ False,
+ query_user_list,
+ enum_dom_groups,
+ enum_local_groups,
+ name_to_sid,
+ sid_to_name,
+ query_user,
+ lookup_usergroups,
+ lookup_useraliases,
+ lookup_groupmem,
+ sequence_number,
+ trusted_domains,
+ alternate_name
+};
diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c
index 854688da4e..2b4c020d88 100644
--- a/source3/nsswitch/winbindd_rpc.c
+++ b/source3/nsswitch/winbindd_rpc.c
@@ -37,37 +37,20 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
uint32 *num_entries,
WINBIND_USERINFO **info)
{
- CLI_POLICY_HND *hnd;
- NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ NTSTATUS result;
POLICY_HND dom_pol;
- BOOL got_dom_pol = False;
- uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
- unsigned int i, start_idx, retry;
+ unsigned int i, start_idx;
uint32 loop_count;
+ struct rpc_pipe_client *cli;
DEBUG(3,("rpc: query_user_list\n"));
*num_entries = 0;
*info = NULL;
- retry = 0;
- do {
- /* Get sam handle */
-
- if ( !NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)) )
- return result;
-
- /* Get domain handle */
-
- result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
- des_access, &domain->sid, &dom_pol);
-
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
-
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_dom_pol = True;
+ return result;
i = start_idx = 0;
loop_count = 0;
@@ -83,28 +66,30 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
ZERO_STRUCT( info1 );
ctr.sam.info1 = &info1;
- if (!(ctx2 = talloc_init("winbindd enum_users"))) {
- result = NT_STATUS_NO_MEMORY;
- goto done;
- }
+ if (!(ctx2 = talloc_init("winbindd enum_users")))
+ return NT_STATUS_NO_MEMORY;
/* this next bit is copied from net_user_list_internal() */
- get_query_dispinfo_params( loop_count, &max_entries, &max_size );
+ get_query_dispinfo_params(loop_count, &max_entries,
+ &max_size);
- result = cli_samr_query_dispinfo(hnd->cli, mem_ctx, &dom_pol,
- &start_idx, 1, &num_dom_users, max_entries, max_size, &ctr);
+ result = rpccli_samr_query_dispinfo(cli, mem_ctx, &dom_pol,
+ &start_idx, 1,
+ &num_dom_users,
+ max_entries, max_size,
+ &ctr);
loop_count++;
*num_entries += num_dom_users;
- *info = TALLOC_REALLOC_ARRAY( mem_ctx, *info, WINBIND_USERINFO, *num_entries);
+ *info = TALLOC_REALLOC_ARRAY(mem_ctx, *info, WINBIND_USERINFO,
+ *num_entries);
if (!(*info)) {
- result = NT_STATUS_NO_MEMORY;
talloc_destroy(ctx2);
- goto done;
+ return NT_STATUS_NO_MEMORY;
}
for (j = 0; j < num_dom_users; i++, j++) {
@@ -116,7 +101,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
(*info)[i].acct_name = talloc_strdup(mem_ctx, username );
(*info)[i].full_name = talloc_strdup(mem_ctx, fullname );
- (*info)[i].user_sid = rid_to_talloced_sid(domain, mem_ctx, rid );
+ sid_compose(&(*info)[i].user_sid, &domain->sid, rid);
/* For the moment we set the primary group for
every user to be the Domain Users group.
@@ -126,19 +111,14 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
force group' smb.conf parameter or
something like that. */
- (*info)[i].group_sid = rid_to_talloced_sid(domain,
- mem_ctx, DOMAIN_GROUP_RID_USERS);
+ sid_compose(&(*info)[i].group_sid, &domain->sid,
+ DOMAIN_GROUP_RID_USERS);
}
talloc_destroy(ctx2);
} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
- done:
-
- if (got_dom_pol)
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
return result;
}
@@ -148,28 +128,17 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
uint32 *num_entries,
struct acct_info **info)
{
- uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
- CLI_POLICY_HND *hnd;
POLICY_HND dom_pol;
NTSTATUS status;
uint32 start = 0;
- int retry;
- NTSTATUS result;
+ struct rpc_pipe_client *cli;
*num_entries = 0;
*info = NULL;
DEBUG(3,("rpc: enum_dom_groups\n"));
- retry = 0;
- do {
- if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
- return result;
-
- status = cli_samr_open_domain(hnd->cli, mem_ctx,
- &hnd->pol, des_access, &domain->sid, &dom_pol);
- } while (!NT_STATUS_IS_OK(status) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
-
+ status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(status))
return status;
@@ -181,10 +150,10 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
/* start is updated by this call. */
- status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
- &start,
- 0xFFFF, /* buffer size? */
- &info2, &count);
+ status = rpccli_samr_enum_dom_groups(cli, mem_ctx2, &dom_pol,
+ &start,
+ 0xFFFF, /* buffer size? */
+ &info2, &count);
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
@@ -192,11 +161,13 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
break;
}
- (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info, struct acct_info, (*num_entries) + count);
+ (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
+ struct acct_info,
+ (*num_entries) + count);
if (! *info) {
talloc_destroy(mem_ctx2);
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ break;
}
memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
@@ -204,9 +175,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
talloc_destroy(mem_ctx2);
} while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
- return status;
+ return NT_STATUS_OK;
}
/* List all domain groups */
@@ -216,25 +185,17 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
uint32 *num_entries,
struct acct_info **info)
{
- uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
- CLI_POLICY_HND *hnd;
POLICY_HND dom_pol;
NTSTATUS result;
- int retry;
+ struct rpc_pipe_client *cli;
*num_entries = 0;
*info = NULL;
- retry = 0;
- do {
- if ( !NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)) )
- return result;
-
- result = cli_samr_open_domain( hnd->cli, mem_ctx, &hnd->pol,
- des_access, &domain->sid, &dom_pol);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
+ DEBUG(3,("rpc: enum_local_groups\n"));
- if ( !NT_STATUS_IS_OK(result))
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
return result;
do {
@@ -244,31 +205,32 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
mem_ctx2 = talloc_init("enum_dom_local_groups[rpc]");
- result = cli_samr_enum_als_groups( hnd->cli, mem_ctx2, &dom_pol,
- &start, 0xFFFF, &info2, &count);
+ result = rpccli_samr_enum_als_groups( cli, mem_ctx2, &dom_pol,
+ &start, 0xFFFF, &info2,
+ &count);
- if ( !NT_STATUS_IS_OK(result)
- && !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) )
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) )
{
talloc_destroy(mem_ctx2);
- break;
+ return result;
}
- (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info, struct acct_info, (*num_entries) + count);
+ (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
+ struct acct_info,
+ (*num_entries) + count);
if (! *info) {
talloc_destroy(mem_ctx2);
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
return NT_STATUS_NO_MEMORY;
}
memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
(*num_entries) += count;
talloc_destroy(mem_ctx2);
- } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
- return result;
+ return NT_STATUS_OK;
}
/* convert a single name to a sid in a domain */
@@ -279,12 +241,12 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
DOM_SID *sid,
enum SID_NAME_USE *type)
{
- CLI_POLICY_HND *hnd;
NTSTATUS result;
DOM_SID *sids = NULL;
uint32 *types = NULL;
const char *full_name;
- int retry;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
if(name == NULL || *name=='\0') {
DEBUG(3,("rpc: name_to_sid name=%s\n", domain_name));
@@ -300,25 +262,22 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", name?name:"", domain_name ));
- retry = 0;
- do {
- if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(domain, &hnd))) {
- return result;
- }
-
- result = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
- &full_name, &sids, &types);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
- hnd && hnd->cli && hnd->cli->fd == -1);
+ result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_lsa_lookup_names(cli, mem_ctx, &lsa_policy, 1,
+ &full_name, &sids, &types);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
/* Return rid and type if lookup successful */
- if (NT_STATUS_IS_OK(result)) {
- sid_copy(sid, &sids[0]);
- *type = (enum SID_NAME_USE)types[0];
- }
+ sid_copy(sid, &sids[0]);
+ *type = (enum SID_NAME_USE)types[0];
- return result;
+ return NT_STATUS_OK;
}
/*
@@ -331,34 +290,30 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
char **name,
enum SID_NAME_USE *type)
{
- CLI_POLICY_HND *hnd;
char **domains;
char **names;
uint32 *types;
NTSTATUS result;
- int retry;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_static(sid),
domain->name ));
- retry = 0;
- do {
- if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(domain, &hnd)))
- return result;
-
- result = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
- 1, sid, &domains, &names, &types);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
- hnd && hnd->cli && hnd->cli->fd == -1);
+ result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- if (NT_STATUS_IS_OK(result)) {
- *type = (enum SID_NAME_USE)types[0];
- *domain_name = domains[0];
- *name = names[0];
- DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
- }
+ result = rpccli_lsa_lookup_sids(cli, mem_ctx, &lsa_policy,
+ 1, sid, &domains, &names, &types);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- return result;
+ *type = (enum SID_NAME_USE)types[0];
+ *domain_name = domains[0];
+ *name = names[0];
+ DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
+ return NT_STATUS_OK;
}
/* Lookup user information from a rid or username. */
@@ -367,20 +322,19 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
const DOM_SID *user_sid,
WINBIND_USERINFO *user_info)
{
- CLI_POLICY_HND *hnd = NULL;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
POLICY_HND dom_pol, user_pol;
- BOOL got_dom_pol = False, got_user_pol = False;
SAM_USERINFO_CTR *ctr;
- int retry;
fstring sid_string;
uint32 user_rid;
NET_USER_INFO_3 *user;
+ struct rpc_pipe_client *cli;
- DEBUG(3,("rpc: query_user rid=%s\n", sid_to_string(sid_string, user_sid)));
- if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
- goto done;
- }
+ DEBUG(3,("rpc: query_user rid=%s\n",
+ sid_to_string(sid_string, user_sid)));
+
+ if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
+ return NT_STATUS_UNSUCCESSFUL;
/* try netsamlogon cache first */
@@ -389,12 +343,15 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
sid_string_static(user_sid)));
-
- user_info->user_sid = rid_to_talloced_sid( domain, mem_ctx, user_rid );
- user_info->group_sid = rid_to_talloced_sid( domain, mem_ctx, user->group_rid );
+
+ sid_compose(&user_info->user_sid, &domain->sid, user_rid);
+ sid_compose(&user_info->group_sid, &domain->sid,
+ user->group_rid);
- user_info->acct_name = unistr2_tdup(mem_ctx, &user->uni_user_name);
- user_info->full_name = unistr2_tdup(mem_ctx, &user->uni_full_name);
+ user_info->acct_name = unistr2_tdup(mem_ctx,
+ &user->uni_user_name);
+ user_info->full_name = unistr2_tdup(mem_ctx,
+ &user->uni_full_name);
SAFE_FREE(user);
@@ -403,82 +360,59 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
/* no cache; hit the wire */
- retry = 0;
- do {
- /* Get sam handle; if we fail here there is no hope */
-
- if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
- goto done;
-
- /* Get domain handle */
-
- result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
- SEC_RIGHTS_MAXIMUM_ALLOWED,
- &domain->sid, &dom_pol);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
- hnd && hnd->cli && hnd->cli->fd == -1);
-
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_dom_pol = True;
+ return result;
/* Get user handle */
- result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
- SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
+ result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
+ &user_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_user_pol = True;
+ return result;
/* Get user info */
- result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
- 0x15, &ctr);
+ result = rpccli_samr_query_userinfo(cli, mem_ctx, &user_pol,
+ 0x15, &ctr);
- if (!NT_STATUS_IS_OK(result))
- goto done;
+ rpccli_samr_close(cli, mem_ctx, &user_pol);
- cli_samr_close(hnd->cli, mem_ctx, &user_pol);
- got_user_pol = False;
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- user_info->user_sid = rid_to_talloced_sid(domain, mem_ctx, user_rid);
- user_info->group_sid = rid_to_talloced_sid(domain, mem_ctx, ctr->info.id21->group_rid);
+ sid_compose(&user_info->user_sid, &domain->sid, user_rid);
+ sid_compose(&user_info->group_sid, &domain->sid,
+ ctr->info.id21->group_rid);
user_info->acct_name = unistr2_tdup(mem_ctx,
&ctr->info.id21->uni_user_name);
user_info->full_name = unistr2_tdup(mem_ctx,
&ctr->info.id21->uni_full_name);
- done:
- /* Clean up policy handles */
- if (got_user_pol)
- cli_samr_close(hnd->cli, mem_ctx, &user_pol);
-
- if (got_dom_pol)
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
- return result;
+ return NT_STATUS_OK;
}
/* Lookup groups a user is a member of. I wish Unix had a call like this! */
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,
- uint32 *num_groups, DOM_SID ***user_grpsids)
+ uint32 *num_groups, DOM_SID **user_grpsids)
{
- CLI_POLICY_HND *hnd;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
POLICY_HND dom_pol, user_pol;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
- BOOL got_dom_pol = False, got_user_pol = False;
DOM_GID *user_groups;
unsigned int i;
- unsigned int retry;
fstring sid_string;
uint32 user_rid;
NET_USER_INFO_3 *user;
+ struct rpc_pipe_client *cli;
+
+ DEBUG(3,("rpc: lookup_usergroups sid=%s\n",
+ sid_to_string(sid_string, user_sid)));
- DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_to_string(sid_string, user_sid)));
+ if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
+ return NT_STATUS_UNSUCCESSFUL;
*num_groups = 0;
*user_grpsids = NULL;
@@ -492,9 +426,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
*num_groups = user->num_groups;
- (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID*, *num_groups);
+ (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
for (i=0;i<(*num_groups);i++) {
- (*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user->gids[i].g_rid);
+ sid_copy(&((*user_grpsids)[i]), &domain->sid);
+ sid_append_rid(&((*user_grpsids)[i]),
+ user->gids[i].g_rid);
}
SAFE_FREE(user);
@@ -504,124 +440,73 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
/* no cache; hit the wire */
- retry = 0;
- do {
- /* Get sam handle; if we fail here there is no hope */
-
- if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
- goto done;
-
- /* Get domain handle */
-
- result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
- des_access, &domain->sid, &dom_pol);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
- hnd && hnd->cli && hnd->cli->fd == -1);
-
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_dom_pol = True;
-
-
- if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
- goto done;
- }
+ return result;
/* Get user handle */
- result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
+ result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol,
des_access, user_rid, &user_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_user_pol = True;
+ return result;
/* Query user rids */
- result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
+ result = rpccli_samr_query_usergroups(cli, mem_ctx, &user_pol,
num_groups, &user_groups);
+ rpccli_samr_close(cli, mem_ctx, &user_pol);
+
if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
- goto done;
+ return result;
- (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups);
- if (!(*user_grpsids)) {
- result = NT_STATUS_NO_MEMORY;
- goto done;
- }
+ (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
+ if (!(*user_grpsids))
+ return NT_STATUS_NO_MEMORY;
for (i=0;i<(*num_groups);i++) {
- (*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user_groups[i].g_rid);
+ sid_copy(&((*user_grpsids)[i]), &domain->sid);
+ sid_append_rid(&((*user_grpsids)[i]),
+ user_groups[i].g_rid);
}
- done:
- /* Clean up policy handles */
- if (got_user_pol)
- cli_samr_close(hnd->cli, mem_ctx, &user_pol);
-
- if (got_dom_pol)
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
- return result;
+ return NT_STATUS_OK;
}
NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32 num_sids, DOM_SID **sids,
+ uint32 num_sids, const DOM_SID *sids,
uint32 *num_aliases, uint32 **alias_rids)
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
- CLI_POLICY_HND *hnd;
- BOOL got_dom_pol = False;
POLICY_HND dom_pol;
DOM_SID2 *sid2;
- int i, retry;
+ int i;
+ struct rpc_pipe_client *cli;
*num_aliases = 0;
*alias_rids = NULL;
- retry = 0;
- do {
- /* Get sam handle; if we fail here there is no hope */
-
- if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain,
- &hnd)))
- goto done;
-
- /* Get domain handle */
-
- result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
- SEC_RIGHTS_MAXIMUM_ALLOWED,
- &domain->sid, &dom_pol);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
- hnd && hnd->cli && hnd->cli->fd == -1);
+ DEBUG(3,("rpc: lookup_useraliases\n"));
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_dom_pol = True;
+ return result;
sid2 = TALLOC_ARRAY(mem_ctx, DOM_SID2, num_sids);
- if (sid2 == NULL) {
- result = NT_STATUS_NO_MEMORY;
- goto done;
- }
+ if (sid2 == NULL)
+ return NT_STATUS_NO_MEMORY;
for (i=0; i<num_sids; i++) {
- sid_copy(&sid2[i].sid, sids[i]);
+ sid_copy(&sid2[i].sid, &sids[i]);
sid2[i].num_auths = sid2[i].sid.num_auths;
}
- result = cli_samr_query_useraliases(hnd->cli, mem_ctx, &dom_pol,
- num_sids, sid2,
- num_aliases, alias_rids);
-
- done:
+ result = rpccli_samr_query_useraliases(cli, mem_ctx, &dom_pol,
+ num_sids, sid2,
+ num_aliases, alias_rids);
- if (got_dom_pol)
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
return result;
}
@@ -630,71 +515,54 @@ NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names,
- DOM_SID ***sid_mem, char ***names,
+ DOM_SID **sid_mem, char ***names,
uint32 **name_types)
{
- CLI_POLICY_HND *hnd = NULL;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
uint32 i, total_names = 0;
POLICY_HND dom_pol, group_pol;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
- BOOL got_dom_pol = False, got_group_pol = False;
uint32 *rid_mem = NULL;
uint32 group_rid;
- int retry;
unsigned int j;
fstring sid_string;
+ struct rpc_pipe_client *cli;
- DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name, sid_to_string(sid_string, group_sid)));
+ DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name,
+ sid_to_string(sid_string, group_sid)));
- if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid)) {
- goto done;
- }
+ if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid))
+ return NT_STATUS_UNSUCCESSFUL;
*num_names = 0;
- retry = 0;
- do {
- /* Get sam handle */
- if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
- goto done;
-
- /* Get domain handle */
-
- result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
- des_access, &domain->sid, &dom_pol);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
-
- if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_dom_pol = True;
-
- /* Get group handle */
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
- des_access, group_rid, &group_pol);
+ result = rpccli_samr_open_group(cli, mem_ctx, &dom_pol,
+ des_access, group_rid, &group_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
-
- got_group_pol = True;
+ return result;
/* Step #1: Get a list of user rids that are the members of the
group. */
- result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
- &group_pol, num_names, &rid_mem,
- name_types);
+ result = rpccli_samr_query_groupmem(cli, mem_ctx,
+ &group_pol, num_names, &rid_mem,
+ name_types);
+
+ rpccli_samr_close(cli, mem_ctx, &group_pol);
if (!NT_STATUS_IS_OK(result))
- goto done;
+ return result;
if (!*num_names) {
names = NULL;
name_types = NULL;
sid_mem = NULL;
- goto done;
+ return NT_STATUS_OK;
}
/* Step #2: Convert list of rids into list of usernames. Do this
@@ -706,16 +574,13 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
*names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
*name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
- *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, *num_names);
+ *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_names);
- for (j=0;j<(*num_names);j++) {
- (*sid_mem)[j] = rid_to_talloced_sid(domain, mem_ctx, (rid_mem)[j]);
- }
+ for (j=0;j<(*num_names);j++)
+ sid_compose(&(*sid_mem)[j], &domain->sid, rid_mem[j]);
- if (*num_names>0 && (!*names || !*name_types)) {
- result = NT_STATUS_NO_MEMORY;
- goto done;
- }
+ if (*num_names>0 && (!*names || !*name_types))
+ return NT_STATUS_NO_MEMORY;
for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
@@ -725,18 +590,19 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
/* Lookup a chunk of rids */
- result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
- &dom_pol,
- num_lookup_rids,
- &rid_mem[i],
- &tmp_num_names,
- &tmp_names, &tmp_types);
+ result = rpccli_samr_lookup_rids(cli, mem_ctx,
+ &dom_pol,
+ num_lookup_rids,
+ &rid_mem[i],
+ &tmp_num_names,
+ &tmp_names, &tmp_types);
- /* see if we have a real error (and yes the STATUS_SOME_UNMAPPED is
- the one returned from 2k) */
+ /* see if we have a real error (and yes the
+ STATUS_SOME_UNMAPPED is the one returned from 2k) */
- if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != NT_STATUS_V(STATUS_SOME_UNMAPPED))
- goto done;
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
+ return result;
/* Copy result into array. The talloc system will take
care of freeing the temporary arrays later on. */
@@ -752,16 +618,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
*num_names = total_names;
- result = NT_STATUS_OK;
-
-done:
- if (got_group_pol)
- cli_samr_close(hnd->cli, mem_ctx, &group_pol);
-
- if (got_dom_pol)
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
- return result;
+ return NT_STATUS_OK;
}
#ifdef HAVE_LDAP
@@ -780,11 +637,12 @@ static int get_ldap_seq(const char *server, int port, uint32 *seq)
*seq = DOM_SEQUENCE_NONE;
/*
- * Parameterised (5) second timeout on open. This is needed as the search timeout
- * doesn't seem to apply to doing an open as well. JRA.
+ * Parameterised (5) second timeout on open. This is needed as the
+ * search timeout doesn't seem to apply to doing an open as well. JRA.
*/
- if ((ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout())) == NULL)
+ ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout());
+ if (ldp == NULL)
return -1;
/* Timeout if no response within 20 seconds. */
@@ -792,7 +650,7 @@ static int get_ldap_seq(const char *server, int port, uint32 *seq)
to.tv_usec = 0;
if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)",
- CONST_DISCARD(char **, &attrs[0]), 0, &to, &res))
+ CONST_DISCARD(char **, attrs), 0, &to, &res))
goto done;
if (ldap_count_entries(ldp, res) != 1)
@@ -838,8 +696,10 @@ static int get_ldap_sequence_number( const char* domain, uint32 *seq)
for (i = 0; i < count; i++) {
fstring ipstr;
- /* since the is an LDAP lookup, default to the LDAP_PORT is not set */
- port = (ip_list[i].port!= PORT_NONE) ? ip_list[i].port : LDAP_PORT;
+ /* since the is an LDAP lookup, default to the LDAP_PORT is
+ * not set */
+ port = (ip_list[i].port!= PORT_NONE) ?
+ ip_list[i].port : LDAP_PORT;
fstrcpy( ipstr, inet_ntoa(ip_list[i].ip) );
@@ -850,12 +710,14 @@ static int get_ldap_sequence_number( const char* domain, uint32 *seq)
goto done;
/* add to failed connection cache */
- add_failed_connection_entry( domain, ipstr, NT_STATUS_UNSUCCESSFUL );
+ add_failed_connection_entry( domain, ipstr,
+ NT_STATUS_UNSUCCESSFUL );
}
done:
if ( ret == 0 ) {
- DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence number for Domain (%s) from DC (%s:%d)\n",
+ DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence "
+ "number for Domain (%s) from DC (%s:%d)\n",
domain, inet_ntoa(ip_list[i].ip), port));
}
@@ -870,14 +732,12 @@ done:
static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
{
TALLOC_CTX *mem_ctx;
- CLI_POLICY_HND *hnd;
SAM_UNK_CTR ctr;
NTSTATUS result;
POLICY_HND dom_pol;
- BOOL got_dom_pol = False;
BOOL got_seq_num = False;
- uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
int retry;
+ struct rpc_pipe_client *cli;
DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
@@ -887,41 +747,39 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
return NT_STATUS_NO_MEMORY;
retry = 0;
- do {
-#ifdef HAVE_LDAP
- if ( domain->native_mode )
- {
- DEBUG(8,("using get_ldap_seq() to retrieve the sequence number\n"));
-
- if ( get_ldap_sequence_number( domain->name, seq ) == 0 ) {
- result = NT_STATUS_OK;
- DEBUG(10,("domain_sequence_number: LDAP for domain %s is %u\n",
- domain->name, *seq));
- goto done;
- }
- DEBUG(10,("domain_sequence_number: failed to get LDAP sequence number for domain %s\n",
- domain->name ));
- }
-#endif /* HAVE_LDAP */
- /* Get sam handle */
- if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
+#ifdef HAVE_LDAP
+ if ( domain->native_mode )
+ {
+ int res;
+
+ DEBUG(8,("using get_ldap_seq() to retrieve the "
+ "sequence number\n"));
+
+ res = get_ldap_sequence_number( domain->name, seq );
+ if (res == 0)
+ {
+ result = NT_STATUS_OK;
+ DEBUG(10,("domain_sequence_number: LDAP for "
+ "domain %s is %u\n",
+ domain->name, *seq));
goto done;
+ }
- /* Get domain handle */
- result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
- des_access, &domain->sid, &dom_pol);
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
+ DEBUG(10,("domain_sequence_number: failed to get LDAP "
+ "sequence number for domain %s\n",
+ domain->name ));
+ }
+#endif /* HAVE_LDAP */
- if (!NT_STATUS_IS_OK(result))
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result)) {
goto done;
-
- got_dom_pol = True;
+ }
/* Query domain info */
- result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
- 8, &ctr);
+ result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 8, &ctr);
if (NT_STATUS_IS_OK(result)) {
*seq = ctr.info.inf8.seq_num.low;
@@ -932,8 +790,7 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
/* retry with info-level 2 in case the dc does not support info-level 8
* (like all older samba2 and samba3 dc's - Guenther */
- result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
- 2, &ctr);
+ result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 2, &ctr);
if (NT_STATUS_IS_OK(result)) {
*seq = ctr.info.inf2.seq_num.low;
@@ -942,17 +799,16 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
seq_num:
if (got_seq_num) {
- DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)*seq));
+ DEBUG(10,("domain_sequence_number: for domain %s is %u\n",
+ domain->name, (unsigned)*seq));
} else {
- DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
- (unsigned)*seq, domain->name ));
+ DEBUG(10,("domain_sequence_number: failed to get sequence "
+ "number (%u) for domain %s\n",
+ (unsigned)*seq, domain->name ));
}
done:
- if (got_dom_pol)
- cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
talloc_destroy(mem_ctx);
return result;
@@ -966,10 +822,10 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
char ***alt_names,
DOM_SID **dom_sids)
{
- CLI_POLICY_HND *hnd;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
uint32 enum_ctx = 0;
- int retry;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
DEBUG(3,("rpc: trusted_domains\n"));
@@ -978,46 +834,45 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
*alt_names = NULL;
*dom_sids = NULL;
- retry = 0;
- do {
- if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(find_our_domain(), &hnd)))
- goto done;
+ result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- result = STATUS_MORE_ENTRIES;
-
- while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
- uint32 start_idx, num;
- char **tmp_names;
- DOM_SID *tmp_sids;
- int i;
-
- result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
- &hnd->pol, &enum_ctx,
- &num, &tmp_names,
- &tmp_sids);
-
- if (!NT_STATUS_IS_OK(result) &&
- !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
- break;
-
- start_idx = *num_domains;
- *num_domains += num;
- *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
- char *, *num_domains);
- *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
- DOM_SID,
- *num_domains);
- if ((*names == NULL) || (*dom_sids == NULL))
- return NT_STATUS_NO_MEMORY;
-
- for (i=0; i<num; i++) {
- (*names)[start_idx+i] = tmp_names[i];
- (*dom_sids)[start_idx+i] = tmp_sids[i];
- }
- }
- } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
+ result = STATUS_MORE_ENTRIES;
-done:
+ while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
+ uint32 start_idx, num;
+ char **tmp_names;
+ DOM_SID *tmp_sids;
+ int i;
+
+ result = rpccli_lsa_enum_trust_dom(cli, mem_ctx,
+ &lsa_policy, &enum_ctx,
+ &num, &tmp_names,
+ &tmp_sids);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
+ break;
+
+ start_idx = *num_domains;
+ *num_domains += num;
+ *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
+ char *, *num_domains);
+ *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
+ DOM_SID, *num_domains);
+ *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names,
+ char *, *num_domains);
+ if ((*names == NULL) || (*dom_sids == NULL) ||
+ (*alt_names == NULL))
+ return NT_STATUS_NO_MEMORY;
+
+ for (i=0; i<num; i++) {
+ (*names)[start_idx+i] = tmp_names[i];
+ (*dom_sids)[start_idx+i] = tmp_sids[i];
+ (*alt_names)[start_idx+i] = talloc_strdup(mem_ctx, "");
+ }
+ }
return result;
}
diff --git a/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c
index 060e66fbc2..f8fb5e93c2 100644
--- a/source3/nsswitch/winbindd_sid.c
+++ b/source3/nsswitch/winbindd_sid.c
@@ -28,12 +28,13 @@
/* Convert a string */
+static void lookupsid_recv(void *private, BOOL success,
+ const char *dom_name, const char *name,
+ enum SID_NAME_USE type);
+
enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
{
- enum SID_NAME_USE type;
DOM_SID sid;
- fstring name;
- fstring dom_name;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
@@ -41,38 +42,46 @@ enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
state->request.data.sid));
- /* Lookup sid from PDC using lsa_lookup_sids() */
-
if (!string_to_sid(&sid, state->request.data.sid)) {
DEBUG(5, ("%s not a SID\n", state->request.data.sid));
return WINBINDD_ERROR;
}
- /* Lookup the sid */
+ winbindd_lookupsid_async(state->mem_ctx, &sid, lookupsid_recv, state);
+ return WINBINDD_PENDING;
+}
- if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type)) {
- return WINBINDD_ERROR;
+static void lookupsid_recv(void *private, BOOL success,
+ const char *dom_name, const char *name,
+ enum SID_NAME_USE type)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("lookupsid returned an error\n"));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
}
fstrcpy(state->response.data.name.dom_name, dom_name);
fstrcpy(state->response.data.name.name, name);
-
state->response.data.name.type = type;
-
- return WINBINDD_OK;
+ state->response.result = WINBINDD_OK;
+ request_finished(state);
}
-
/**
* Look up the SID for a qualified name.
**/
+
+static void lookupname_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type);
+
enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
{
- enum SID_NAME_USE type;
- fstring sid_str;
char *name_domain, *name_user;
- DOM_SID sid;
- struct winbindd_domain *domain;
char *p;
/* Ensure null termination */
@@ -95,27 +104,48 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
name_domain, lp_winbind_separator(), name_user));
- if ((domain = find_lookup_domain_from_name(name_domain)) == NULL) {
- DEBUG(0, ("could not find domain entry for domain %s\n",
- name_domain));
- return WINBINDD_ERROR;
- }
+ winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
+ lookupname_recv, state);
+ return WINBINDD_PENDING;
+}
- /* Lookup name from PDC using lsa_lookup_names() */
- if (!winbindd_lookup_sid_by_name(domain, name_domain, name_user, &sid, &type)) {
- return WINBINDD_ERROR;
+static void lookupname_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("lookupname returned an error\n"));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
}
- sid_to_string(sid_str, &sid);
- fstrcpy(state->response.data.sid.sid, sid_str);
+ sid_to_string(state->response.data.sid.sid, sid);
state->response.data.sid.type = type;
+ state->response.result = WINBINDD_OK;
+ request_finished(state);
+ return;
+}
- return WINBINDD_OK;
+static struct winbindd_child static_idmap_child;
+
+void init_idmap_child(void)
+{
+ setup_domain_child(NULL, &static_idmap_child, "idmap");
+}
+
+struct winbindd_child *idmap_child(void)
+{
+ return &static_idmap_child;
}
/* Convert a sid to a uid. We assume we only have one rid attached to the
sid. */
+static void sid2uid_recv(void *private, BOOL success, uid_t uid);
+
enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
{
DOM_SID sid;
@@ -127,105 +157,53 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
state->request.data.sid));
- if (!string_to_sid(&sid, state->request.data.sid)) {
- DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
+ if (idmap_proxyonly()) {
+ DEBUG(8, ("IDMAP proxy only\n"));
return WINBINDD_ERROR;
}
-
- /* This gets a little tricky. If we assume that usernames are syncd between
- /etc/passwd and the windows domain (such as a member of a Samba domain),
- the we need to get the uid from the OS and not alocate one ourselves */
-
- if ( lp_winbind_trusted_domains_only() ) {
- struct winbindd_domain *domain = NULL;
- DOM_SID sid2;
- uint32 rid;
-
- domain = find_our_domain();
- if ( !domain ) {
- DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n"));
- return WINBINDD_ERROR;
- }
-
- sid_copy( &sid2, &sid );
- sid_split_rid( &sid2, &rid );
-
- if ( sid_equal( &sid2, &domain->sid ) ) {
-
- fstring domain_name;
- fstring user;
- enum SID_NAME_USE type;
- struct passwd *pw = NULL;
- unid_t id;
-
- /* ok...here's we know that we are dealing with our
- own domain (the one to which we are joined). And
- we know that there must be a UNIX account for this user.
- So we lookup the sid and the call getpwnam().*/
-
-
- /* But first check and see if we don't already have a mapping */
-
- if ( NT_STATUS_IS_OK(idmap_sid_to_uid(&sid, &(state->response.data.uid), ID_QUERY_ONLY)) )
- return WINBINDD_OK;
-
- /* now fall back to the hard way */
-
- if ( !winbindd_lookup_name_by_sid(&sid, domain_name, user, &type) )
- return WINBINDD_ERROR;
-
- if ( !(pw = getpwnam(user)) ) {
- DEBUG(0,("winbindd_sid_to_uid: 'winbind trusted domains only' is "
- "set but this user [%s] doesn't exist!\n", user));
- return WINBINDD_ERROR;
- }
-
- state->response.data.uid = pw->pw_uid;
-
- id.uid = pw->pw_uid;
- idmap_set_mapping( &sid, id, ID_USERID );
-
- return WINBINDD_OK;
- }
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
}
-
- /* Find uid for this sid and return it */
+
+ /* Query only the local tdb, everything else might possibly block */
result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
- ID_QUERY_ONLY);
+ ID_QUERY_ONLY|ID_CACHE_ONLY);
- if (NT_STATUS_IS_OK(result))
+ if (NT_STATUS_IS_OK(result)) {
return WINBINDD_OK;
+ }
- if (state->request.flags & WBFLAG_QUERY_ONLY)
- return WINBINDD_ERROR;
-
- /* The query-only did not work, allocate a new uid *if* it's a user */
-
- {
- fstring dom_name, name;
- enum SID_NAME_USE type;
-
- if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type))
- return WINBINDD_ERROR;
+ winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
+ return WINBINDD_PENDING;
+}
- if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))
- return WINBINDD_ERROR;
+static void sid2uid_recv(void *private, BOOL success, uid_t uid)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not convert sid %s\n",
+ state->request.data.sid));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
}
-
- result = idmap_sid_to_uid(&sid, &(state->response.data.uid), 0);
- if (NT_STATUS_IS_OK(result))
- return WINBINDD_OK;
-
- DEBUG(4, ("Could not get uid for sid %s\n", state->request.data.sid));
- return WINBINDD_ERROR;
+ state->response.result = WINBINDD_OK;
+ state->response.data.uid = uid;
+ request_finished(state);
}
/* Convert a sid to a gid. We assume we only have one rid attached to the
sid.*/
+static void sid2gid_recv(void *private, BOOL success, gid_t gid);
+
enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
{
DOM_SID sid;
@@ -234,253 +212,301 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
- DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
+ DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
state->request.data.sid));
- if (!string_to_sid(&sid, state->request.data.sid)) {
- DEBUG(1, ("Could not cvt string to sid %s\n", state->request.data.sid));
+ if (idmap_proxyonly()) {
+ DEBUG(8, ("IDMAP proxy only\n"));
return WINBINDD_ERROR;
}
- /* This gets a little tricky. If we assume that usernames are syncd between
- /etc/passwd and the windows domain (such as a member of a Samba domain),
- the we need to get the uid from the OS and not alocate one ourselves */
-
- if ( lp_winbind_trusted_domains_only() ) {
- struct winbindd_domain *domain = NULL;
- DOM_SID sid2;
- uint32 rid;
- unid_t id;
-
- domain = find_our_domain();
- if ( !domain ) {
- DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n"));
- return WINBINDD_ERROR;
- }
-
- sid_copy( &sid2, &sid );
- sid_split_rid( &sid2, &rid );
-
- if ( sid_equal( &sid2, &domain->sid ) ) {
-
- fstring domain_name;
- fstring group;
- enum SID_NAME_USE type;
- struct group *grp = NULL;
-
- /* ok...here's we know that we are dealing with our
- own domain (the one to which we are joined). And
- we know that there must be a UNIX account for this group.
- So we lookup the sid and the call getpwnam().*/
-
- /* But first check and see if we don't already have a mapping */
-
- if ( NT_STATUS_IS_OK(idmap_sid_to_gid(&sid, &(state->response.data.gid), ID_QUERY_ONLY)) )
- return WINBINDD_OK;
-
- /* now fall back to the hard way */
-
- if ( !winbindd_lookup_name_by_sid(&sid, domain_name, group, &type) )
- return WINBINDD_ERROR;
-
- if ( !(grp = getgrnam(group)) ) {
- DEBUG(0,("winbindd_sid_to_uid: 'winbind trusted domains only' is "
- "set but this group [%s] doesn't exist!\n", group));
- return WINBINDD_ERROR;
- }
-
- state->response.data.gid = grp->gr_gid;
-
- id.gid = grp->gr_gid;
- idmap_set_mapping( &sid, id, ID_GROUPID );
-
- return WINBINDD_OK;
- }
-
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
}
-
- /* Find gid for this sid and return it */
+
+ /* Query only the local tdb, everything else might possibly block */
result = idmap_sid_to_gid(&sid, &(state->response.data.gid),
- ID_QUERY_ONLY);
+ ID_QUERY_ONLY|ID_CACHE_ONLY);
- if (NT_STATUS_IS_OK(result))
+ if (NT_STATUS_IS_OK(result)) {
return WINBINDD_OK;
+ }
- if (state->request.flags & WBFLAG_QUERY_ONLY)
- return WINBINDD_ERROR;
+ winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
+ return WINBINDD_PENDING;
+}
- /* The query-only did not work, allocate a new gid *if* it's a group */
-
- {
- fstring dom_name, name;
- enum SID_NAME_USE type;
-
- if (sid_check_is_in_our_domain(&sid)) {
- /* This is for half-created aliases... */
- type = SID_NAME_ALIAS;
- } else {
- /* Foreign domains need to be looked up by the DC if
- * it's the right type */
- if (!winbindd_lookup_name_by_sid(&sid, dom_name, name,
- &type))
- return WINBINDD_ERROR;
- }
-
- if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
- (type != SID_NAME_WKN_GRP))
- return WINBINDD_ERROR;
+static void sid2gid_recv(void *private, BOOL success, gid_t gid)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not convert sid %s\n",
+ state->request.data.sid));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
}
-
- result = idmap_sid_to_gid(&sid, &(state->response.data.gid), 0);
-
- if (NT_STATUS_IS_OK(result))
- return WINBINDD_OK;
- DEBUG(4, ("Could not get gid for sid %s\n", state->request.data.sid));
- return WINBINDD_ERROR;
+ state->response.result = WINBINDD_OK;
+ state->response.data.gid = gid;
+ request_finished(state);
}
/* Convert a uid to a sid */
+struct uid2sid_state {
+ struct winbindd_cli_state *cli_state;
+ uid_t uid;
+ fstring name;
+ DOM_SID sid;
+ enum SID_NAME_USE type;
+};
+
+static void uid2sid_uid2name_recv(void *private, BOOL success,
+ const char *username);
+static void uid2sid_lookupname_recv(void *private, BOOL success,
+ const DOM_SID *sid,
+ enum SID_NAME_USE type);
+static void uid2sid_idmap_set_mapping_recv(void *private, BOOL success);
+
enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state)
{
DOM_SID sid;
+ NTSTATUS status;
+ struct uid2sid_state *uid2sid_state;
DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.uid));
- if ( (state->request.data.uid < server_state.uid_low )
- || (state->request.data.uid > server_state.uid_high) )
- {
- struct passwd *pw = NULL;
- enum SID_NAME_USE type;
- unid_t id;
- struct winbindd_domain *domain;
-
- /* SPECIAL CASE FOR MEMBERS OF SAMBA DOMAINS */
-
- /* if we don't trust /etc/password then when can't know
- anything about this uid */
-
- if ( !lp_winbind_trusted_domains_only() )
- return WINBINDD_ERROR;
-
-
- /* look for an idmap entry first */
-
- if ( NT_STATUS_IS_OK(idmap_uid_to_sid(&sid, state->request.data.uid)) )
- goto done;
-
- /* if users exist in /etc/passwd, we should try to
- use that uid. Get the username and the lookup the SID */
-
- if ( !(pw = getpwuid(state->request.data.uid)) )
- return WINBINDD_ERROR;
-
- if ( !(domain = find_our_domain()) ) {
- DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n"));
- return WINBINDD_ERROR;
- }
-
- if ( !winbindd_lookup_sid_by_name(domain, domain->name, pw->pw_name, &sid, &type) )
- return WINBINDD_ERROR;
-
- if ( type != SID_NAME_USER )
- return WINBINDD_ERROR;
-
- /* don't fail if we can't store it */
-
- id.uid = pw->pw_uid;
- idmap_set_mapping( &sid, id, ID_USERID );
-
- goto done;
+ if (idmap_proxyonly()) {
+ DEBUG(8, ("IDMAP proxy only\n"));
+ return WINBINDD_ERROR;
}
- /* Lookup rid for this uid */
-
- if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&sid, state->request.data.uid))) {
- DEBUG(1, ("Could not convert uid %lu to rid\n",
- (unsigned long)state->request.data.uid));
+ status = idmap_uid_to_sid(&sid, state->request.data.uid,
+ ID_QUERY_ONLY | ID_CACHE_ONLY);
+
+ if (NT_STATUS_IS_OK(status)) {
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_USER;
+ return WINBINDD_OK;
+ }
+
+ if (is_in_uid_range(state->request.data.uid)) {
+ /* This is winbind's, so we should better have succeeded
+ * above. */
return WINBINDD_ERROR;
}
-done:
- sid_to_string(state->response.data.sid.sid, &sid);
- state->response.data.sid.type = SID_NAME_USER;
+ /* The only chance that this is correct is that winbind trusted
+ * domains only = yes, and the user exists in nss and the domain. */
- return WINBINDD_OK;
+ if (!lp_winbind_trusted_domains_only()) {
+ return WINBINDD_ERROR;
+ }
+
+ /* The only chance that this is correct is that winbind trusted
+ * domains only = yes, and the user exists in nss and the domain. */
+
+ uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state);
+ if (uid2sid_state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ uid2sid_state->cli_state = state;
+ uid2sid_state->uid = state->request.data.uid;
+
+ winbindd_uid2name_async(state->mem_ctx, state->request.data.uid,
+ uid2sid_uid2name_recv, uid2sid_state);
+ return WINBINDD_PENDING;
+}
+
+static void uid2sid_uid2name_recv(void *private, BOOL success,
+ const char *username)
+{
+ struct uid2sid_state *state =
+ talloc_get_type_abort(private, struct uid2sid_state);
+
+ DEBUG(10, ("uid2sid: uid %lu has name %s\n",
+ (unsigned long)state->uid, username));
+
+ fstrcpy(state->name, username);
+
+ if (!success) {
+ state->cli_state->response.result = WINBINDD_ERROR;
+ request_finished(state->cli_state);
+ return;
+ }
+
+ winbindd_lookupname_async(state->cli_state->mem_ctx,
+ find_our_domain()->name, username,
+ uid2sid_lookupname_recv, state);
+}
+
+static void uid2sid_lookupname_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type)
+{
+ struct uid2sid_state *state =
+ talloc_get_type_abort(private, struct uid2sid_state);
+ unid_t id;
+
+ if ((!success) || (type != SID_NAME_USER)) {
+ state->cli_state->response.result = WINBINDD_ERROR;
+ request_finished(state->cli_state);
+ return;
+ }
+
+ state->sid = *sid;
+ state->type = type;
+
+ id.uid = state->uid;
+ idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_USERID,
+ uid2sid_idmap_set_mapping_recv, state );
+}
+
+static void uid2sid_idmap_set_mapping_recv(void *private, BOOL success)
+{
+ struct uid2sid_state *state =
+ talloc_get_type_abort(private, struct uid2sid_state);
+
+ /* don't fail if we can't store it */
+
+ sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
+ state->cli_state->response.data.sid.type = state->type;
+ state->cli_state->response.result = WINBINDD_OK;
+ request_finished(state->cli_state);
}
/* Convert a gid to a sid */
+struct gid2sid_state {
+ struct winbindd_cli_state *cli_state;
+ gid_t gid;
+ fstring name;
+ DOM_SID sid;
+ enum SID_NAME_USE type;
+};
+
+static void gid2sid_gid2name_recv(void *private, BOOL success,
+ const char *groupname);
+static void gid2sid_lookupname_recv(void *private, BOOL success,
+ const DOM_SID *sid,
+ enum SID_NAME_USE type);
+static void gid2sid_idmap_set_mapping_recv(void *private, BOOL success);
+
enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state)
{
DOM_SID sid;
+ NTSTATUS status;
+ struct gid2sid_state *gid2sid_state;
- DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
+ DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.gid));
-
- if ( (state->request.data.gid < server_state.gid_low)
- || (state->request.data.gid > server_state.gid_high) )
- {
- struct group *grp = NULL;
- enum SID_NAME_USE type;
- unid_t id;
- struct winbindd_domain *domain;
-
- /* SPECIAL CASE FOR MEMBERS OF SAMBA DOMAINS */
-
- /* if we don't trust /etc/group then when can't know
- anything about this gid */
-
- if ( !lp_winbind_trusted_domains_only() )
- return WINBINDD_ERROR;
-
- /* look for an idmap entry first */
-
- if ( NT_STATUS_IS_OK(idmap_gid_to_sid(&sid, state->request.data.gid)) )
- goto done;
-
- /* if users exist in /etc/group, we should try to
- use that gid. Get the username and the lookup the SID */
-
- if ( !(grp = getgrgid(state->request.data.gid)) )
- return WINBINDD_ERROR;
-
- if ( !(domain = find_our_domain()) ) {
- DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n"));
- return WINBINDD_ERROR;
- }
-
- if ( !winbindd_lookup_sid_by_name(domain, domain->name, grp->gr_name, &sid, &type) )
- return WINBINDD_ERROR;
-
- if ( type!=SID_NAME_DOM_GRP && type!=SID_NAME_ALIAS )
- return WINBINDD_ERROR;
-
- /* don't fail if we can't store it */
-
- id.gid = grp->gr_gid;
- idmap_set_mapping( &sid, id, ID_GROUPID );
-
- goto done;
+
+ if (idmap_proxyonly()) {
+ DEBUG(8, ("IDMAP proxy only\n"));
+ return WINBINDD_ERROR;
}
- /* Lookup sid for this uid */
-
- if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&sid, state->request.data.gid))) {
- DEBUG(1, ("Could not convert gid %lu to sid\n",
- (unsigned long)state->request.data.gid));
+ status = idmap_gid_to_sid(&sid, state->request.data.gid,
+ ID_QUERY_ONLY | ID_CACHE_ONLY);
+
+ if (NT_STATUS_IS_OK(status)) {
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_USER;
+ return WINBINDD_OK;
+ }
+
+ if (is_in_gid_range(state->request.data.gid)) {
+ /* This is winbind's, so we should better have succeeded
+ * above. */
return WINBINDD_ERROR;
}
-done:
- /* Construct sid and return it */
- sid_to_string(state->response.data.sid.sid, &sid);
- state->response.data.sid.type = SID_NAME_DOM_GRP;
+ /* The only chance that this is correct is that winbind trusted
+ * domains only = yes, and the user exists in nss and the domain. */
- return WINBINDD_OK;
+ if (!lp_winbind_trusted_domains_only()) {
+ return WINBINDD_ERROR;
+ }
+
+ /* The only chance that this is correct is that winbind trusted
+ * domains only = yes, and the user exists in nss and the domain. */
+
+ gid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct gid2sid_state);
+ if (gid2sid_state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ gid2sid_state->cli_state = state;
+ gid2sid_state->gid = state->request.data.gid;
+
+ winbindd_gid2name_async(state->mem_ctx, state->request.data.gid,
+ gid2sid_gid2name_recv, gid2sid_state);
+ return WINBINDD_PENDING;
+}
+
+static void gid2sid_gid2name_recv(void *private, BOOL success,
+ const char *username)
+{
+ struct gid2sid_state *state =
+ talloc_get_type_abort(private, struct gid2sid_state);
+
+ DEBUG(10, ("gid2sid: gid %lu has name %s\n",
+ (unsigned long)state->gid, username));
+
+ fstrcpy(state->name, username);
+
+ if (!success) {
+ state->cli_state->response.result = WINBINDD_ERROR;
+ request_finished(state->cli_state);
+ return;
+ }
+
+ winbindd_lookupname_async(state->cli_state->mem_ctx,
+ find_our_domain()->name, username,
+ gid2sid_lookupname_recv, state);
+}
+
+static void gid2sid_lookupname_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type)
+{
+ struct gid2sid_state *state =
+ talloc_get_type_abort(private, struct gid2sid_state);
+ unid_t id;
+
+ if ((!success) ||
+ ((type != SID_NAME_DOM_GRP) && (type!=SID_NAME_ALIAS))) {
+ state->cli_state->response.result = WINBINDD_ERROR;
+ request_finished(state->cli_state);
+ return;
+ }
+
+ state->sid = *sid;
+ state->type = type;
+
+ id.gid = state->gid;
+ idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_GROUPID,
+ gid2sid_idmap_set_mapping_recv, state );
+}
+
+static void gid2sid_idmap_set_mapping_recv(void *private, BOOL success)
+{
+ struct gid2sid_state *state = private;
+
+ /* don't fail if we can't store it */
+
+ sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
+ state->cli_state->response.data.sid.type = state->type;
+ state->cli_state->response.result = WINBINDD_OK;
+ request_finished(state->cli_state);
}
enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
@@ -491,6 +517,15 @@ enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
return WINBINDD_ERROR;
}
+ async_request(state->mem_ctx, idmap_child(),
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_allocate_rid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
/* We tell idmap to always allocate a user RID. There might be a good
* reason to keep RID allocation for users to even and groups to
* odd. This needs discussion I think. For now only allocate user
@@ -502,3 +537,45 @@ enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
+
+enum winbindd_result winbindd_allocate_rid_and_gid(struct winbindd_cli_state *state)
+{
+ if ( !state->privileged ) {
+ DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
+ "denied!\n"));
+ return WINBINDD_ERROR;
+ }
+
+ async_request(state->mem_ctx, idmap_child(),
+ &state->request, &state->response,
+ request_finished_cont, state);
+ return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_allocate_rid_and_gid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result;
+ DOM_SID sid;
+
+ /* We tell idmap to always allocate a user RID. This is really
+ * historic and needs to be fixed. I *think* this has to do with the
+ * way winbind determines its free RID space. */
+
+ result = idmap_allocate_rid(&state->response.data.rid_and_gid.rid,
+ USER_RID_TYPE);
+
+ if (!NT_STATUS_IS_OK(result))
+ return WINBINDD_ERROR;
+
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, state->response.data.rid_and_gid.rid);
+
+ result = idmap_sid_to_gid(&sid, &state->response.data.rid_and_gid.gid,
+ 0);
+
+ if (!NT_STATUS_IS_OK(result))
+ return WINBINDD_ERROR;
+
+ return WINBINDD_OK;
+}
diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c
index 7a9b5cf96a..d192793993 100644
--- a/source3/nsswitch/winbindd_user.c
+++ b/source3/nsswitch/winbindd_user.c
@@ -106,174 +106,295 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
return True;
}
-/* Return a password structure from a username. */
+/* Wrapper for domain->methods->query_user, only on the parent->child pipe */
-enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
+enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
{
+ DOM_SID sid;
WINBIND_USERINFO user_info;
- DOM_SID user_sid;
NTSTATUS status;
- fstring name_domain, name_user;
- enum SID_NAME_USE name_type;
- struct winbindd_domain *domain;
- TALLOC_CTX *mem_ctx;
-
+
/* Ensure null termination */
- state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
- DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
- state->request.data.username));
-
- /* Parse domain and username */
+ DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
- parse_domain_user(state->request.data.username,
- name_domain, name_user);
-
- /* should we deal with users for our domain? */
-
- if ((domain = find_domain_from_name(name_domain)) == NULL) {
- DEBUG(5, ("no such domain: %s\n", name_domain));
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(5, ("%s not a SID\n", state->request.data.sid));
return WINBINDD_ERROR;
}
-
- if ( domain->primary && lp_winbind_trusted_domains_only()) {
- DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n",
- name_domain, name_user));
- return WINBINDD_ERROR;
- }
-
- /* Get rid and name type from name */
- if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid, &name_type)) {
- DEBUG(1, ("user '%s' does not exist\n", name_user));
+ status = domain->methods->query_user(domain, state->mem_ctx,
+ &sid, &user_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("error getting user info for sid %s\n",
+ sid_string_static(&sid)));
return WINBINDD_ERROR;
}
- if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) {
- DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
- name_type));
- return WINBINDD_ERROR;
- }
-
- /* Get some user info. */
-
- if (!(mem_ctx = talloc_init("winbindd_getpwnam([%s]\\[%s])",
- name_domain, name_user))) {
- DEBUG(1, ("out of memory\n"));
+ fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
+ fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
+ if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
+ &state->response.data.user_info.group_rid)) {
+ DEBUG(1, ("Could not extract group rid out of %s\n",
+ sid_string_static(&sid)));
return WINBINDD_ERROR;
}
- status = domain->methods->query_user(domain, mem_ctx, &user_sid,
- &user_info);
+ return WINBINDD_OK;
+}
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("error getting user info for user '[%s]\\[%s]'\n",
- name_domain, name_user));
- talloc_destroy(mem_ctx);
- return WINBINDD_ERROR;
+struct getpwsid_state {
+ struct winbindd_cli_state *state;
+ struct winbindd_domain *domain;
+ char *username;
+ char *fullname;
+ DOM_SID user_sid;
+ uid_t uid;
+ DOM_SID group_sid;
+ gid_t gid;
+};
+
+static void getpwsid_queryuser_recv(void *private, BOOL success,
+ const char *acct_name,
+ const char *full_name, uint32 group_rid);
+static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid);
+static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid);
+
+static void winbindd_getpwsid(struct winbindd_cli_state *state,
+ const DOM_SID *sid)
+{
+ struct getpwsid_state *s;
+
+ s = TALLOC_P(state->mem_ctx, struct getpwsid_state);
+ if (s == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto error;
}
-
- /* Now take all this information and fill in a passwd structure */
- if (!winbindd_fill_pwent(name_domain, user_info.acct_name,
- user_info.user_sid, user_info.group_sid,
- user_info.full_name,
- &state->response.data.pw)) {
- talloc_destroy(mem_ctx);
- return WINBINDD_ERROR;
+
+ s->state = state;
+ s->domain = find_domain_from_sid_noinit(sid);
+ if (s->domain == NULL) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_static(sid)));
+ goto error;
}
- talloc_destroy(mem_ctx);
+ sid_copy(&s->user_sid, sid);
+
+ query_user_async(s->state->mem_ctx, s->domain, sid,
+ getpwsid_queryuser_recv, s);
+ return;
+
+ error:
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+}
- return WINBINDD_OK;
-}
+static void getpwsid_queryuser_recv(void *private, BOOL success,
+ const char *acct_name,
+ const char *full_name, uint32 group_rid)
+{
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private, struct getpwsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not query user %s\\%s\n", s->domain->name,
+ s->username));
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(s->state);
+ return;
+ }
-/* Return a password structure given a uid number */
+ s->username = talloc_strdup(s->state->mem_ctx, acct_name);
+ s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
+ sid_copy(&s->group_sid, &s->domain->sid);
+ sid_append_rid(&s->group_sid, group_rid);
-enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
+ winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
+ getpwsid_sid2uid_recv, s);
+}
+
+static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid)
{
- DOM_SID user_sid;
- struct winbindd_domain *domain;
- fstring dom_name;
- fstring user_name;
- enum SID_NAME_USE name_type;
- WINBIND_USERINFO user_info;
- TALLOC_CTX *mem_ctx;
- NTSTATUS status;
- gid_t gid;
-
- /* Bug out if the uid isn't in the winbind range */
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private, struct getpwsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not query user's %s\\%s uid\n",
+ s->domain->name, s->username));
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(s->state);
+ return;
+ }
- if ((state->request.data.uid < server_state.uid_low ) ||
- (state->request.data.uid > server_state.uid_high))
- return WINBINDD_ERROR;
+ s->uid = uid;
+ winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
+ getpwsid_sid2gid_recv, s);
+}
- DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
- (unsigned long)state->request.data.uid));
+static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid)
+{
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private, struct getpwsid_state);
+ struct winbindd_pw *pw;
+ fstring output_username;
+ char *homedir;
+ char *shell;
- /* Get rid from uid */
+ s->state->response.result = WINBINDD_ERROR;
- if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&user_sid, state->request.data.uid))) {
- DEBUG(1, ("could not convert uid %lu to SID\n",
- (unsigned long)state->request.data.uid));
- return WINBINDD_ERROR;
+ if (!success) {
+ DEBUG(5, ("Could not query user's %s\\%s\n gid",
+ s->domain->name, s->username));
+ goto done;
}
+
+ s->gid = gid;
+
+ pw = &s->state->response.data.pw;
+ pw->pw_uid = s->uid;
+ pw->pw_gid = s->gid;
+ fill_domain_username(output_username, s->domain->name, s->username);
+ safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
+ safe_strcpy(pw->pw_gecos, s->fullname, 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. */
- /* Get name and name type from rid */
+ /* The substitution of %U and %D in the 'template homedir' is done
+ by alloc_sub_specified() below. */
- if (!winbindd_lookup_name_by_sid(&user_sid, dom_name, user_name, &name_type)) {
- fstring temp;
-
- sid_to_string(temp, &user_sid);
- DEBUG(1, ("could not lookup sid %s\n", temp));
- return WINBINDD_ERROR;
+ fstrcpy(current_user_info.domain, s->domain->name);
+
+ homedir = alloc_sub_specified(lp_template_homedir(), s->username,
+ s->domain->name, pw->pw_uid, pw->pw_gid);
+ if (homedir == NULL) {
+ DEBUG(5, ("Could not compose homedir\n"));
+ goto done;
}
+ safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1);
+ SAFE_FREE(homedir);
- domain = find_domain_from_sid(&user_sid);
+ shell = alloc_sub_specified(lp_template_shell(), s->username,
+ s->domain->name, pw->pw_uid, pw->pw_gid);
+ if (shell == NULL) {
+ DEBUG(5, ("Could not compose shell\n"));
+ goto done;
+ }
+ safe_strcpy(pw->pw_shell, shell, sizeof(pw->pw_shell) - 1);
+ SAFE_FREE(shell);
+
+ /* Password - set to "x" as we can't generate anything useful here.
+ Authentication can be done using the pam_winbind module. */
+
+ safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+
+ s->state->response.result = WINBINDD_OK;
+
+ done:
+ request_finished(s->state);
+}
- if (!domain) {
- DEBUG(1,("Can't find domain from sid\n"));
+/* Return a password structure from a username. */
+
+static void getpwnam_name2sid_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type);
+
+enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring domname, username;
+
+ /* Ensure null termination */
+ state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
+ state->request.data.username));
+
+ if (!parse_domain_user(state->request.data.username, domname,
+ username)) {
+ DEBUG(0, ("Could not parse domain user: %s\n",
+ state->request.data.username));
return WINBINDD_ERROR;
}
-
- /* Get some user info */
- if (!(mem_ctx = talloc_init("winbind_getpwuid(%lu)",
- (unsigned long)state->request.data.uid))) {
+ /* Get info for the domain */
- DEBUG(1, ("out of memory\n"));
+ domain = find_lookup_domain_from_name(domname);
+
+ if (domain == NULL) {
+ DEBUG(7, ("could not find domain entry for domain %s\n",
+ domname));
return WINBINDD_ERROR;
}
- status = domain->methods->query_user(domain, mem_ctx, &user_sid,
- &user_info);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("error getting user info for user '%s'\n",
- user_name));
- talloc_destroy(mem_ctx);
+ if ( domain->primary && lp_winbind_trusted_domains_only()) {
+ DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
+ "getgroups() for %s\\%s.\n", domname, username));
return WINBINDD_ERROR;
+ }
+
+ /* Get rid and name type from name. The following costs 1 packet */
+
+ winbindd_lookupname_async(state->mem_ctx, domname, username,
+ getpwnam_name2sid_recv, state);
+ return WINBINDD_PENDING;
+}
+
+static void getpwnam_name2sid_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type)
+{
+ struct winbindd_cli_state *state = private;
+
+ if (!success) {
+ DEBUG(5, ("Could not lookup name for user %s\n",
+ state->request.data.username));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
+ }
+
+ if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
+ DEBUG(5, ("%s is not a user\n", state->request.data.username));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
}
+
+ winbindd_getpwsid(state, sid);
+}
+
+/* Return a password structure given a uid number */
+
+enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ NTSTATUS status;
- /* Check group has a gid number */
+ /* Bug out if the uid isn't in the winbind range */
- if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_info.group_sid, &gid, 0))) {
- DEBUG(1, ("error getting group id for user %s\n", user_name));
- talloc_destroy(mem_ctx);
+ if ((state->request.data.uid < server_state.uid_low ) ||
+ (state->request.data.uid > server_state.uid_high))
return WINBINDD_ERROR;
- }
- /* Fill in password structure */
+ DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.uid));
- if (!winbindd_fill_pwent(domain->name, user_info.acct_name, user_info.user_sid,
- user_info.group_sid,
- user_info.full_name, &state->response.data.pw)) {
- talloc_destroy(mem_ctx);
+ status = idmap_uid_to_sid(&user_sid, state->request.data.uid,
+ ID_QUERY_ONLY | ID_CACHE_ONLY);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Could not find SID for uid %lu\n",
+ (unsigned long)state->request.data.uid));
return WINBINDD_ERROR;
}
-
- talloc_destroy(mem_ctx);
- return WINBINDD_OK;
+ winbindd_getpwsid(state, &user_sid);
+ return WINBINDD_PENDING;
}
/*
@@ -365,14 +486,13 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
field is incremented to the index of the next user to fetch. Return True if
some users were returned, False otherwise. */
-static BOOL get_sam_user_entries(struct getent_state *ent)
+static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
uint32 num_entries;
WINBIND_USERINFO *info;
struct getpwent_user *name_list = NULL;
BOOL result = False;
- TALLOC_CTX *mem_ctx;
struct winbindd_domain *domain;
struct winbindd_methods *methods;
unsigned int i;
@@ -380,10 +500,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
if (ent->num_sam_entries)
return False;
- if (!(mem_ctx = talloc_init("get_sam_user_entries(%s)",
- ent->domain_name)))
- return False;
-
if (!(domain = find_domain_from_name(ent->domain_name))) {
DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
ent->domain_name));
@@ -433,8 +549,10 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
}
/* User and group ids */
- sid_copy(&name_list[ent->num_sam_entries+i].user_sid, info[i].user_sid);
- sid_copy(&name_list[ent->num_sam_entries+i].group_sid, info[i].group_sid);
+ sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
+ &info[i].user_sid);
+ sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
+ &info[i].group_sid);
}
ent->num_sam_entries += num_entries;
@@ -447,8 +565,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
done:
- talloc_destroy(mem_ctx);
-
return result;
}
@@ -497,7 +613,8 @@ enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
if (ent->num_sam_entries == ent->sam_entry_index) {
- while(ent && !get_sam_user_entries(ent)) {
+ while(ent &&
+ !get_sam_user_entries(ent, state->mem_ctx)) {
struct getent_state *next_ent;
/* Free state information for this domain */
@@ -560,14 +677,10 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
uint32 num_entries = 0, total_entries = 0;
char *ted, *extra_data = NULL;
int extra_data_len = 0;
- TALLOC_CTX *mem_ctx;
enum winbindd_result rv = WINBINDD_ERROR;
DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid));
- if (!(mem_ctx = talloc_init("winbindd_list_users")))
- return WINBINDD_ERROR;
-
/* Ensure null termination */
state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
which_domain = state->request.domain_name;
@@ -585,14 +698,11 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
if ( *which_domain && !strequal(which_domain, domain->name) )
continue;
-
- if ( !domain->initialized )
- set_dc_type_and_flags( domain );
methods = domain->methods;
/* Query display info */
- status = methods->query_user_list(domain, mem_ctx,
+ status = methods->query_user_list(domain, state->mem_ctx,
&num_entries, &info);
if (num_entries == 0)
@@ -646,7 +756,5 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
done:
- talloc_destroy(mem_ctx);
-
return rv;
}
diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c
index 739a7ed2a7..21ae4611c2 100644
--- a/source3/nsswitch/winbindd_util.c
+++ b/source3/nsswitch/winbindd_util.c
@@ -24,9 +24,6 @@
#include "includes.h"
#include "winbindd.h"
-extern struct winbindd_methods cache_methods;
-extern struct winbindd_methods passdb_methods;
-
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -65,8 +62,7 @@ struct winbindd_domain *domain_list(void)
/* Initialise list */
if (!_domain_list)
- if (!init_domain_list())
- return NULL;
+ init_domain_list();
return _domain_list;
}
@@ -91,12 +87,7 @@ static BOOL is_internal_domain(const DOM_SID *sid)
if (sid == NULL)
return False;
- if ( sid_compare_domain( sid, get_global_sam_sid() ) == 0 )
- return True;
- if ( sid_compare_domain( sid, &global_sid_Builtin ) == 0 )
- return True;
-
- return False;
+ return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
}
@@ -181,80 +172,115 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
rescan our domains looking for new trusted domains
********************************************************************/
+struct trustdom_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_response *response;
+};
+
+static void trustdom_recv(void *private, BOOL success);
+
static void add_trusted_domains( struct winbindd_domain *domain )
{
TALLOC_CTX *mem_ctx;
- NTSTATUS result;
- time_t t;
- char **names;
- char **alt_names;
- int num_domains = 0;
- DOM_SID *dom_sids, null_sid;
- int i;
- struct winbindd_domain *new_domain;
-
- /* trusted domains might be disabled */
- if (!lp_allow_trusted_domains()) {
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+
+ struct trustdom_state *state;
+
+ mem_ctx = talloc_init("add_trusted_domains");
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_init failed\n"));
return;
}
- DEBUG(5, ("scanning trusted domain list\n"));
+ request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
+ response = TALLOC_P(mem_ctx, struct winbindd_response);
+ state = TALLOC_P(mem_ctx, struct trustdom_state);
- if (!(mem_ctx = talloc_init("init_domain_list")))
+ if ((request == NULL) || (response == NULL) || (state == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ talloc_destroy(mem_ctx);
return;
-
- ZERO_STRUCTP(&null_sid);
+ }
- t = time(NULL);
-
- /* ask the DC what domains it trusts */
-
- result = domain->methods->trusted_domains(domain, mem_ctx, (unsigned int *)&num_domains,
- &names, &alt_names, &dom_sids);
-
- if ( NT_STATUS_IS_OK(result) ) {
+ state->mem_ctx = mem_ctx;
+ state->response = response;
- /* Add each domain to the trusted domain list */
-
- for(i = 0; i < num_domains; i++) {
- DEBUG(10,("Found domain %s\n", names[i]));
- add_trusted_domain(names[i], alt_names?alt_names[i]:NULL,
- &cache_methods, &dom_sids[i]);
-
- /* if the SID was empty, we better set it now */
-
- if ( sid_equal(&dom_sids[i], &null_sid) ) {
- enum SID_NAME_USE type;
- new_domain = find_domain_from_name(names[i]);
-
- /* this should never happen */
- if ( !new_domain ) {
- DEBUG(0,("rescan_trust_domains: can't find the domain I just added! [%s]\n",
- names[i]));
- break;
- }
-
- /* call the cache method; which will operate on the winbindd_domain \
- passed in and choose either rpc or ads as appropriate */
-
- result = domain->methods->name_to_sid( domain,
- mem_ctx,
- new_domain->name,
- NULL,
- &new_domain->sid,
- &type);
-
- if ( NT_STATUS_IS_OK(result) )
- sid_copy( &dom_sids[i], &new_domain->sid );
- }
+ request->length = sizeof(*request);
+ request->cmd = WINBINDD_LIST_TRUSTDOM;
+
+ async_domain_request(mem_ctx, domain, request, response,
+ trustdom_recv, state);
+}
+
+static void trustdom_recv(void *private, BOOL success)
+{
+ extern struct winbindd_methods cache_methods;
+ struct trustdom_state *state =
+ talloc_get_type_abort(private, struct trustdom_state);
+ struct winbindd_response *response = state->response;
+ char *p;
+
+ if ((!success) || (response->result != WINBINDD_OK)) {
+ DEBUG(1, ("Could not receive trustdoms\n"));
+ talloc_destroy(state->mem_ctx);
+ return;
+ }
+
+ p = response->extra_data;
+
+ while ((p != NULL) && (*p != '\0')) {
+ char *q, *sidstr, *alt_name;
+ DOM_SID sid;
+
+ alt_name = strchr(p, '\\');
+ if (alt_name == NULL) {
+ DEBUG(0, ("Got invalid trustdom response\n"));
+ break;
+ }
+
+ *alt_name = '\0';
+ alt_name += 1;
+
+ sidstr = strchr(alt_name, '\\');
+ if (sidstr == NULL) {
+ DEBUG(0, ("Got invalid trustdom response\n"));
+ break;
+ }
+
+ *sidstr = '\0';
+ sidstr += 1;
+
+ q = strchr(sidstr, '\n');
+ if (q != NULL)
+ *q = '\0';
+
+ if (!string_to_sid(&sid, sidstr)) {
+ DEBUG(0, ("Got invalid trustdom response\n"));
+ break;
+ }
+
+ if (find_domain_from_name_noinit(p) == NULL) {
+ struct winbindd_domain *domain;
+ char *alternate_name = NULL;
- /* store trusted domain in the cache */
- trustdom_cache_store(names[i], alt_names ? alt_names[i] : NULL,
- &dom_sids[i], t + WINBINDD_RESCAN_FREQ);
+ /* use the real alt_name if we have one, else pass in NULL */
+
+ if ( !strequal( alt_name, "(null)" ) )
+ alternate_name = alt_name;
+
+ domain = add_trusted_domain(p, alternate_name,
+ &cache_methods,
+ &sid);
+ setup_domain_child(domain, &domain->child, NULL);
}
+ p=q;
+ if (p != NULL)
+ p += 1;
}
- talloc_destroy(mem_ctx);
+ SAFE_FREE(response->extra_data);
+ talloc_destroy(state->mem_ctx);
}
/********************************************************************
@@ -264,30 +290,204 @@ static void add_trusted_domains( struct winbindd_domain *domain )
void rescan_trusted_domains( void )
{
time_t now = time(NULL);
- struct winbindd_domain *mydomain = NULL;
/* see if the time has come... */
- if ( (now > last_trustdom_scan) && ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
+ if ((now >= last_trustdom_scan) &&
+ ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
return;
- if ( (mydomain = find_our_domain()) == NULL ) {
- DEBUG(0,("rescan_trusted_domains: Can't find my own domain!\n"));
- return;
- }
-
/* this will only add new domains we didn't already know about */
- add_trusted_domains( mydomain );
+ add_trusted_domains( find_our_domain() );
last_trustdom_scan = now;
return;
}
+struct init_child_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_domain *domain;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ void (*continuation)(void *private, BOOL success);
+ void *private;
+};
+
+static void init_child_recv(void *private, BOOL success);
+static void init_child_getdc_recv(void *private, BOOL success);
+
+enum winbindd_result init_child_connection(struct winbindd_domain *domain,
+ void (*continuation)(void *private,
+ BOOL success),
+ void *private)
+{
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ struct init_child_state *state;
+
+ mem_ctx = talloc_init("init_child_connection");
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_init failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
+ response = TALLOC_P(mem_ctx, struct winbindd_response);
+ state = TALLOC_P(mem_ctx, struct init_child_state);
+
+ if ((request == NULL) || (response == NULL) || (state == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ continuation(private, False);
+ return WINBINDD_ERROR;
+ }
+
+ request->length = sizeof(*request);
+
+ state->mem_ctx = mem_ctx;
+ state->domain = domain;
+ state->request = request;
+ state->response = response;
+ state->continuation = continuation;
+ state->private = private;
+
+ if (domain->primary) {
+ /* The primary domain has to find the DC name itself */
+ request->cmd = WINBINDD_INIT_CONNECTION;
+ fstrcpy(request->domain_name, domain->name);
+ request->data.init_conn.is_primary = True;
+ fstrcpy(request->data.init_conn.dcname, "");
+
+ async_request(mem_ctx, &domain->child, request, response,
+ init_child_recv, state);
+ return WINBINDD_PENDING;
+ }
+
+ /* This is *not* the primary domain, let's ask our DC about a DC
+ * name */
+
+ request->cmd = WINBINDD_GETDCNAME;
+ fstrcpy(request->domain_name, domain->name);
+
+ async_domain_request(mem_ctx, find_our_domain(), request, response,
+ init_child_getdc_recv, state);
+ return WINBINDD_PENDING;
+}
+
+static void init_child_getdc_recv(void *private, BOOL success)
+{
+ struct init_child_state *state =
+ talloc_get_type_abort(private, struct init_child_state);
+ const char *dcname = "";
+
+ DEBUG(10, ("Received getdcname response\n"));
+
+ if (success && (state->response->result == WINBINDD_OK)) {
+ dcname = state->response->data.dc_name;
+ }
+
+ state->request->cmd = WINBINDD_INIT_CONNECTION;
+ fstrcpy(state->request->domain_name, state->domain->name);
+ state->request->data.init_conn.is_primary = False;
+ fstrcpy(state->request->data.init_conn.dcname, dcname);
+
+ async_request(state->mem_ctx, &state->domain->child,
+ state->request, state->response,
+ init_child_recv, state);
+}
+
+static void init_child_recv(void *private, BOOL success)
+{
+ struct init_child_state *state =
+ talloc_get_type_abort(private, struct init_child_state);
+
+ DEBUG(5, ("Received child initialization response for domain %s\n",
+ state->domain->name));
+
+ if ((!success) || (state->response->result != WINBINDD_OK)) {
+ DEBUG(3, ("Could not init child\n"));
+ state->continuation(state->private, False);
+ talloc_destroy(state->mem_ctx);
+ return;
+ }
+
+ fstrcpy(state->domain->name,
+ state->response->data.domain_info.name);
+ fstrcpy(state->domain->alt_name,
+ state->response->data.domain_info.alt_name);
+ string_to_sid(&state->domain->sid,
+ state->response->data.domain_info.sid);
+ state->domain->native_mode =
+ state->response->data.domain_info.native_mode;
+ state->domain->active_directory =
+ state->response->data.domain_info.active_directory;
+ state->domain->sequence_number =
+ state->response->data.domain_info.sequence_number;
+
+ state->domain->initialized = 1;
+
+ if (state->continuation != NULL)
+ state->continuation(state->private, True);
+ talloc_destroy(state->mem_ctx);
+}
+
+enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct in_addr ipaddr;
+
+ /* Ensure null termination */
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1]='\0';
+ state->request.data.init_conn.dcname
+ [sizeof(state->request.data.init_conn.dcname)-1]='\0';
+
+ fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
+
+ if (strlen(domain->dcname) > 0) {
+ if (!resolve_name(domain->dcname, &ipaddr, 0x20)) {
+ DEBUG(2, ("Could not resolve DC name %s for domain %s\n",
+ domain->dcname, domain->name));
+ return WINBINDD_ERROR;
+ }
+
+ domain->dcaddr.sin_family = PF_INET;
+ putip((char *)&(domain->dcaddr.sin_addr), (char *)&ipaddr);
+ domain->dcaddr.sin_port = 0;
+ }
+
+ set_dc_type_and_flags(domain);
+
+ if (!domain->initialized) {
+ DEBUG(1, ("Could not initialize domain %s\n",
+ state->request.domain_name));
+ return WINBINDD_ERROR;
+ }
+
+ fstrcpy(state->response.data.domain_info.name, domain->name);
+ fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
+ fstrcpy(state->response.data.domain_info.sid,
+ sid_string_static(&domain->sid));
+
+ state->response.data.domain_info.native_mode
+ = domain->native_mode;
+ state->response.data.domain_info.active_directory
+ = domain->active_directory;
+ state->response.data.domain_info.primary
+ = domain->primary;
+ state->response.data.domain_info.sequence_number =
+ domain->sequence_number;
+
+ return WINBINDD_OK;
+}
+
/* Look up global info for the winbind daemon */
-BOOL init_domain_list(void)
+void init_domain_list(void)
{
+ extern struct winbindd_methods cache_methods;
+ extern struct winbindd_methods passdb_methods;
struct winbindd_domain *domain;
/* Free existing list */
@@ -297,50 +497,35 @@ BOOL init_domain_list(void)
if (IS_DC) {
domain = add_trusted_domain(get_global_sam_name(), NULL,
- &passdb_methods, get_global_sam_sid());
+ &passdb_methods,
+ get_global_sam_sid());
} else {
-
- domain = add_trusted_domain( lp_workgroup(), lp_realm(),
- &cache_methods, NULL);
-
- /* set flags about native_mode, active_directory */
- set_dc_type_and_flags(domain);
- }
- domain->primary = True;
+ DOM_SID our_sid;
- /* get any alternate name for the primary domain */
-
- cache_methods.alternate_name(domain);
-
- /* now we have the correct netbios (short) domain name */
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
+ DEBUG(0, ("Could not fetch our SID - did we join?\n"));
+ }
- if ( *domain->name )
- set_global_myworkgroup( domain->name );
-
- if (!secrets_fetch_domain_sid(domain->name, &domain->sid)) {
- DEBUG(1, ("Could not fetch sid for our domain %s\n",
- domain->name));
- return False;
+ domain = add_trusted_domain( lp_workgroup(), lp_realm(),
+ &cache_methods, &our_sid);
}
- /* do an initial scan for trusted domains */
- add_trusted_domains(domain);
-
+ domain->primary = True;
+ setup_domain_child(domain, &domain->child, NULL);
/* Add our local SAM domains */
- add_trusted_domain("BUILTIN", NULL, &passdb_methods,
- &global_sid_Builtin);
+ domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
+ &global_sid_Builtin);
+ setup_domain_child(domain, &domain->child, NULL);
if (!IS_DC) {
- add_trusted_domain(get_global_sam_name(), NULL,
- &passdb_methods, get_global_sam_sid());
+ domain = add_trusted_domain(get_global_sam_name(), NULL,
+ &passdb_methods,
+ get_global_sam_sid());
+ setup_domain_child(domain, &domain->child, NULL);
}
-
- /* avoid rescanning this right away */
- last_trustdom_scan = time(NULL);
- return True;
}
/**
@@ -355,7 +540,7 @@ BOOL init_domain_list(void)
* @return The domain structure for the named domain, if it is working.
*/
-struct winbindd_domain *find_domain_from_name(const char *domain_name)
+struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
{
struct winbindd_domain *domain;
@@ -363,10 +548,8 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
for (domain = domain_list(); domain != NULL; domain = domain->next) {
if (strequal(domain_name, domain->name) ||
- (domain->alt_name[0] && strequal(domain_name, domain->alt_name))) {
- if (!domain->initialized)
- set_dc_type_and_flags(domain);
-
+ (domain->alt_name[0] &&
+ strequal(domain_name, domain->alt_name))) {
return domain;
}
}
@@ -376,20 +559,32 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
return NULL;
}
+struct winbindd_domain *find_domain_from_name(const char *domain_name)
+{
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_name_noinit(domain_name);
+
+ if (domain == NULL)
+ return NULL;
+
+ if (!domain->initialized)
+ set_dc_type_and_flags(domain);
+
+ return domain;
+}
+
/* Given a domain sid, return the struct winbindd domain info for it */
-struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
+struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
{
struct winbindd_domain *domain;
/* Search through list */
for (domain = domain_list(); domain != NULL; domain = domain->next) {
- if (sid_compare_domain(sid, &domain->sid) == 0) {
- if (!domain->initialized)
- set_dc_type_and_flags(domain);
+ if (sid_compare_domain(sid, &domain->sid) == 0)
return domain;
- }
}
/* Not found */
@@ -399,6 +594,21 @@ struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
/* Given a domain sid, return the struct winbindd domain info for it */
+struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
+{
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_sid_noinit(sid);
+
+ if (domain == NULL)
+ return NULL;
+
+ if (!domain->initialized)
+ set_dc_type_and_flags(domain);
+
+ return domain;
+}
+
struct winbindd_domain *find_our_domain(void)
{
struct winbindd_domain *domain;
@@ -410,11 +620,24 @@ struct winbindd_domain *find_our_domain(void)
return domain;
}
- /* Not found */
-
+ smb_panic("Could not find our domain\n");
return NULL;
}
+struct winbindd_domain *find_builtin_domain(void)
+{
+ DOM_SID sid;
+ struct winbindd_domain *domain;
+
+ string_to_sid(&sid, "S-1-5-32");
+ domain = find_domain_from_sid(&sid);
+
+ if (domain == NULL)
+ smb_panic("Could not find BUILTIN domain\n");
+
+ return domain;
+}
+
/* Find the appropriate domain to lookup a name or SID */
struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
@@ -436,31 +659,24 @@ struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
{
if (IS_DC || strequal(domain_name, "BUILTIN") ||
strequal(domain_name, get_global_sam_name()))
- return find_domain_from_name(domain_name);
+ return find_domain_from_name_noinit(domain_name);
return find_our_domain();
}
/* Lookup a sid in a domain from a name */
-BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
+BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
const char *domain_name,
const char *name, DOM_SID *sid,
enum SID_NAME_USE *type)
{
NTSTATUS result;
- TALLOC_CTX *mem_ctx;
- mem_ctx = talloc_init("lookup_sid_by_name for %s\\%s\n",
- domain_name, name);
- if (!mem_ctx)
- return False;
-
/* Lookup name */
result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
- talloc_destroy(mem_ctx);
-
/* Return rid and type if lookup successful */
if (!NT_STATUS_IS_OK(result)) {
*type = SID_NAME_UNKNOWN;
@@ -480,7 +696,8 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
* @retval True if the name exists, in which case @p name and @p type
* are set, otherwise False.
**/
-BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
+BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
+ DOM_SID *sid,
fstring dom_name,
fstring name,
enum SID_NAME_USE *type)
@@ -488,7 +705,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
char *names;
char *dom_names;
NTSTATUS result;
- TALLOC_CTX *mem_ctx;
BOOL rv = False;
struct winbindd_domain *domain;
@@ -501,9 +717,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
/* Lookup name */
- if (!(mem_ctx = talloc_init("winbindd_lookup_name_by_sid")))
- return False;
-
result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
/* Return name and type if successful */
@@ -516,12 +729,9 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
fstrcpy(name, name_deadbeef);
}
- talloc_destroy(mem_ctx);
-
return rv;
}
-
/* Free state information held for {set,get,end}{pw,gr}ent() functions */
void free_getent_state(struct getent_state *state)
@@ -553,31 +763,30 @@ BOOL winbindd_param_init(void)
/* Parse winbind uid and winbind_gid parameters */
if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
- DEBUG(2, ("winbindd: idmap uid range missing or invalid\n"));
+ DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
+ DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
return False;
}
if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
- DEBUG(2, ("winbindd: idmap gid range missing or invalid\n"));
+ DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
+ DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
return False;
}
return True;
}
-/* Check if a domain is present in a comma-separated list of domains */
-
-BOOL check_domain_env(char *domain_env, char *domain)
+BOOL is_in_uid_range(uid_t uid)
{
- fstring name;
- const char *tmp = domain_env;
-
- while(next_token(&tmp, name, ",", sizeof(fstring))) {
- if (strequal(name, domain))
- return True;
- }
+ return ((uid >= server_state.uid_low) &&
+ (uid <= server_state.uid_high));
+}
- return False;
+BOOL is_in_gid_range(gid_t gid)
+{
+ return ((gid >= server_state.gid_low) &&
+ (gid <= server_state.gid_high));
}
/* Is this a domain which we may assume no DOMAIN\ prefix? */
@@ -620,6 +829,16 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
return True;
}
+BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
+ char **domain, char **user)
+{
+ fstring fstr_domain, fstr_user;
+ parse_domain_user(domuser, fstr_domain, fstr_user);
+ *domain = talloc_strdup(mem_ctx, fstr_domain);
+ *user = talloc_strdup(mem_ctx, fstr_user);
+ return ((*domain != NULL) && (*user != NULL));
+}
+
/*
Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
'winbind separator' options.
@@ -635,14 +854,16 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
*/
void fill_domain_username(fstring name, const char *domain, const char *user)
{
- strlower_m(CONST_DISCARD(char *, user));
+ fstring tmp_user;
+
+ fstrcpy(tmp_user, user);
if (assume_domain(domain)) {
strlcpy(name, user, sizeof(fstring));
} else {
slprintf(name, sizeof(fstring) - 1, "%s%c%s",
domain, *lp_winbind_separator(),
- user);
+ tmp_user);
}
}
@@ -764,22 +985,6 @@ int winbindd_num_clients(void)
return _num_clients;
}
-/* Help with RID -> SID conversion */
-
-DOM_SID *rid_to_talloced_sid(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- uint32 rid)
-{
- DOM_SID *sid;
- sid = TALLOC_P(mem_ctx, DOM_SID);
- if (!sid) {
- smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n");
- }
- sid_copy(sid, &domain->sid);
- sid_append_rid(sid, rid);
- return sid;
-}
-
/*****************************************************************************
For idmap conversion: convert one record to new format
Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
@@ -986,52 +1191,3 @@ BOOL winbindd_upgrade_idmap(void)
return idmap_convert(idmap_name);
}
-
-/*******************************************************************
- wrapper around retrieving the trust account password
-*******************************************************************/
-
-BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
- time_t *pass_last_set_time, uint32 *channel)
-{
- DOM_SID sid;
- char *pwd;
-
- /* if we are a DC and this is not our domain, then lookup an account
- for the domain trust */
-
- if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains() )
- {
- if ( !secrets_fetch_trusted_domain_password(domain, &pwd, &sid,
- pass_last_set_time) )
- {
- DEBUG(0, ("get_trust_pw: could not fetch trust account "
- "password for trusted domain %s\n", domain));
- return False;
- }
-
- *channel = SEC_CHAN_DOMAIN;
- E_md4hash(pwd, ret_pwd);
- SAFE_FREE(pwd);
-
- return True;
- }
- else /* just get the account for our domain (covers
- ROLE_DOMAIN_MEMBER as well */
- {
- /* get the machine trust account for our domain */
-
- if ( !secrets_fetch_trust_account_password (lp_workgroup(), ret_pwd,
- pass_last_set_time, channel) )
- {
- DEBUG(0, ("get_trust_pw: could not fetch trust account "
- "password for my domain %s\n", domain));
- return False;
- }
-
- return True;
- }
-
- /* Failure */
-}
-