--neYutvxvOLaeuPCA
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Thu, Sep 16, 2004 at 03:40:09PM +0200, Henrik Nordstrom wrote:
> Is there any thoughts about addressing this "minor" detail in the winbindd
> architecture? Having an central authentication service single-threaded
> blocking on external resources does not scale too well..


Look at trunk winbind. This has the architecture to have a configurable number
of worker-processes. It's not finished, but looks very promising. The only
problem is: I need a bit help to convert and test the rest of the requests.

Attached find the essence of that patch in its current form, with some torture
code in.

Volker

--neYutvxvOLaeuPCA
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="samba3-wbmultdual-3.0.7.diff"

diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/include/idmap.h ./include/idmap.h
--- ../../samba-3.0.7/source/include/idmap.h 2004-04-04 09:37:23.000000000 +0200
+++ ./source/include/idmap.h 2004-09-15 18:15:38.000000000 +0200
@@ -35,6 +35,7 @@
#define ID_TYPEMASK 0x0f

#define ID_QUERY_ONLY 0x10
+#define ID_CACHE_ONLY 0x20

/* Filled out by IDMAP backends */
struct idmap_methods {
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/include/messages.h ./include/messages.h
--- ../../samba-3.0.7/source/include/messages.h 2004-08-19 15:39:13.000000000 +0200
+++ ./source/include/messages.h 2004-09-15 18:15:38.000000000 +0200
@@ -63,6 +63,9 @@
#define MSG_SMB_SAM_REPL 3004
#define MSG_SMB_UNLOCK 3005

+/* winbind messages */
+#define MSG_WINBIND_FINISHED 4001
+
/* Flags to classify messages - used in message_send_all() */
/* Sender will filter by flag. */

diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/wbinfo.c ./nsswitch/wbinfo.c
--- ../../samba-3.0.7/source/nsswitch/wbinfo.c 2004-09-16 14:30:16.000000000 +0200
+++ ./source/nsswitch/wbinfo.c 2004-09-15 18:15:38.000000000 +0200
@@ -85,6 +85,26 @@ static const char *get_winbind_domain(vo

}

+static BOOL wbinfo_info(void)
+{
+ struct winbindd_response response;
+
+ ZERO_STRUCT(response);
+
+ /* Send off request */
+
+ if (winbindd_request(WINBINDD_INFO, NULL, &response)
+ != NSS_STATUS_SUCCESS)
+ return False;
+
+ d_printf("Separator: [%c]\nVersion: %s\nmax_busy: %d\n",
+ response.data.info.winbind_separator,
+ response.data.info.samba_version,
+ response.data.info.max_busy_children);
+
+ return True;
+}
+
/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
form DOMAIN/user into a domain and a user */

@@ -1072,6 +1092,7 @@ int main(int argc, char **argv)
{ "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" },
+ { "get-info", 'i', POPT_ARG_NONE, 0, 'i', "Get misc info" },
#ifdef WITH_FAKE_KASERVER
{ "klog", 'k', POPT_ARG_STRING, &string_arg, 'k', "set an AFS token from winbind", "user%password" },
#endif
@@ -1288,6 +1309,12 @@ int main(int argc, char **argv)
goto done;
}
break;
+ case 'i':
+ if (!wbinfo_info()) {
+ d_printf("could not get winbind info!\n");
+ goto done;
+ }
+ break;
case OPT_SET_AUTH_USER:
wbinfo_set_auth_user(string_arg);
break;
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd.c ./nsswitch/winbindd.c
--- ../../samba-3.0.7/source/nsswitch/winbindd.c 2004-08-06 23:38:19.000000000 +0200
+++ ./source/nsswitch/winbindd.c 2004-09-15 18:15:38.000000000 +0200
@@ -27,6 +27,7 @@

BOOL opt_nocache = False;
BOOL opt_dual_daemon = True;
+int max_busy_children = 0;

/* Reload configuration */

@@ -213,12 +214,133 @@ static void msg_shutdown(int msg_type, p
terminate();
}

