diff options
Diffstat (limited to 'source3/nsswitch')
-rw-r--r-- | source3/nsswitch/winbindd.c | 108 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.h | 2 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 4 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cm.c | 138 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_dual.c | 3 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_idmap.c | 194 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_idmap_tdb.c | 459 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_misc.c | 4 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_pam.c | 88 |
9 files changed, 846 insertions, 154 deletions
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index da2540f5d9..c7e45e5429 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -729,62 +729,6 @@ static void process_loop(void) } } - -/* - these are split out from the main winbindd for use by the background daemon - */ -BOOL winbind_setup_common(void) -{ - load_interfaces(); - - if (!secrets_init()) { - - DEBUG(0,("Could not initialize domain trust account secrets. Giving up\n")); - return False; - } - - namecache_enable(); /* Enable netbios namecache */ - - /* Check winbindd parameters are valid */ - - ZERO_STRUCT(server_state); - - if (!winbindd_param_init()) - return False; - - /* Winbind daemon initialisation */ - - if (!idmap_init()) - return False; - - if (!idmap_init_wellknown_sids()) - return False; - - /* Unblock all signals we are interested in as they may have been - blocked by the parent process. */ - - BlockSignals(False, SIGINT); - BlockSignals(False, SIGQUIT); - BlockSignals(False, SIGTERM); - BlockSignals(False, SIGUSR1); - BlockSignals(False, SIGUSR2); - BlockSignals(False, SIGHUP); - - /* Setup signal handlers */ - - CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */ - CatchSignal(SIGQUIT, termination_handler); - CatchSignal(SIGTERM, termination_handler); - - CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */ - - CatchSignal(SIGUSR2, sigusr2_handler); /* Debugging sigs */ - CatchSignal(SIGHUP, sighup_handler); - - return True; -} - - /* Main function */ struct winbindd_state server_state; /* Server state information */ @@ -868,6 +812,54 @@ int main(int argc, char **argv) if (!init_names()) exit(1); + load_interfaces(); + + if (!secrets_init()) { + + DEBUG(0,("Could not initialize domain trust account secrets. Giving up\n")); + return False; + } + + /* Enable netbios namecache */ + + namecache_enable(); + + /* Check winbindd parameters are valid */ + + ZERO_STRUCT(server_state); + + if (!winbindd_param_init()) + return 1; + + /* Winbind daemon initialisation */ + + if (!idmap_init()) + return 1; + + if (!idmap_init_wellknown_sids()) + exit(1); + + /* Unblock all signals we are interested in as they may have been + blocked by the parent process. */ + + BlockSignals(False, SIGINT); + BlockSignals(False, SIGQUIT); + BlockSignals(False, SIGTERM); + BlockSignals(False, SIGUSR1); + BlockSignals(False, SIGUSR2); + BlockSignals(False, SIGHUP); + + /* Setup signal handlers */ + + CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */ + CatchSignal(SIGQUIT, termination_handler); + CatchSignal(SIGTERM, termination_handler); + + CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */ + + CatchSignal(SIGUSR2, sigusr2_handler); /* Debugging sigs */ + CatchSignal(SIGHUP, sighup_handler); + if (!interactive) become_daemon(Fork); @@ -882,10 +874,6 @@ int main(int argc, char **argv) setpgid( (pid_t)0, (pid_t)0); #endif - if (!winbind_setup_common()) { - return 1; - } - if (opt_dual_daemon) { do_dual_daemon(); } diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 2d9a0b5949..987a58e502 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -219,7 +219,7 @@ struct winbindd_idmap_methods { void (*status)(void); }; -#include "winbindd_proto.h" +#include "../nsswitch/winbindd_proto.h" #include "rpc_parse.h" #include "rpc_client.h" diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index 27e168b6f9..dc40142a77 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -100,12 +100,12 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain) ret = smb_xmalloc(sizeof(*ret)); ZERO_STRUCTP(ret); - + switch (lp_security()) { /* winbind pdc disabled until ready if (!strcmp(domain->name, lp_workgroup()) && (lp_security() == SEC_USER)) { extern struct winbindd_methods passdb_methods; ret->backend = &passdb_methods; - } else switch (lp_security()) { + } else switch (lp_security()) { */ #ifdef HAVE_ADS case SEC_ADS: { extern struct winbindd_methods ads_methods; diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 02fd15e069..b04d77ee2e 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -415,21 +415,19 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index, static BOOL connection_ok(struct winbindd_cm_conn *conn) { if (!conn) { - smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n"); + smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n"); return False; } if (!conn->cli) { - DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", + DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", conn->controller, conn->domain, conn->pipe_name)); - smb_panic("connection_ok: conn->cli was null!"); return False; } if (!conn->cli->initialised) { - DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", + DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", conn->controller, conn->domain, conn->pipe_name)); - smb_panic("connection_ok: conn->cli->initialised is False!"); return False; } @@ -442,52 +440,73 @@ static BOOL connection_ok(struct winbindd_cm_conn *conn) return True; } -/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */ +/* Search the cache for a connection. If there is a broken one, + shut it down properly and return NULL. */ -static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name, - struct winbindd_cm_conn **conn_out) +static void find_cm_connection(const char *domain, const char *pipe_name, + struct winbindd_cm_conn **conn_out) { - struct winbindd_cm_conn *conn, conn_temp; - NTSTATUS result; - - *conn_out = NULL; + struct winbindd_cm_conn *conn; - for (conn = cm_conns; conn; conn = conn->next) { + for (conn = cm_conns; conn; ) { if (strequal(conn->domain, domain) && 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); - ZERO_STRUCT(conn_temp); - conn_temp.next = conn->next; DLIST_REMOVE(cm_conns, conn); SAFE_FREE(conn); - conn = &conn_temp; /* Just to keep the loop moving */ + conn = conn_temp; /* Keep the loop moving */ + continue; } else { break; } } + conn = conn->next; } - - if (!conn) { - if (!(conn = malloc(sizeof(*conn)))) - return NT_STATUS_NO_MEMORY; + + *conn_out = conn; +} + +/* Initialize a new connection up to the RPC BIND. */ + +static NTSTATUS new_cm_connection(const char *domain, const char *pipe_name, + struct winbindd_cm_conn **conn_out) +{ + struct winbindd_cm_conn *conn; + NTSTATUS result; + + if (!(conn = malloc(sizeof(*conn)))) + return NT_STATUS_NO_MEMORY; - ZERO_STRUCTP(conn); + 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, pipe_name, nt_errstr(result))); - SAFE_FREE(conn); - return result; - } - DLIST_ADD(cm_conns, 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, pipe_name, nt_errstr(result))); + SAFE_FREE(conn); + return result; } - + DLIST_ADD(cm_conns, conn); + *conn_out = conn; return NT_STATUS_OK; } +/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */ + +static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name, + struct winbindd_cm_conn **conn_out) +{ + find_cm_connection(domain, pipe_name, conn_out); + + if (*conn_out != NULL) + return NT_STATUS_OK; + + return new_cm_connection(domain, pipe_name, conn_out); +} /********************************************************************************** **********************************************************************************/ @@ -858,11 +877,11 @@ CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid, NTSTATUS cm_get_netlogon_cli(const char *domain, const unsigned char *trust_passwd, uint32 sec_channel_type, + BOOL fresh, struct cli_state **cli) { NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; struct winbindd_cm_conn *conn; - uint32 neg_flags = 0x000001ff; fstring lock_name; BOOL got_mutex; @@ -871,7 +890,30 @@ NTSTATUS cm_get_netlogon_cli(const char *domain, /* Open an initial conection - keep the mutex. */ - if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) + find_cm_connection(domain, PIPE_NETLOGON, &conn); + + if ( fresh && (conn != NULL) ) { + cli_shutdown(conn->cli); + conn->cli = NULL; + + conn = NULL; + + /* 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; + } + } + + if (conn != NULL) { + *cli = conn->cli; + return NT_STATUS_OK; + } + + result = new_cm_connection(domain, PIPE_NETLOGON, &conn); + + if (!NT_STATUS_IS_OK(result)) return result; snprintf(lock_name, sizeof(lock_name), "NETLOGON\\%s", conn->controller); @@ -880,38 +922,16 @@ NTSTATUS cm_get_netlogon_cli(const char *domain, DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller)); } - result = cli_nt_setup_creds(conn->cli, sec_channel_type, trust_passwd, &neg_flags, 2); + 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)) { - DEBUG(0, ("error connecting to domain password server: %s\n", - nt_errstr(result))); - - /* Hit the cache code again. This cleans out the old connection and gets a new one */ - if (conn->cli->fd == -1) { - if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) - return result; - - snprintf(lock_name, sizeof(lock_name), "NETLOGON\\%s", conn->controller); - 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)); - } - - /* Try again */ - result = cli_nt_setup_creds( conn->cli, sec_channel_type,trust_passwd, &neg_flags, 2); - - 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); - return result; - } + cli_shutdown(conn->cli); + DLIST_REMOVE(cm_conns, conn); + SAFE_FREE(conn); + return result; } *cli = conn->cli; diff --git a/source3/nsswitch/winbindd_dual.c b/source3/nsswitch/winbindd_dual.c index 3597171005..167630b0e1 100644 --- a/source3/nsswitch/winbindd_dual.c +++ b/source3/nsswitch/winbindd_dual.c @@ -166,9 +166,6 @@ void do_dual_daemon(void) _exit(0); } - if (!winbind_setup_common()) - _exit(0); - dual_daemon_pipe = -1; opt_dual_daemon = False; diff --git a/source3/nsswitch/winbindd_idmap.c b/source3/nsswitch/winbindd_idmap.c new file mode 100644 index 0000000000..3b23089200 --- /dev/null +++ b/source3/nsswitch/winbindd_idmap.c @@ -0,0 +1,194 @@ +/* + Unix SMB/CIFS implementation. + Winbind ID Mapping + Copyright (C) Tim Potter 2000 + Copyright (C) Anthony Liguori <aliguor@us.ibm.com> 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "winbindd.h" + +static struct { + const char *name; + /* Function to create a member of the idmap_methods list */ + BOOL (*reg_meth)(struct winbindd_idmap_methods **methods); + struct winbindd_idmap_methods *methods; +} builtin_winbindd_idmap_functions[] = { + { "tdb", winbind_idmap_reg_tdb, NULL }, + { NULL, NULL, NULL } +}; + +/* singleton pattern: uberlazy evaluation */ +static struct winbindd_idmap_methods *impl; + +static struct winbindd_idmap_methods *get_impl(const char *name) +{ + int i = 0; + struct winbindd_idmap_methods *ret = NULL; + + while (builtin_winbindd_idmap_functions[i].name && + strcmp(builtin_winbindd_idmap_functions[i].name, name)) { + i++; + } + + if (builtin_winbindd_idmap_functions[i].name) { + if (!builtin_winbindd_idmap_functions[i].methods) { + builtin_winbindd_idmap_functions[i].reg_meth(&builtin_winbindd_idmap_functions[i].methods); + } + + ret = builtin_winbindd_idmap_functions[i].methods; + } + + return ret; +} + +/* Initialize backend */ +BOOL winbindd_idmap_init(void) +{ + BOOL ret = False; + + DEBUG(3, ("winbindd_idmap_init: using '%s' as backend\n", + lp_winbind_backend())); + + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } + + if (impl) { + ret = impl->init(); + } + + DEBUG(3, ("winbind_idmap_init: returning %s\n", ret ? "true" : "false")); + + return ret; +} + +/* Get UID from SID */ +BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid) +{ + BOOL ret = False; + + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } + + if (impl) { + ret = impl->get_uid_from_sid(sid, uid); + } + + return ret; +} + +/* Get GID from SID */ +BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid) +{ + BOOL ret = False; + + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } + + if (impl) { + ret = impl->get_gid_from_sid(sid, gid); + } + + return ret; +} + +/* Get SID from UID */ +BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid) +{ + BOOL ret = False; + + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } + + if (impl) { + ret = impl->get_sid_from_uid(uid, sid); + } + + return ret; +} + +/* Get SID from GID */ +BOOL winbindd_idmap_get_sid_from_gid(gid_t gid, DOM_SID *sid) +{ + BOOL ret = False; + + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } + + if (impl) { + ret = impl->get_sid_from_gid(gid, sid); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + + return ret; +} + +/* Close backend */ +BOOL winbindd_idmap_close(void) +{ + BOOL ret = False; + + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } + + if (impl) { + ret = impl->close(); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + + return ret; +} + +/* Dump backend status */ +void winbindd_idmap_status(void) +{ + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } + + if (impl) { + impl->status(); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } +} diff --git a/source3/nsswitch/winbindd_idmap_tdb.c b/source3/nsswitch/winbindd_idmap_tdb.c new file mode 100644 index 0000000000..12d6972bae --- /dev/null +++ b/source3/nsswitch/winbindd_idmap_tdb.c @@ -0,0 +1,459 @@ +/* + Unix SMB/CIFS implementation. + + Winbind daemon - user related function + + Copyright (C) Tim Potter 2000 + Copyright (C) Anthony Liguori 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "winbindd.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND + +/* High water mark keys */ +#define HWM_GROUP "GROUP HWM" +#define HWM_USER "USER HWM" + +/* idmap version determines auto-conversion */ +#define IDMAP_VERSION 2 + +/* Globals */ +static TDB_CONTEXT *idmap_tdb; + +/* convert one record to the new format */ +static int tdb_convert_fn(TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data, + void *ignored) +{ + struct winbindd_domain *domain; + char *p; + DOM_SID sid; + uint32 rid; + fstring keystr; + fstring dom_name; + TDB_DATA key2; + + p = strchr(key.dptr, '/'); + if (!p) + return 0; + + *p = 0; + fstrcpy(dom_name, key.dptr); + *p++ = '/'; + + domain = find_domain_from_name(dom_name); + if (!domain) { + /* We must delete the old record. */ + DEBUG(0, + ("winbindd: tdb_convert_fn : Unable to find domain %s\n", + dom_name)); + DEBUG(0, + ("winbindd: tdb_convert_fn : deleting record %s\n", + key.dptr)); + tdb_delete(idmap_tdb, key); + return 0; + } + + rid = atoi(p); + + sid_copy(&sid, &domain->sid); + sid_append_rid(&sid, rid); + + sid_to_string(keystr, &sid); + key2.dptr = keystr; + key2.dsize = strlen(keystr) + 1; + + if (tdb_store(idmap_tdb, key2, data, TDB_INSERT) != 0) { + /* not good! */ + DEBUG(0, + ("winbindd: tdb_convert_fn : Unable to update record %s\n", + key2.dptr)); + DEBUG(0, + ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n")); + return -1; + } + + if (tdb_store(idmap_tdb, data, key2, TDB_REPLACE) != 0) { + /* not good! */ + DEBUG(0, + ("winbindd: tdb_convert_fn : Unable to update record %s\n", + data.dptr)); + DEBUG(0, + ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n")); + return -1; + } + + tdb_delete(idmap_tdb, key); + + return 0; +} + +/***************************************************************************** + Convert the idmap database from an older version. +*****************************************************************************/ +static BOOL tdb_idmap_convert(void) +{ + int32 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION"); + BOOL bigendianheader = + (idmap_tdb->flags & TDB_BIGENDIAN) ? True : False; + + if (vers == IDMAP_VERSION) + return True; + + if (((vers == -1) && bigendianheader) + || (IREV(vers) == IDMAP_VERSION)) { + /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */ + /* + * high and low records were created on a + * big endian machine and will need byte-reversing. + */ + + int32 wm; + + wm = tdb_fetch_int32(idmap_tdb, HWM_USER); + + if (wm != -1) { + wm = IREV(wm); + } else + wm = server_state.uid_low; + + if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) { + DEBUG(0, + ("tdb_idmap_convert: Unable to byteswap user hwm in idmap database\n")); + return False; + } + + wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP); + if (wm != -1) { + wm = IREV(wm); + } else + wm = server_state.gid_low; + + if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) { + DEBUG(0, + ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n")); + return False; + } + } + + /* the old format stored as DOMAIN/rid - now we store the SID direct */ + tdb_traverse(idmap_tdb, tdb_convert_fn, NULL); + + if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == + -1) { + DEBUG(0, + ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n")); + return False; + } + + return True; +} + +/* Allocate either a user or group id from the pool */ +static BOOL tdb_allocate_id(uid_t * id, BOOL isgroup) +{ + int hwm; + + /* Get current high water mark */ + if ((hwm = tdb_fetch_int32(idmap_tdb, + isgroup ? HWM_GROUP : HWM_USER)) == + -1) { + return False; + } + + /* Return next available uid in list */ + if ((isgroup && (hwm > server_state.gid_high)) || + (!isgroup && (hwm > server_state.uid_high))) { + DEBUG(0, + ("winbind %sid range full!\n", isgroup ? "g" : "u")); + return False; + } + + if (id) { + *id = hwm; + } + + hwm++; + + /* Store new high water mark */ + tdb_store_int32(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm); + + return True; +} + +/* Get a sid from an id */ +static BOOL tdb_get_sid_from_id(int id, DOM_SID * sid, BOOL isgroup) +{ + TDB_DATA key, data; + fstring keystr; + BOOL result = False; + + slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", + id); + + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + + data = tdb_fetch(idmap_tdb, key); + + if (data.dptr) { + result = string_to_sid(sid, data.dptr); + SAFE_FREE(data.dptr); + } + + return result; +} + +/* Get an id from a sid */ +static BOOL tdb_get_id_from_sid(DOM_SID * sid, uid_t * id, BOOL isgroup) +{ + TDB_DATA data, key; + fstring keystr; + BOOL result = False; + + /* Check if sid is present in database */ + sid_to_string(keystr, sid); + + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + + data = tdb_fetch(idmap_tdb, key); + + if (data.dptr) { + fstring scanstr; + int the_id; + + /* Parse and return existing uid */ + fstrcpy(scanstr, isgroup ? "GID" : "UID"); + fstrcat(scanstr, " %d"); + + if (sscanf(data.dptr, scanstr, &the_id) == 1) { + /* Store uid */ + if (id) { + *id = the_id; + } + + result = True; + } + + SAFE_FREE(data.dptr); + } else { + + /* Allocate a new id for this sid */ + if (id && tdb_allocate_id(id, isgroup)) { + fstring keystr2; + + /* Store new id */ + slprintf(keystr2, sizeof(keystr2), "%s %d", + isgroup ? "GID" : "UID", *id); + + data.dptr = keystr2; + data.dsize = strlen(keystr2) + 1; + + tdb_store(idmap_tdb, key, data, TDB_REPLACE); + tdb_store(idmap_tdb, data, key, TDB_REPLACE); + + result = True; + } + } + + return result; +} + +/***************************************************************************** + Initialise idmap database. +*****************************************************************************/ +static BOOL tdb_idmap_init(void) +{ + SMB_STRUCT_STAT stbuf; + + /* move to the new database on first startup */ + if (!file_exist(lock_path("idmap.tdb"), &stbuf)) { + if (file_exist(lock_path("winbindd_idmap.tdb"), &stbuf)) { + char *cmd = NULL; + + /* lazy file copy */ + if (asprintf(&cmd, "cp -p %s/winbindd_idmap.tdb %s/idmap.tdb", lp_lockdir(), lp_lockdir()) != -1) { + system(cmd); + free(cmd); + } + if (!file_exist(lock_path("idmap.tdb"), &stbuf)) { + DEBUG(0, ("idmap_init: Unable to make a new database copy\n")); + return False; + } + } + } + + /* Open tdb cache */ + if (!(idmap_tdb = tdb_open_log(lock_path("idmap.tdb"), 0, + TDB_DEFAULT, O_RDWR | O_CREAT, + 0600))) { + DEBUG(0, + ("winbindd_idmap_init: Unable to open idmap database\n")); + return False; + } + + /* possibly convert from an earlier version */ + if (!tdb_idmap_convert()) { + DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n")); + return False; + } + + /* Create high water marks for group and user id */ + if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) { + if (tdb_store_int32 + (idmap_tdb, HWM_USER, server_state.uid_low) == -1) { + DEBUG(0, + ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n")); + return False; + } + } + + if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) { + if (tdb_store_int32 + (idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) { + DEBUG(0, + ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n")); + return False; + } + } + + return True; +} + +/* Get a sid from a uid */ +static BOOL tdb_get_sid_from_uid(uid_t uid, DOM_SID * sid) +{ + return tdb_get_sid_from_id((int) uid, sid, False); +} + +/* Get a sid from a gid */ +static BOOL tdb_get_sid_from_gid(gid_t gid, DOM_SID * sid) +{ + return tdb_get_sid_from_id((int) gid, sid, True); +} + +/* Get a uid from a sid */ +static BOOL tdb_get_uid_from_sid(DOM_SID * sid, uid_t * uid) +{ + return tdb_get_id_from_sid(sid, uid, False); +} + +/* Get a gid from a group sid */ +static BOOL tdb_get_gid_from_sid(DOM_SID * sid, gid_t * gid) +{ + return tdb_get_id_from_sid(sid, gid, True); +} + +/* Close the tdb */ +static BOOL tdb_idmap_close(void) +{ + if (idmap_tdb) + return (tdb_close(idmap_tdb) == 0); + return True; +} + + +/* Dump status information to log file. Display different stuff based on + the debug level: + + Debug Level Information Displayed + ================================================================= + 0 Percentage of [ug]id range allocated + 0 High water marks (next allocated ids) +*/ + +#define DUMP_INFO 0 + +static void tdb_idmap_status(void) +{ + int user_hwm, group_hwm; + + DEBUG(0, ("winbindd idmap status:\n")); + + /* Get current high water marks */ + + if ((user_hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) { + DEBUG(DUMP_INFO, + ("\tCould not get userid high water mark!\n")); + } + + if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) { + DEBUG(DUMP_INFO, + ("\tCould not get groupid high water mark!\n")); + } + + /* Display next ids to allocate */ + + if (user_hwm != -1) { + DEBUG(DUMP_INFO, + ("\tNext userid to allocate is %d\n", user_hwm)); + } + + if (group_hwm != -1) { + DEBUG(DUMP_INFO, + ("\tNext groupid to allocate is %d\n", group_hwm)); + } + + /* Display percentage of id range already allocated. */ + + if (user_hwm != -1) { + int num_users = user_hwm - server_state.uid_low; + int total_users = + server_state.uid_high - server_state.uid_low; + + DEBUG(DUMP_INFO, + ("\tUser id range is %d%% full (%d of %d)\n", + num_users * 100 / total_users, num_users, + total_users)); + } + + if (group_hwm != -1) { + int num_groups = group_hwm - server_state.gid_low; + int total_groups = + server_state.gid_high - server_state.gid_low; + + DEBUG(DUMP_INFO, + ("\tGroup id range is %d%% full (%d of %d)\n", + num_groups * 100 / total_groups, num_groups, + total_groups)); + } + + /* Display complete mapping of users and groups to rids */ +} + +struct winbindd_idmap_methods tdb_idmap_methods = { + tdb_idmap_init, + + tdb_get_sid_from_uid, + tdb_get_sid_from_gid, + + tdb_get_uid_from_sid, + tdb_get_gid_from_sid, + + tdb_idmap_close, + + tdb_idmap_status +}; + +BOOL winbind_idmap_reg_tdb(struct winbindd_idmap_methods **meth) +{ + *meth = &tdb_idmap_methods; + + return True; +} diff --git a/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c index fb56d0e657..436c95053e 100644 --- a/source3/nsswitch/winbindd_misc.c +++ b/source3/nsswitch/winbindd_misc.c @@ -50,7 +50,9 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat the trust account password. */ /* Don't shut this down - it belongs to the connection cache code */ - result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, sec_channel_type, &cli); + result = cm_get_netlogon_cli(lp_workgroup(), + trust_passwd, sec_channel_type, + True, &cli); if (!NT_STATUS_IS_OK(result)) { DEBUG(3, ("could not open handle to NETLOGON pipe\n")); diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c index 2998372bd2..3b306eed3b 100644 --- a/source3/nsswitch/winbindd_pam.c +++ b/source3/nsswitch/winbindd_pam.c @@ -68,6 +68,8 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) TALLOC_CTX *mem_ctx = NULL; DATA_BLOB lm_resp; DATA_BLOB nt_resp; + DOM_CRED ret_creds; + int attempts = 0; /* Ensure null termination */ state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0'; @@ -119,23 +121,35 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) goto done; } - ZERO_STRUCT(info3); + do { + ZERO_STRUCT(info3); + ZERO_STRUCT(ret_creds); - /* Don't shut this down - it belongs to the connection cache code */ - result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, - sec_channel_type, - &cli); - - 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, - name_user, name_domain, - global_myname(), chal, - lm_resp, nt_resp, - &info3); + /* Don't shut this down - it belongs to the connection cache code */ + result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, + sec_channel_type, False, &cli); + + 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); + attempts += 1; + + /* We have to try a second time as cm_get_netlogon_cli + might not yet have noticed that the DC has killed + our connection. */ + + } while ( (attempts < 2) && (cli->fd == -1) ); + + + clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds); uni_group_cache_store_netlogon(mem_ctx, &info3); done: @@ -176,6 +190,8 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) const char *domain = NULL; const char *contact_domain; const char *workstation; + DOM_CRED ret_creds; + int attempts = 0; DATA_BLOB lm_resp, nt_resp; @@ -264,21 +280,37 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) goto done; } - ZERO_STRUCT(info3); + do { + ZERO_STRUCT(info3); + ZERO_STRUCT(ret_creds); + + /* 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); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", + nt_errstr(result))); + goto done; + } + + result = cli_netlogon_sam_network_logon(cli, mem_ctx, + &ret_creds, + user, domain, + workstation, + state->request.data.auth_crap.chal, + lm_resp, nt_resp, + &info3); + + attempts += 1; - /* Don't shut this down - it belongs to the connection cache code */ - result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, &cli); + /* We have to try a second time as cm_get_netlogon_cli + might not yet have noticed that the DC has killed + our connection. */ - if (!NT_STATUS_IS_OK(result)) { - DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", nt_errstr(result))); - goto done; - } + } while ( (attempts < 2) && (cli->fd == -1) ); - result = cli_netlogon_sam_network_logon(cli, mem_ctx, - user, domain, - workstation, state->request.data.auth_crap.chal, - lm_resp, nt_resp, - &info3); + clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds); if (NT_STATUS_IS_OK(result)) { uni_group_cache_store_netlogon(mem_ctx, &info3); |