+/* Dual daemon finished a request */
+static void msg_finished(int msg_type, pid_t src, void *buf, size_t len)
+{
+ struct winbindd_cli_state *state;
+ int *msgid;
+
+ DEBUG(5, ("Got finished message\n"));
+
+ if (len != sizeof(*msgid)) {
+ DEBUG(0, ("Wrong buffer size in message: %d\n", len));
+ return;
+ }
+
+ dual_finished(src);
+
+ msgid = (int *)buf;
+
+ DEBUGADD(10, ("got msgid %d\n", *msgid));
+
+ for (state = winbindd_client_list(); state; state = state->next) {
+ if (state->response.result != WINBINDD_PENDING)
+ continue;
+
+ if (state->msgid != *msgid)
+ continue;
+
+ state->response.result = state->continuation(state, src);
+
+ if (state->response.result == WINBINDD_PENDING) {
+ if (state->send_to_background) {
+ extern BOOL background_process;
+ background_process = True;
+ dual_send_request(state);
+ }
+ return;
+ }
+
+ state->read_buf_len = 0;
+ state->write_buf_len = sizeof(struct winbindd_response);
+ }
+}
+
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 cache_table[] = {
+
+ /* User functions */
+
+ { WINBINDD_GETPWNAM, dual_request, "GETPWNAM" },
+ { WINBINDD_GETPWUID, dual_request, "GETPWUID" },
+
+ { WINBINDD_SETPWENT, winbindd_setpwent, "SETPWENT" },
+ { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" },
+ { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" },
+
+ { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
+ { WINBINDD_GETUSERSIDS, cache_getusersids, "GETUSERSIDS" },
+
+ /* Group functions */
+
+ { WINBINDD_GETGRNAM, dual_request, "GETGRNAM" },
+ { WINBINDD_GETGRGID, dual_request, "GETGRGID" },
+ { WINBINDD_SETGRENT, winbindd_setgrent, "SETGRENT" },
+ { WINBINDD_ENDGRENT, winbindd_endgrent, "ENDGRENT" },
+ { WINBINDD_GETGRENT, winbindd_getgrent, "GETGRENT" },
+ { WINBINDD_GETGRLST, winbindd_getgrent, "GETGRLST" },
+
+ /* PAM auth functions */
+
+ { WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
+ { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
+ { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
+
+ /* Enumeration functions */
+
+ { WINBINDD_LIST_USERS, cache_list_users, "LIST_USERS" },
+ { WINBINDD_LIST_GROUPS, cache_list_groups, "LIST_GROUPS" },
+ { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains, "LIST_TRUSTDOM" },
+ { WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
+
+ /* SID related functions */
+
+ { WINBINDD_LOOKUPSID, cache_lookupsid, "LOOKUPSID" },
+ { WINBINDD_LOOKUPNAME, cache_lookupname, "LOOKUPNAME" },
+
+ /* Lookup related functions */
+
+ { WINBINDD_SID_TO_UID, cache_sid_to_uid, "SID_TO_UID" },
+ { WINBINDD_SID_TO_GID, cache_sid_to_gid, "SID_TO_GID" },
+ { WINBINDD_GID_TO_SID, cache_gid_to_sid, "GID_TO_SID" },
+ { WINBINDD_UID_TO_SID, cache_uid_to_sid, "UID_TO_SID" },
+ { WINBINDD_ALLOCATE_RID, winbindd_allocate_rid, "ALLOCATE_RID" },
+
+ /* 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_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" },
+
+ /* WINS functions */
+
+ { WINBINDD_WINS_BYNAME, winbindd_wins_byname, "WINS_BYNAME" },
+ { WINBINDD_WINS_BYIP, winbindd_wins_byip, "WINS_BYIP" },
+
+ /* UNIX account management functions */
+ { WINBINDD_CREATE_USER, winbindd_create_user, "CREATE_USER" },
+ { WINBINDD_CREATE_GROUP, winbindd_create_group, "CREATE_GROUP" },
+ { WINBINDD_ADD_USER_TO_GROUP, winbindd_add_user_to_group, "ADD_USER_TO_GROUP" },
+ { WINBINDD_REMOVE_USER_FROM_GROUP, winbindd_remove_user_from_group,"REMOVE_USER_FROM_GROUP"},
+ { WINBINDD_SET_USER_PRIMARY_GROUP, winbindd_set_user_primary_group,"SET_USER_PRIMARY_GROUP"},
+ { WINBINDD_DELETE_USER, winbindd_delete_user, "DELETE_USER" },
+ { WINBINDD_DELETE_GROUP, winbindd_delete_group, "DELETE_GROUP" },
+
+ /* End of list */
+
+ { WINBINDD_NUM_CMDS, NULL, "NONE" }
+};
+
static struct dispatch_table dispatch_table[] = {

/* User functions */
@@ -300,7 +422,7 @@ static struct dispatch_table dispatch_ta

static void process_request(struct winbindd_cli_state *state)
{
- struct dispatch_table *table = dispatch_table;
+ struct dispatch_table *table;

/* Free response data - we may be interrupted and receive another
command before being able to send this data off. */
@@ -314,7 +436,8 @@ static void process_request(struct winbi

/* Process command */

- for (table = dispatch_table; table->fn; table++) {
+ for (table = opt_dual_daemon ? cache_table : 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(state);
@@ -440,16 +563,22 @@ void winbind_process_packet(struct winbi
state->request.null_term = '\0';

state->pid = state->request.pid;
+
+ state->continuation = NULL;

process_request(state);

/* Update client state */
-
- state->read_buf_len = 0;
- state->write_buf_len = sizeof(struct winbindd_response);
+
+ if (state->response.result != WINBINDD_PENDING) {
+ state->read_buf_len = 0;
+ state->write_buf_len = sizeof(struct winbindd_response);
+ }

/* we might need to send it to the dual daemon */
- if (opt_dual_daemon) {
+ if (opt_dual_daemon && state->send_to_background) {
+ extern BOOL background_process;
+ background_process = True;
dual_send_request(state);
}
}
@@ -587,6 +716,7 @@ static void process_loop(void)
int maxfd, listen_sock, listen_priv_sock, selret;
struct timeval timeout;

+ again:
/* Handle messages */

message_dispatch();
@@ -680,6 +810,28 @@ static void process_loop(void)

if (opt_dual_daemon) {
dual_select(&w_fds);
+
+ if (!opt_dual_daemon) {
+ /* All children died */
+
+ state = winbindd_client_list();
+
+ while (state != NULL) {
+ struct winbindd_cli_state *next;
+ next = state->next;
+
+ /* In theory we should re-do
+ * the whole request, but this
+ * looks rather complicated as
+ * the client's state machines
+ * might have changed
+ * state->request. Is it worth
+ * the effort? */
+ remove_client(state);
+
+ state = next;
+ }
+ }
}

if (FD_ISSET(listen_sock, &r_fds)) {
@@ -715,6 +867,15 @@ static void process_loop(void)
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)) {
@@ -746,14 +907,15 @@ static void process_loop(void)

if (state->read_buf_len ==
sizeof(state->request)) {
+ static int msgid;
+ msgid += 1;
+ state->msgid = msgid;
+ state->request.msgid = msgid;
winbind_process_packet(state);
+ winbindd_demote_client(state);
+ goto again;
}
}
-
- /* Data available for writing */
-
- if (FD_ISSET(state->sock, &w_fds))
- client_write(state);
}
}

@@ -788,6 +950,7 @@ struct winbindd_state server_state; /*
int main(int argc, char **argv)
{
pstring logfile;
+ int num_children = 1;
static BOOL interactive = False;
static BOOL Fork = True;
static BOOL log_stdout = False;
@@ -798,6 +961,7 @@ int main(int argc, char **argv)
{ "interactive", 'i', POPT_ARG_NONE, NULL, 'i', "Interactive mode" },
{ "single-daemon", 'Y', POPT_ARG_VAL, &opt_dual_daemon, False, "Single daemon mode" },
{ "no-caching", 'n', POPT_ARG_VAL, &opt_nocache, True, "Disable caching" },
+ { "num-clients", 'c', POPT_ARG_INT, &num_children, True, "Number of winbind children" },
POPT_COMMON_SAMBA
POPT_TABLEEND
};
@@ -928,7 +1092,10 @@ int main(int argc, char **argv)
#endif

if (opt_dual_daemon) {
- do_dual_daemon();
+ int i;
+
+ for (i=0; i + do_dual_daemon();
}

/* Initialise messaging system */
@@ -942,6 +1109,7 @@ int main(int argc, char **argv)
as to SIGHUP signal */
message_register(MSG_SMB_CONF_UPDATED, msg_reload_services);
message_register(MSG_SHUTDOWN, msg_shutdown);
+ message_register(MSG_WINBIND_FINISHED, msg_finished);

poptFreeContext(pc);

diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd.h ./nsswitch/winbindd.h
--- ../../samba-3.0.7/source/nsswitch/winbindd.h 2004-09-16 14:30:16.000000000 +0200
+++ ./source/nsswitch/winbindd.h 2004-09-15 18:15:38.000000000 +0200
@@ -44,6 +44,12 @@ struct winbindd_cli_state {
time_t last_access; /* Time of last access (read or write) */
BOOL privileged; /* Is the client 'privileged' */

+ int msgid; /* message id to expect */
+ BOOL send_to_background;
+ enum winbindd_result (*continuation)(struct winbindd_cli_state *cli,
+ pid_t dual_daemon);
+ void *continuation_private;
+
struct winbindd_request request; /* Request from client */
struct winbindd_response response; /* Respose to client */
BOOL getpwent_initialized; /* Has getpwent_state been initialized? */
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd_cache.c ./nsswitch/winbindd_cache.c
--- ../../samba-3.0.7/source/nsswitch/winbindd_cache.c 2004-09-12 05:47:17.000000000 +0200
+++ ./source/nsswitch/winbindd_cache.c 2004-09-16 14:04:32.000000000 +0200
@@ -66,6 +66,27 @@ void wcache_flush_cache(void)
DEBUG(10,("wcache_flush_cache success\n"));
}

+static BOOL init_wcache(void)
+{
+ if (wcache == NULL) {
+ wcache = smb_xmalloc(sizeof(*wcache));
+ 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 winbindd_check_cache_size(time_t t)
{
static time_t last_check_time;
@@ -391,14 +412,15 @@ done:
/*
decide if a cache entry has expired
*/
-static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
+static BOOL centry_expired(struct winbindd_domain *domain,
+ struct cache_entry *centry)
{
- /* if the server is OK and our cache entry came from when it was down then
- the entry is invalid */
+ /* if the server is OK and our cache entry came from when it was down
+ then the entry is invalid */
if (domain->sequence_number != DOM_SEQUENCE_NONE &&
centry->sequence_number == DOM_SEQUENCE_NONE) {
- DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
- keystr, domain->name ));
+ DEBUG(10,("centry_expired: Key for domain %s invalid "
+ "sequence.\n", domain->name ));
return True;
}

@@ -406,13 +428,13 @@ static BOOL centry_expired(struct winbin
current sequence number then it is OK */
if (wcache_server_down(domain) ||
centry->sequence_number == domain->sequence_number) {
- DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
- keystr, domain->name ));
+ DEBUG(10,("centry_expired: Key for domain %s is good.\n",
+ domain->name ));
return False;
}

- DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
- keystr, domain->name ));
+ DEBUG(10,("centry_expired: Key for domain %s expired\n",
+ domain->name ));

/* it's expired */
return True;
@@ -467,7 +489,7 @@ static struct cache_entry *wcache_fetch(
centry->status = NT_STATUS(centry_uint32(centry));
centry->sequence_number = centry_uint32(centry);

- if (centry_expired(domain, kstr, centry)) {
+ if (centry_expired(domain, centry)) {
extern BOOL opt_dual_daemon;

DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
@@ -609,7 +631,6 @@ static void wcache_save_name_to_sid(stru
{
struct cache_entry *centry;
fstring uname;
- fstring sid_string;

centry = centry_start(domain, status);
if (!centry)
@@ -619,7 +640,8 @@ static void wcache_save_name_to_sid(stru
fstrcpy(uname, name);
strupper_m(uname);
centry_end(centry, "NS/%s/%s", domain_name, uname);
- DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname, sid_string));
+ DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname,
+ sid_string_static(sid)));
centry_free(centry);
}

@@ -1134,6 +1156,10 @@ static NTSTATUS lookup_usergroups(struct
if (!cache->tdb)
goto do_query;

+#if 1
+ goto do_query;
+#endif
+
centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));

/* If we have an access denied cache entry and a cached info3 in the
@@ -1393,3 +1419,678 @@ struct winbindd_methods cache_methods =
domain_sid,
alternate_name
};
+
+static struct cache_entry *
+wcache_fetch_only(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
+
+static struct cache_entry *wcache_fetch_only(const char *format, ...)
+{
+ va_list ap;
+ char *kstr;
+ TDB_DATA data;
+ struct cache_entry *centry;
+ TDB_DATA key;
+
+ if (!init_wcache())
+ return NULL;
+
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
+
+ key.dptr = kstr;
+ key.dsize = strlen(kstr);
+ data = tdb_fetch(wcache->tdb, key);
+ if (!data.dptr) {
+ /* a cache miss */
+ free(kstr);
+ return NULL;
+ }
+
+ centry = smb_xmalloc(sizeof(*centry));
+ centry->data = (unsigned char *)data.dptr;
+ centry->len = data.dsize;
+ centry->ofs = 0;
+
+ if (centry->len < 8) {
+ /* huh? corrupt cache? */
+ DEBUG(10,("wcache_fetch: Corrupt cache for key %s "
+ "(len < 8) ?\n", kstr));
+ centry_free(centry);
+ free(kstr);
+ return NULL;
+ }
+
+ centry->status = NT_STATUS(centry_uint32(centry));
+ centry->sequence_number = centry_uint32(centry);
+
+ DEBUG(10,("wcache_fetch: returning entry %s\n", kstr));
+
+ free(kstr);
+ return centry;
+}
+
+static enum winbindd_result
+cache_lookupsid_cont(struct winbindd_cli_state *state, pid_t dual)
+{
+ return cache_lookupsid(state);
+}
+
+enum winbindd_result cache_lookupsid(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ DOM_SID sid;
+ struct cache_entry *centry = NULL;
+ char *dom_name, *name;
+ TALLOC_CTX *mem_ctx;
+
+ /* 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;
+ }
+
+ domain = find_lookup_domain_from_sid(&sid);
+
+ if (!domain) {
+ DEBUG(1,("Can't find domain from sid\n"));
+ return WINBINDD_ERROR;
+ }
+
+ /* Lookup the sid */
+
+ centry = wcache_fetch_only("SN/%s", sid_string_static(&sid));
+
+ if ((state->continuation != NULL) && /* Here the second time */
+ (centry == NULL)) {
+ DEBUG(1, ("Internal error, no centry second time\n"));
+ return WINBINDD_ERROR;
+ }
+
+ if ((centry == NULL) || centry_expired(domain, centry))
+ state->send_to_background = True;
+
+ if (centry == NULL) {
+ state->continuation = cache_lookupsid_cont;
+ return WINBINDD_PENDING;
+ }
+
+ if (!NT_STATUS_IS_OK(centry->status)) {
+ centry_free(centry);
+ return WINBINDD_ERROR;
+ }
+
+ mem_ctx = talloc_init("winbindd_sid_to_name");
+ if (mem_ctx == NULL) {
+ centry_free(centry);
+ return WINBINDD_ERROR;
+ }
+
+ state->response.data.name.type =
+ (enum SID_NAME_USE)centry_uint32(centry);
+ dom_name = centry_string(centry, mem_ctx);
+ name = centry_string(centry, mem_ctx);
+ centry_free(centry);
+
+ fstrcpy(state->response.data.name.dom_name, dom_name);
+ fstrcpy(state->response.data.name.name, name);
+
+ talloc_destroy(mem_ctx);
+
+ return WINBINDD_OK;
+}
+
+static enum winbindd_result
+cache_lookupname_cont(struct winbindd_cli_state *state, pid_t dual)
+{
+ return cache_lookupname(state);
+}
+
+enum winbindd_result cache_lookupname(struct winbindd_cli_state *state)
+{
+ fstring domain_name, user_name;
+ DOM_SID *sid;
+ struct winbindd_domain *domain;
+ char *p;
+ struct cache_entry *centry = NULL;
+ TALLOC_CTX *mem_ctx;
+
+ /* 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 != NULL) {
+ *p = 0;
+ fstrcpy(domain_name, state->request.data.name.name);
+ fstrcpy(user_name, p+1);
+ } else {
+ fstrcpy(domain_name, state->request.data.name.dom_name);
+ fstrcpy(user_name,state->request.data.name.name);
+ }
+
+ strupper_m(domain_name);
+ strupper_m(user_name);
+
+ DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
+ domain_name, lp_winbind_separator(), user_name));
+
+ if ((domain = find_lookup_domain_from_name(domain_name)) == NULL) {
+ DEBUG(0, ("could not find domain entry for domain %s\n",
+ domain_name));
+ return WINBINDD_ERROR;
+ }
+
+ centry = wcache_fetch_only("NS/%s/%s", domain_name, user_name);
+
+ if ((state->continuation != NULL) && /* Here the second time */
+ (centry == NULL)) {
+ DEBUG(1, ("Internal error, no centry second time\n"));
+ return WINBINDD_ERROR;
+ }
+
+ if ((centry == NULL) || centry_expired(domain, centry))
+ state->send_to_background = True;
+
+ if (centry == NULL) {
+ state->continuation = cache_lookupname_cont;
+ return WINBINDD_PENDING;
+ }
+
+ if (!NT_STATUS_IS_OK(centry->status)) {
+ centry_free(centry);
+ return WINBINDD_ERROR;
+ }
+
+ mem_ctx = talloc_init("winbindd_name_to_sid");
+ if (mem_ctx == NULL) {
+ centry_free(centry);
+ return WINBINDD_ERROR;
+ }
+
+ state->response.data.sid.type =
+ (enum SID_NAME_USE)centry_uint32(centry);
+
+ sid = centry_sid(centry, mem_ctx);
+ if (sid == NULL)
+ ZERO_STRUCTP(sid);
+ centry_free(centry);
+
+ sid_to_string(state->response.data.sid.sid, sid);
+
+ talloc_destroy(mem_ctx);
+
+ return WINBINDD_OK;
+}
+
+/* State machine for listing users
+ Look into the cache. 3 cases can happen:
+
+ * Data exist and is fresh
+ -> Fill buffer and directly go to next domain
+ * Data exist and is stale
+ -> Fill buffer, send to dual. When called again check next domain
+ * Data don't exist
+ -> Send to dual. When called again goto next if not there.
+
+*/
+
+struct list_entries_private {
+ struct winbindd_domain *domain;
+ BOOL expect_data;
+ char *extra_data;
+ int extra_data_len;
+};
+
+static enum winbindd_result
+cache_list_users_next(struct winbindd_cli_state *state, pid_t dual);
+
+enum winbindd_result cache_list_users(struct winbindd_cli_state *state)
+{
+ struct list_entries_private *priv;
+
+ if (state->continuation_private != NULL) {
+ DEBUG(0, ("Internal error, continuation_private != NULL\n"));
+ return WINBINDD_ERROR;
+ }
+
+ state->continuation = cache_list_users_next;
+ state->continuation_private = priv =
+ malloc(sizeof(struct list_entries_private));
+
+ priv->domain = domain_list();
+ priv->expect_data = False;
+ priv->extra_data = NULL;
+ priv->extra_data_len = 0;
+
+ return cache_list_users_next(state, -1);
+}
+
+static enum winbindd_result
+cache_list_users_next(struct winbindd_cli_state *state, pid_t dual)
+{
+ struct cache_entry *centry;
+ struct list_entries_private *priv =
+ (struct list_entries_private *)state->continuation_private;
+ int i, num_entries;
+ TALLOC_CTX *mem_ctx;
+ BOOL expired = False;
+
+ next_domain:
+
+ centry = wcache_fetch_only("UL/%s", priv->domain->name);
+
+ if ((centry == NULL) && (priv->expect_data)) {
+ /* We've been called again after the dual had been asked to
+ * query the data */
+ priv->expect_data = False;
+ goto no_entries;
+ }
+
+ priv->expect_data = False;
+
+ if (centry == NULL) {
+ priv->expect_data = True;
+ state->send_to_background = True;
+ fstrcpy(state->request.domain_name, priv->domain->name);
+ return WINBINDD_PENDING;
+ }
+
+ num_entries = centry_uint32(centry);
+
+ priv->extra_data = Realloc(priv->extra_data,
+ priv->extra_data_len +
+ sizeof(fstring) * num_entries);
+
+ if (priv->extra_data == NULL) {
+ return WINBINDD_ERROR;
+ }
+
+ mem_ctx = talloc_init("cache_list_users_next");
+
+ for (i=0; i + char *p;
+ fstring acct_name, name;
+
+ p = centry_string(centry, mem_ctx);
+
+ if ((p == NULL) || (*p == '\0'))
+ fstrcpy(acct_name, "");
+ else
+ fstrcpy(acct_name, p);
+
+ fill_domain_username(name, priv->domain->name, acct_name);
+
+ memcpy(&priv->extra_data[priv->extra_data_len], name,
+ strlen(name));
+ priv->extra_data_len += strlen(name);
+ priv->extra_data[priv->extra_data_len++] = ',';
+
+ /* Dump full_name, user_sid and group_sid */
+ centry_string(centry, mem_ctx);
+ centry_string(centry, mem_ctx);
+ centry_string(centry, mem_ctx);
+ }
+
+ expired = centry_expired(priv->domain, centry);
+
+ centry_free(centry);
+ talloc_destroy(mem_ctx);
+
+ no_entries:
+
+ priv->domain = priv->domain->next;
+
+ if (priv->domain == NULL) {
+ state->response.length = sizeof(state->response);
+ if (priv->extra_data != NULL) {
+ priv->extra_data[priv->extra_data_len - 1] = '\0';
+ state->response.extra_data = priv->extra_data;
+ state->response.length += priv->extra_data_len;
+ }
+ SAFE_FREE(state->continuation_private);
+ return WINBINDD_OK;
+ }
+
+ if (expired) {
+ state->send_to_background = True;
+ fstrcpy(state->request.domain_name, priv->domain->name);
+ return WINBINDD_PENDING;
+ }
+
+ /* If we had tail recursion, we could call ourselves :-) */
+ goto next_domain;
+}
+
+static enum winbindd_result
+cache_list_groups_next(struct winbindd_cli_state *state, pid_t dual);
+
+enum winbindd_result cache_list_groups(struct winbindd_cli_state *state)
+{
+ struct list_entries_private *priv;
+
+ if (state->continuation_private != NULL) {
+ DEBUG(0, ("Internal error, continuation_private != NULL\n"));
+ return WINBINDD_ERROR;
+ }
+
+ state->continuation = cache_list_groups_next;
+ state->continuation_private = priv =
+ malloc(sizeof(struct list_entries_private));
+
+ priv->domain = domain_list();
+ priv->expect_data = False;
+ priv->extra_data = NULL;
+ priv->extra_data_len = 0;
+
+ return cache_list_groups_next(state, -1);
+}
+
+static enum winbindd_result
+cache_list_groups_next(struct winbindd_cli_state *state, pid_t dual)
+{
+ struct cache_entry *centry;
+ struct list_entries_private *priv =
+ (struct list_entries_private *)state->continuation_private;
+ int i, num_entries;
+ TALLOC_CTX *mem_ctx;
+ BOOL expired = False;
+
+ next_domain:
+
+ centry = wcache_fetch_only("GL/%s/domain", priv->domain->name);
+
+ if ((centry == NULL) && (priv->expect_data)) {
+ /* We've been called again after the dual had been asked to
+ * query the data */
+ priv->expect_data = False;
+ goto no_entries;
+ }
+
+ priv->expect_data = False;
+
+ if (centry == NULL) {
+ priv->expect_data = True;
+ state->send_to_background = True;
+ fstrcpy(state->request.domain_name, priv->domain->name);
+ return WINBINDD_PENDING;
+ }
+
+ num_entries = centry_uint32(centry);
+
+ priv->extra_data = Realloc(priv->extra_data,
+ priv->extra_data_len +
+ sizeof(fstring) * num_entries);
+
+ if (priv->extra_data == NULL) {
+ return WINBINDD_ERROR;
+ }
+
+ mem_ctx = talloc_init("cache_list_groups_next");
+
+ for (i=0; i + char *p;
+ fstring acct_name, name;
+
+ p = centry_string(centry, mem_ctx);
+
+ if ((p == NULL) || (*p == '\0'))
+ fstrcpy(acct_name, "");
+ else
+ fstrcpy(acct_name, p);
+
+ fill_domain_username(name, priv->domain->name, acct_name);
+
+ memcpy(&priv->extra_data[priv->extra_data_len], name,
+ strlen(name));
+ priv->extra_data_len += strlen(name);
+ priv->extra_data[priv->extra_data_len++] = ',';
+
+ /* Dump acct_desc and group_rid */
+ centry_string(centry, mem_ctx);
+ centry_uint32(centry);
+ }
+
+ expired = centry_expired(priv->domain, centry);
+
+ centry_free(centry);
+ talloc_destroy(mem_ctx);
+
+ no_entries:
+
+ priv->domain = priv->domain->next;
+
+ if (priv->domain == NULL) {
+ state->response.length = sizeof(state->response);
+ if (priv->extra_data != NULL) {
+ priv->extra_data[priv->extra_data_len - 1] = '\0';
+ state->response.extra_data = priv->extra_data;
+ state->response.length += priv->extra_data_len;
+ }
+ SAFE_FREE(state->continuation_private);
+ return WINBINDD_OK;
+ }
+
+ if (expired) {
+ state->send_to_background = True;
+ fstrcpy(state->request.domain_name, priv->domain->name);
+ return WINBINDD_PENDING;
+ }
+
+ /* If we had tail recursion, we could call ourselves :-) */
+ goto next_domain;
+}
+
+static enum winbindd_result
+cache_getusersids_cont(struct winbindd_cli_state *state, pid_t dual)
+{
+ return cache_getusersids(state);
+}
+
+enum winbindd_result cache_getusersids(struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ DOM_SID **user_sids;
+ struct winbindd_domain *domain;
+ unsigned int i;
+ TALLOC_CTX *mem_ctx;
+ char *ret = NULL;
+ uint32 num_groups;
+ unsigned ofs, ret_size = 0;
+ struct cache_entry *centry = NULL;
+
+ /* 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 convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ DEBUG(10, ("cache_getusersids called for sid %s, cont=%x\n",
+ sid_string_static(&user_sid), state->continuation));
+
+ domain = find_lookup_domain_from_sid(&user_sid);
+
+ if (!domain) {
+ DEBUG(1,("Can't find domain from sid\n"));
+ return WINBINDD_ERROR;
+ }
+
+ centry = wcache_fetch_only("UG/%s", sid_string_static(&user_sid));
+
+#if 1
+ /* Torture code ... */
+ if (state->continuation == NULL) {
+ centry_free(centry);
+ centry = NULL;
+ }
+#endif
+
+ if ((state->continuation != NULL) && /* Here the second time */
+ (centry == NULL)) {
+ DEBUG(1, ("Internal error, no centry second time\n"));
+ return WINBINDD_ERROR;
+ }
+
+ if ((centry == NULL) || centry_expired(domain, centry))
+ state->send_to_background = True;
+
+ if (centry == NULL) {
+ state->continuation = cache_getusersids_cont;
+ return WINBINDD_PENDING;
+ }
+
+ mem_ctx = talloc_init("winbindd_getusersids(%s)",
+ state->request.data.username);
+
+ if (mem_ctx == NULL) {
+ centry_free(centry);
+ return WINBINDD_ERROR;
+ }
+
+ num_groups = centry_uint32(centry);
+
+ user_sids = talloc(mem_ctx, sizeof(*user_sids) * num_groups);
+ if ((num_groups != 0) && (user_sids == NULL))
+ smb_panic("cache_getusersids out of memory");
+
+ for (i=0; i + user_sids[i] = centry_sid(centry, mem_ctx);
+
+ centry_free(centry);
+
+ /* work out the response size */
+ for (i = 0; i < num_groups; i++) {
+ const char *s = sid_string_static(user_sids[i]);
+ ret_size += strlen(s) + 1;
+ }
+
+ ret = malloc(ret_size);
+ if ((ret_size != 0) && (ret == NULL))
+ smb_panic("cache_getusersids out of memory");
+
+ ofs = 0;
+ for (i = 0; i < num_groups; i++) {
+ const char *s = sid_string_static(user_sids[i]);
+ safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
+ ofs += strlen(ret+ofs) + 1;
+ }
+
+ /* Send data back to client */
+ state->response.data.num_entries = num_groups;
+ state->response.extra_data = ret;
+ state->response.length += ret_size;
+
+ talloc_destroy(mem_ctx);
+
+ return WINBINDD_OK;
+}
+
+void cache_store_response(pid_t pid, struct winbindd_response *response)
+{
+ TDB_DATA key, data;
+ fstring key_str;
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ key.dptr = key_str;
+ key.dsize = strlen(key_str);
+ data.dptr = (void *)response;
+ data.dsize = sizeof(*response);
+ if (tdb_store(wcache->tdb, key, data, TDB_REPLACE) == -1)
+ return;
+
+ if (response->length == sizeof(*response))
+ return;
+
+ /* There's extra data */
+
+ fstr_sprintf(key_str, "DE/%d", pid);
+ key.dptr = key_str;
+ key.dsize = strlen(key_str);
+ data.dptr = response->extra_data;
+ data.dsize = response->length - sizeof(*response);
+ if (tdb_store(wcache->tdb, key, data, 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);
+ key.dptr = key_str;
+ key.dsize = strlen(key_str);
+ tdb_delete(wcache->tdb, key);
+
+ return;
+}
+
+static BOOL cache_retrieve_response(pid_t pid,
+ struct winbindd_response * response)
+{
+ TDB_DATA key, data;
+ fstring key_str;
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ key.dptr = key_str;
+ key.dsize = strlen(key_str);
+
+ data = tdb_fetch(wcache->tdb, key);
+
+ 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))
+ return True;
+
+ /* There's extra data */
+
+ fstr_sprintf(key_str, "DE/%d", pid);
+ key.dptr = key_str;
+ key.dsize = strlen(key_str);
+
+ data = tdb_fetch(wcache->tdb, key);
+
+ if (data.dptr == NULL)
+ return False;
+
+ if (data.dsize != (response->length - sizeof(*response))) {
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+
+ response->extra_data = data.dptr;
+ return True;
+}
+
+static enum winbindd_result dual_response(struct winbindd_cli_state *state,
+ pid_t dual)
+{
+ if (!cache_retrieve_response(dual, &state->response))
+ return WINBINDD_ERROR;
+ return state->response.result;
+}
+
+enum winbindd_result dual_request(struct winbindd_cli_state *state)
+{
+ state->send_to_background = True;
+ state->request.flags |= WBFLAG_CACHE_RESPONSE;
+ state->continuation = dual_response;
+ return WINBINDD_PENDING;
+}
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd_cm.c ./nsswitch/winbindd_cm.c
--- ../../samba-3.0.7/source/nsswitch/winbindd_cm.c 2004-09-16 14:30:16.000000000 +0200
+++ ./source/nsswitch/winbindd_cm.c 2004-09-15 18:15:38.000000000 +0200
@@ -505,6 +505,8 @@ static BOOL get_dcs_1c(TALLOC_CTX *mem_c
}
}

+ SAFE_FREE(iplist);
+
return True;
}

diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd_dual.c ./nsswitch/winbindd_dual.c
--- ../../samba-3.0.7/source/nsswitch/winbindd_dual.c 2004-04-04 09:37:18.000000000 +0200
+++ ./source/nsswitch/winbindd_dual.c 2004-09-15 18:15:38.000000000 +0200
@@ -42,32 +42,107 @@ int dual_daemon_pipe = -1;

/* a list of requests ready to be sent to the dual daemon */
struct dual_list {
- struct dual_list *next;
+ struct dual_list *next, *prev;
+ char *data;
+ int length;
+};
+
+struct dual_child {
+ struct dual_child *next, *prev;
+ BOOL busy;
+ pid_t pid;
+ int fd;
char *data;
int length;
int offset;
};

+static struct dual_child *child_list;
+
static struct dual_list *dual_list;
-static struct dual_list *dual_list_end;
+
+static BOOL dual_schedule_request(void)
+{
+ struct dual_child *child;
+ int busy_children = 0;
+
+ if (dual_list == NULL)
+ return False;
+
+ for (child = child_list; child != NULL; child = child->next) {
+ struct dual_list *this;
+
+ if (child->busy) {
+ extern int max_busy_children;
+ busy_children += 1;
+ if (busy_children > max_busy_children)
+ max_busy_children = busy_children;
+ continue;
+ }
+
+ SMB_ASSERT(child->data == NULL);
+
+ DEBUG(10, ("scheduling %d\n",
+ ((struct winbindd_request *)(dual_list->data))->cmd));
+
+ child->data = dual_list->data;
+ child->length = dual_list->length;
+ child->offset = 0;
+ child->busy = True;
+
+ this = dual_list;
+
+ DLIST_REMOVE(dual_list, this);
+ free(this);
+
+ return True;
+ }
+ return False;
+}
+
+void dual_finished(pid_t pid)
+{
+ struct dual_child *child;
+
+ for (child = child_list; child != NULL; child = child->next) {
+ if (child->pid == pid) {
+ child->busy = False;
+ return;
+ }
+ }
+}

/*
setup a select() including the dual daemon pipe
*/
int dual_select_setup(fd_set *fds, int maxfd)
{
- if (dual_daemon_pipe == -1 ||
- !dual_list) {
- return maxfd;
- }
+ struct dual_child *child;

- FD_SET(dual_daemon_pipe, fds);
- if (dual_daemon_pipe > maxfd) {
- maxfd = dual_daemon_pipe;
+ while (dual_schedule_request())
+ ;
+
+ for (child = child_list; child != NULL; child = child->next) {
+ if (child->length == 0)
+ continue;
+
+ FD_SET(child->fd, fds);
+ if (child->fd > maxfd)
+ maxfd = child->fd;
}
+
return maxfd;
}

+static void resend_request(char *data, int length)
+{
+ struct dual_list *req;
+
+ req = malloc(sizeof(*req));
+ req->data = data;
+ req->length = length;
+ DLIST_ADD(dual_list, req);
+}

/*
a hook called from the main winbindd select() loop to handle writes
@@ -76,34 +151,54 @@ int dual_select_setup(fd_set *fds, int m
void dual_select(fd_set *fds)
{
int n;
+ struct dual_child *child;

- if (dual_daemon_pipe == -1 ||
- !dual_list ||
- !FD_ISSET(dual_daemon_pipe, fds)) {
- return;
- }
+ for (child = child_list; child != NULL; child = child->next) {
+ if (child->length == 0)
+ continue;
+
+ if (!FD_ISSET(child->fd, fds))
+ continue;
+
+ n = sys_write(child->fd,
+ &child->data[child->offset],
+ child->length - child->offset);
+
+ if (n <= 0) {
+ /* the pipe is dead! */
+ resend_request(child->data, child->length);
+ child->fd = -1;
+ continue;
+ }

- n = sys_write(dual_daemon_pipe,
- &dual_list->data[dual_list->offset],
- dual_list->length - dual_list->offset);
-
- if (n <= 0) {
- /* the pipe is dead! fall back to normal operation */
- dual_daemon_pipe = -1;
- return;
+ child->offset += n;
+
+ if (child->offset < child->length)
+ continue;
+
+ /* Data fully sent, discard it */
+
+ SAFE_FREE(child->data);
+ child->length = 0;
}

- dual_list->offset += n;
+ /* Remove dead children */
+ child = child_list;

- if (dual_list->offset == dual_list->length) {
- struct dual_list *next;
- next = dual_list->next;
- free(dual_list->data);
- free(dual_list);
- dual_list = next;
- if (!dual_list) {
- dual_list_end = NULL;
+ while (child != NULL) {
+ struct dual_child *next;
+ next = child->next;
+ if (child->fd == -1) {
+ DLIST_REMOVE(child_list, child);
+ free(child);
}
+ child = next;
+ }
+
+ if (child_list == NULL) {
+ extern BOOL opt_dual_daemon;
+ DEBUG(0, ("All children died -- normal operation\n"));
+ opt_dual_daemon = False;
}
}

@@ -113,25 +208,20 @@ void dual_select(fd_set *fds)
*/
void dual_send_request(struct winbindd_cli_state *state)
{
- struct dual_list *list;
+ struct dual_list *req, *tmp;

if (!background_process) return;

- list = malloc(sizeof(*list));
- if (!list) return;
+ DEBUG(10, ("dual_send_request: cmd=%d, msgid=%d\n",
+ state->request.cmd, state->request.msgid));

- list->next = NULL;
- list->data = memdup(&state->request, sizeof(state->request));
- list->length = sizeof(state->request);
- list->offset = 0;
-
- if (!dual_list_end) {
- dual_list = list;
- dual_list_end = list;
- } else {
- dual_list_end->next = list;
- dual_list_end = list;
- }
+ req = malloc(sizeof(*req));
+ if (!req) return;
+
+ req->next = NULL;
+ req->data = memdup(&state->request, sizeof(state->request));
+ req->length = sizeof(state->request);
+ DLIST_ADD_END(dual_list, req, tmp);

background_process = False;
}
@@ -144,6 +234,7 @@ void do_dual_daemon(void)
{
int fdpair[2];
struct winbindd_cli_state state;
+ struct dual_child *child;

if (pipe(fdpair) != 0) {
return;
@@ -152,10 +243,23 @@ void do_dual_daemon(void)
ZERO_STRUCT(state);
state.pid = getpid();

- dual_daemon_pipe = fdpair[1];
+ child = malloc(sizeof(*child));
+
+ if (child == NULL)
+ return;
+
+ child->busy = False;
+ child->data = NULL;
+ child->length = 0;
+ child->offset = 0;
+
+ child->fd = fdpair[1];
state.sock = fdpair[0];
+ child->pid = sys_fork();
+
+ DLIST_ADD(child_list, child)

- if (fork() != 0) {
+ if (child->pid != 0) {
close(fdpair[0]);
return;
}
@@ -166,6 +270,11 @@ void do_dual_daemon(void)
DEBUG(0,("tdb_reopen_all failed.\n"));
_exit(0);
}
+
+ if (!message_init()) {
+ DEBUG(0, ("message_init failed\n"));
+ _exit(0);
+ }

dual_daemon_pipe = -1;
opt_dual_daemon = False;
@@ -202,6 +311,15 @@ void do_dual_daemon(void)
}

winbind_process_packet(&state);
+
+ if (state.request.flags & WBFLAG_CACHE_RESPONSE)
+ cache_store_response(getpid(),
+ &state.response);
+
+ message_send_pid(getppid(), MSG_WINBIND_FINISHED,
+ &state.request.msgid,
+ sizeof(state.request.msgid),
+ True);
SAFE_FREE(state.response.extra_data);

free_getent_state(state.getpwent_state);
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd_misc.c ./nsswitch/winbindd_misc.c
--- ../../samba-3.0.7/source/nsswitch/winbindd_misc.c 2004-04-04 09:37:17.000000000 +0200
+++ ./source/nsswitch/winbindd_misc.c 2004-09-15 18:15:38.000000000 +0200
@@ -244,11 +244,13 @@ enum winbindd_result winbindd_ping(struc

enum winbindd_result winbindd_info(struct winbindd_cli_state *state)
{
+ extern int max_busy_children;

DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));

state->response.data.info.winbind_separator = *lp_winbind_separator();
fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
+ state->response.data.info.max_busy_children = max_busy_children;

return WINBINDD_OK;
}
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd_nss.h ./nsswitch/winbindd_nss.h
--- ../../samba-3.0.7/source/nsswitch/winbindd_nss.h 2004-04-20 22:42:55.000000000 +0200
+++ ./source/nsswitch/winbindd_nss.h 2004-09-15 18:15:38.000000000 +0200
@@ -159,6 +159,7 @@ typedef struct winbindd_gr {
#define WBFLAG_PAM_UNIX_NAME 0x0080
#define WBFLAG_PAM_AFS_TOKEN 0x0100
#define WBFLAG_PAM_NT_STATUS_SQUASH 0x0200
+#define WBFLAG_CACHE_RESPONSE 0x0400

/* Winbind request structure */

@@ -169,6 +170,10 @@ struct winbindd_request {
uint32 flags; /* flags relavant to a given request */
fstring domain_name; /* name of domain for which the request applies */

+ int msgid; /* Uniquely identify a request, used in
+ * MSG_WINBINDD_FINISHED from dual daemon to
+ * parent. */
+
union {
fstring winsreq; /* WINS request */
fstring username; /* getpwnam */
@@ -217,7 +222,8 @@ struct winbindd_request {

enum winbindd_result {
WINBINDD_ERROR,
- WINBINDD_OK
+ WINBINDD_OK,
+ WINBINDD_PENDING
};

/* Winbind response structure */
@@ -259,6 +265,7 @@ struct winbindd_response {
struct winbindd_info {
char winbind_separator;
fstring samba_version;
+ int max_busy_children;
} info;
fstring domain_name;
fstring netbios_name;
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd_sid.c ./nsswitch/winbindd_sid.c
--- ../../samba-3.0.7/source/nsswitch/winbindd_sid.c 2004-09-16 14:30:16.000000000 +0200
+++ ./source/nsswitch/winbindd_sid.c 2004-09-16 12:40:22.000000000 +0200
@@ -494,3 +494,147 @@ enum winbindd_result winbindd_allocate_r

return WINBINDD_OK;
}
+
+enum winbindd_result cache_sid_to_uid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ uint32 flags = ID_CACHE_ONLY;
+ NTSTATUS result;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ 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 convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ if ( state->request.flags & WBFLAG_QUERY_ONLY )
+ flags |= ID_QUERY_ONLY;
+
+ /* Find uid for this sid and return it */
+
+ result = idmap_sid_to_uid(&sid, &(state->response.data.uid), flags);
+
+ if (NT_STATUS_IS_OK(result))
+ return WINBINDD_OK;
+
+ if (state->continuation != NULL) {
+ /* Here the second time, the SID could not be mapped by the
+ * dual daemon */
+ return WINBINDD_ERROR;
+ }
+
+ state->send_to_background = True;
+ state->continuation = cache_sid_to_uid;
+ return WINBINDD_PENDING;
+}
+
+enum winbindd_result cache_sid_to_gid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ uint32 flags = ID_CACHE_ONLY;
+ NTSTATUS result;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ 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 convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ if ( state->request.flags & WBFLAG_QUERY_ONLY )
+ flags |= ID_QUERY_ONLY;
+
+ /* Find uid for this sid and return it */
+
+ result = idmap_sid_to_gid(&sid, &(state->response.data.uid), flags);
+
+ if (NT_STATUS_IS_OK(result))
+ return WINBINDD_OK;
+
+ if (state->continuation != NULL) {
+ /* Here the second time, the SID could not be mapped by the
+ * dual daemon */
+ return WINBINDD_ERROR;
+ }
+
+ state->send_to_background = True;
+ state->continuation = cache_sid_to_gid;
+ return WINBINDD_PENDING;
+}
+
+enum winbindd_result cache_uid_to_sid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ unid_t id;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.uid));
+
+ /* Lookup rid for this uid */
+
+ id.uid = state->request.data.uid;
+
+ result = idmap_get_sid_from_id(&sid, id,
+ ID_USERID|ID_QUERY_ONLY|ID_CACHE_ONLY);
+
+ if (NT_STATUS_IS_OK(result)) {
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_USER;
+ return WINBINDD_OK;
+ }
+
+ if (state->continuation != NULL) {
+ /* Here the second time, the SID could not be mapped by the
+ * dual daemon */
+ return WINBINDD_ERROR;
+ }
+
+ state->send_to_background = True;
+ state->continuation = cache_uid_to_sid;
+ return WINBINDD_PENDING;
+}
+
+enum winbindd_result cache_gid_to_sid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ unid_t id;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.uid));
+
+ /* Lookup rid for this gid */
+
+ id.uid = state->request.data.gid;
+
+ result = idmap_get_sid_from_id(&sid, id,
+ ID_GROUPID|ID_QUERY_ONLY|ID_CACHE_ONLY);
+
+ if (NT_STATUS_IS_OK(result)) {
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_DOM_GRP;
+ return WINBINDD_OK;
+ }
+
+ if (state->continuation != NULL) {
+ /* Here the second time, the SID could not be mapped by the
+ * dual daemon */
+ return WINBINDD_ERROR;
+ }
+
+ state->send_to_background = True;
+ state->continuation = cache_gid_to_sid;
+ return WINBINDD_PENDING;
+}
diff -Npur --exclude=CVS --exclude='*.bak' --exclude='*.o' --exclude='*.po' --exclude='*.so' --exclude='.#*' --exclude=Makefile --exclude=stamp-h --exclude=configure --exclude=findsmb --exclude='*proto*.h' --exclude=build_env.h --exclude=tdbsam2_parse_info.h --exclude='config.*' --exclude=bin --exclude='*.configure' --exclude=autom4te.cache --exclude='build_options.c*' --exclude=TAGS --exclude='*~' --exclude=gen-8bit-gap.sh --exclude=smbadduser --exclude=version.h --exclude=.svn --exclude=.cvsignore --exclude='*.rej' --exclude='*.orig' ../../samba-3.0.7/source/nsswitch/winbindd_util.c ./nsswitch/winbindd_util.c
--- ../../samba-3.0.7/source/nsswitch/winbindd_util.c 2004-07-08 19:06:11.000000000 +0200
+++ ./source/nsswitch/winbindd_util.c 2004-09-15 18:15:38.000000000 +0200
@@ -175,7 +175,7 @@ static struct winbindd_domain *add_trust
/* Link to domain list */
DLIST_ADD(_domain_list, domain);

- DEBUG(2,("Added domain %s %s %s\n",
+ DEBUG(1,("Added domain %s %s %s\n",
domain->name, domain->alt_name,
&domain->sid?sid_string_static(&domain->sid):""));

@@ -303,9 +303,16 @@ BOOL init_domain_list(void)
domain = add_trusted_domain(get_global_sam_name(), NULL,
&passdb_methods, get_global_sam_sid());
} else {
+
+ DOM_SID our_sid;
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
+ DEBUG(0, ("Could not fetch our SID - did we join?\n"));
+ return False;
+ }

domain = add_trusted_domain( lp_workgroup(), lp_realm(),
- &cache_methods, NULL);
+ &cache_methods, &our_sid);

/* set flags about native_mode, active_directory */
set_dc_type_and_flags(domain);
@@ -736,6 +743,14 @@ void winbindd_remove_client(struct winbi
_num_clients--;
}

+/* Demote a client to be the last in the list */
+
+void winbindd_demote_client(struct winbindd_cli_state *cli)
+{
+ struct winbindd_cli_state *tmp;
+ DLIST_DEMOTE(_client_list, cli, tmp);
+}
+
/* Close all open clients */

void winbindd_kill_all_clients(void)
Binary files ../../samba-3.0.7/source/tdb/tdbdump and ./tdb/tdbdump differ
Binary files ../../samba-3.0.7/source/tdb/tdbtest and ./tdb/tdbtest differ
Binary files ../../samba-3.0.7/source/tdb/tdbtool and ./tdb/tdbtool differ
Binary files ../../samba-3.0.7/source/tdb/tdbtorture and ./tdb/tdbtorture differ

--neYutvxvOLaeuPCA--