From 32cb0660d22f3799840a6a2a88ae4c17f65af3da Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 9 May 2000 11:43:00 +0000 Subject: brought the winbindd code into head this does not yet compile, but I'm working on that. (This used to be commit 3fb862531a4e78dca13d16d958517b16e5bdd4e2) --- source3/nsswitch/winbindd_util.c | 633 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 633 insertions(+) create mode 100644 source3/nsswitch/winbindd_util.c (limited to 'source3/nsswitch/winbindd_util.c') diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c new file mode 100644 index 0000000000..33150d1a62 --- /dev/null +++ b/source3/nsswitch/winbindd_util.c @@ -0,0 +1,633 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "winbindd.h" +#include "sids.h" + +BOOL domain_handles_open(struct winbindd_domain *domain) +{ + return domain->sam_handle_open && + domain->sam_dom_handle_open; +} + +static BOOL resolve_dc_name(char *domain_name, fstring domain_controller) +{ + struct in_addr ip; + extern pstring global_myname; + + /* if its our primary domain and password server is not '*' then use the + password server parameter */ + if (strcmp(domain_name,lp_workgroup()) == 0 && + strcmp(lp_passwordserver(),"*") != 0) { + fstrcpy(domain_controller, lp_passwordserver()); + return True; + } + + if (!resolve_name(domain_name, &ip, 0x1B)) return False; + + return lookup_pdc_name(global_myname, domain_name, &ip, domain_controller); +} + + +static struct winbindd_domain *add_trusted_domain(char *domain_name) +{ + struct winbindd_domain *domain; + + DEBUG(1, ("adding trusted domain %s\n", domain_name)); + + /* Create new domain entry */ + + if ((domain = (struct winbindd_domain *)malloc(sizeof(*domain))) == NULL) { + return NULL; + } + + /* Fill in fields */ + + ZERO_STRUCTP(domain); + + if (domain_name) { + fstrcpy(domain->name, domain_name); + } + + /* Link to domain list */ + + DLIST_ADD(domain_list, domain); + + return domain; +} + +/* Look up global info for the winbind daemon */ +static BOOL get_trusted_domains(void) +{ + uint32 enum_ctx = 0; + uint32 num_doms = 0; + char **domains = NULL; + DOM_SID **sids = NULL; + BOOL result; + int i; + + DEBUG(1, ("getting trusted domain list\n")); + + /* Add our workgroup - keep handle to look up trusted domains */ + if (!add_trusted_domain(lp_workgroup())) { + DEBUG(0, ("could not add record for domain %s\n", lp_workgroup())); + return False; + } + + /* Enumerate list of trusted domains */ + result = lsa_enum_trust_dom(&server_state.lsa_handle, &enum_ctx, + &num_doms, &domains, &sids); + + if (!result || !domains) return False; + + /* Add each domain to the trusted domain list */ + for(i = 0; i < num_doms; i++) { + if (!add_trusted_domain(domains[i])) { + DEBUG(0, ("could not add record for domain %s\n", domains[i])); + result = False; + } + } + + /* Free memory */ + free_char_array(num_doms, domains); + free_sid_array(num_doms, sids); + + return True; +} + + +/* Open sam and sam domain handles to a domain and cache the results */ +static BOOL open_sam_handles(struct winbindd_domain *domain) +{ + /* Get domain info */ + if (!domain->got_domain_info) { + domain->got_domain_info = get_domain_info(domain); + if (!domain->got_domain_info) return False; + } + + /* Open sam handle if it isn't already open */ + if (!domain->sam_handle_open) { + domain->sam_handle_open = + samr_connect(domain->controller, SEC_RIGHTS_MAXIMUM_ALLOWED, + &domain->sam_handle); + if (!domain->sam_handle_open) return False; + } + + /* Open sam domain handle if it isn't already open */ + if (!domain->sam_dom_handle_open) { + domain->sam_dom_handle_open = + samr_open_domain(&domain->sam_handle, + SEC_RIGHTS_MAXIMUM_ALLOWED, &domain->sid, + &domain->sam_dom_handle); + if (!domain->sam_dom_handle_open) return False; + } + + return True; +} + +static void winbindd_kill_connections(void) +{ + struct winbindd_domain *domain; + + DEBUG(1,("killing winbindd connections\n")); + + server_state.pwdb_initialised = False; + server_state.lsa_handle_open = False; + lsa_close(&server_state.lsa_handle); + + for (domain=domain_list; domain; domain=domain->next) { + if (domain->sam_dom_handle_open) { + samr_close(&domain->sam_dom_handle); + domain->sam_dom_handle_open = False; + } + if (domain->sam_handle_open) { + samr_close(&domain->sam_handle); + domain->sam_handle_open = False; + } + DLIST_REMOVE(domain_list, domain); + free(domain); + } +} + +void establish_connections(void) +{ + struct winbindd_domain *domain; + static time_t lastt; + time_t t; + + t = time(NULL); + if (t - lastt < WINBINDD_ESTABLISH_LOOP) return; + lastt = t; + + /* maybe the connection died - if so then close up and restart */ + if (server_state.pwdb_initialised && + server_state.lsa_handle_open && + !rpc_hnd_ok(&server_state.lsa_handle)) { + winbindd_kill_connections(); + } + + if (!server_state.pwdb_initialised) { + fstrcpy(server_state.controller, lp_passwordserver()); + if (strcmp(server_state.controller,"*") == 0) { + if (!resolve_dc_name(lp_workgroup(), server_state.controller)) { + return; + } + } + + server_state.pwdb_initialised = pwdb_initialise(False); + if (!server_state.pwdb_initialised) return; + } + + /* Open lsa handle if it isn't already open */ + if (!server_state.lsa_handle_open) { + server_state.lsa_handle_open = + lsa_open_policy(server_state.controller, &server_state.lsa_handle, + False, SEC_RIGHTS_MAXIMUM_ALLOWED); + if (!server_state.lsa_handle_open) return; + + /* now we can talk to the server we can get some info */ + get_trusted_domains(); + } + + for (domain=domain_list; domain; domain=domain->next) { + if (!domain_handles_open(domain)) { + open_sam_handles(domain); + } + } +} + + +/* Connect to a domain controller using get_any_dc_name() to discover + the domain name and sid */ +BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain) +{ + fstring level5_dom; + BOOL res; + uint32 enum_ctx = 0; + uint32 num_doms = 0; + char **domains = NULL; + DOM_SID **sids = NULL; + + if (domain == NULL) { + return False; + } + + DEBUG(1, ("looking up sid for domain %s\n", domain_name)); + + /* Get controller name for domain */ + if (!resolve_dc_name(domain_name, domain->controller)) { + return False; + } + + if (strequal(domain->controller, server_state.controller)) { + /* Do a level 5 query info policy */ + return lsa_query_info_pol(&server_state.lsa_handle, 0x05, + level5_dom, &domain->sid); + } + + /* Use lsaenumdomains to get sid for this domain */ + + res = lsa_enum_trust_dom(&server_state.lsa_handle, &enum_ctx, + &num_doms, &domains, &sids); + + /* Look for domain name */ + + if (res && domains && sids) { + int found = False; + int i; + + for(i = 0; i < num_doms; i++) { + if (strequal(domain_name, domains[i])) { + sid_copy(&domain->sid, sids[i]); + found = True; + break; + } + } + + res = found; + } + + /* Free memory */ + + free_char_array(num_doms, domains); + free_sid_array(num_doms, sids); + + return res; +} + + +/* Lookup domain controller and sid for a domain */ + +BOOL get_domain_info(struct winbindd_domain *domain) +{ + fstring sid_str; + + DEBUG(1, ("Getting domain info for domain %s\n", domain->name)); + + /* Lookup domain sid */ + if (!lookup_domain_sid(domain->name, domain)) { + DEBUG(0, ("could not find sid for domain %s\n", domain->name)); + return False; + } + + /* Lookup OK */ + + domain->got_domain_info = 1; + + sid_to_string(sid_str, &domain->sid); + DEBUG(1, ("found sid %s for domain %s\n", sid_str, domain->name)); + + return True; +} + +/* Lookup a sid in a domain from a name */ + +BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, + char *name, DOM_SID *sid, + enum SID_NAME_USE *type) +{ + int num_sids = 0, num_names = 1; + DOM_SID *sids = NULL; + uint32 *types = NULL; + BOOL res; + + /* Don't bother with machine accounts */ + + if (name[strlen(name) - 1] == '$') { + return False; + } + + /* Lookup name */ + + res = lsa_lookup_names(&server_state.lsa_handle, num_names, (char **)&name, + &sids, &types, &num_sids); + + /* Return rid and type if lookup successful */ + + if (res) { + + /* Return sid */ + + if ((sid != NULL) && (sids != NULL)) { + sid_copy(sid, &sids[0]); + } + + /* Return name type */ + + if ((type != NULL) && (types != NULL)) { + *type = types[0]; + } + } + + /* Free memory */ + + if (types != NULL) free(types); + if (sids != NULL) free(sids); + + return res; +} + +/* Lookup a name in a domain from a sid */ + +BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain, + DOM_SID *sid, char *name, + enum SID_NAME_USE *type) +{ + int num_sids = 1, num_names = 0; + uint32 *types = NULL; + char **names; + BOOL res; + + /* Lookup name */ + res = lsa_lookup_sids(&server_state.lsa_handle, num_sids, &sid, &names, + &types, &num_names); + + /* Return name and type if successful */ + + if (res) { + + /* Return name */ + + if ((names != NULL) && (name != NULL)) { + fstrcpy(name, names[0]); + } + + /* Return name type */ + + if ((type != NULL) && (types != NULL)) { + *type = types[0]; + } + } + + /* Free memory */ + + safe_free(types); + free_char_array(num_names, names); + + return res; +} + +/* Lookup user information from a rid */ + +BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain, + uint32 user_rid, SAM_USERINFO_CTR *user_info) +{ + if (!domain_handles_open(domain)) return False; + + return get_samr_query_userinfo(&domain->sam_dom_handle, 0x15, user_rid, user_info); +} + +/* Lookup group information from a rid */ + +BOOL winbindd_lookup_groupinfo(struct winbindd_domain *domain, + uint32 group_rid, GROUP_INFO_CTR *info) +{ + if (!domain_handles_open(domain)) return False; + + return get_samr_query_groupinfo(&domain->sam_dom_handle, 1, group_rid, info); +} + +/* Lookup group membership given a rid */ + +BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain, + uint32 group_rid, uint32 *num_names, + uint32 **rid_mem, char ***names, + enum SID_NAME_USE **name_types) +{ + if (!domain_handles_open(domain)) return False; + + return sam_query_groupmem(&domain->sam_dom_handle, group_rid, num_names, + rid_mem, names, name_types); +} + +/* Lookup alias membership given a rid */ + +int winbindd_lookup_aliasmem(struct winbindd_domain *domain, + uint32 alias_rid, uint32 *num_names, + DOM_SID ***sids, char ***names, + enum SID_NAME_USE **name_types) +{ + /* Open sam handles */ + if (!domain_handles_open(domain)) return False; + + return sam_query_aliasmem(domain->controller, + &domain->sam_dom_handle, alias_rid, num_names, + sids, names, name_types); +} + +/* Globals for domain list stuff */ + +struct winbindd_domain *domain_list = NULL; + +/* Given a domain name, return the struct winbindd domain info for it */ + +struct winbindd_domain *find_domain_from_name(char *domain_name) +{ + struct winbindd_domain *tmp; + + /* Search through list */ + for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { + if (strcmp(domain_name, tmp->name) == 0) { + if (!tmp->got_domain_info) return NULL; + return tmp; + } + } + + /* Not found */ + return NULL; +} + +/* Free state information held for {set,get,end}{pw,gr}ent() functions */ + +void free_getent_state(struct getent_state *state) +{ + struct getent_state *temp; + + /* Iterate over state list */ + + temp = state; + + while(temp != NULL) { + struct getent_state *next; + + /* Free sam entries then list entry */ + + safe_free(state->sam_entries); + DLIST_REMOVE(state, state); + next = temp->next; + + free(temp); + temp = next; + } +} + +/* Parse list of arguments to winbind uid or winbind gid parameters */ + +static BOOL parse_id_list(char *paramstr, BOOL is_user) +{ + uid_t id_low, id_high = 0; + + /* Parse entry */ + + if (sscanf(paramstr, "%u-%u", &id_low, &id_high) != 2) { + DEBUG(0, ("winbid %s parameter invalid\n", + is_user ? "uid" : "gid")); + return False; + } + + /* Store id info */ + + if (is_user) { + server_state.uid_low = id_low; + server_state.uid_high = id_high; + } else { + server_state.gid_low = id_low; + server_state.gid_high = id_high; + } + + return True; +} + +/* Initialise trusted domain info */ + +BOOL winbindd_param_init(void) +{ + /* Parse winbind uid and winbind_gid parameters */ + + if (!(parse_id_list(lp_winbind_uid(), True) && + parse_id_list(lp_winbind_gid(), False))) { + return False; + } + + /* Check for reversed uid and gid ranges */ + + if (server_state.uid_low > server_state.uid_high) { + DEBUG(0, ("uid range invalid\n")); + return False; + } + + if (server_state.gid_low > server_state.gid_high) { + DEBUG(0, ("gid range for invalid\n")); + return False; + } + + return True; +} + +/* Convert a enum winbindd_cmd to a string */ + +char *winbindd_cmd_to_string(enum winbindd_cmd cmd) +{ + char *result; + + switch (cmd) { + + case WINBINDD_GETPWNAM_FROM_USER: + result = "getpwnam from user"; + break; + + case WINBINDD_GETPWNAM_FROM_UID: + result = "getpwnam from uid"; + break; + + case WINBINDD_GETGRNAM_FROM_GROUP: + result = "getgrnam from group"; + break; + + case WINBINDD_GETGRNAM_FROM_GID: + result = "getgrnam from gid"; + break; + + case WINBINDD_SETPWENT: + result = "setpwent"; + break; + + case WINBINDD_ENDPWENT: + result = "endpwent"; + break; + + case WINBINDD_GETPWENT: + result = "getpwent"; + break; + + case WINBINDD_SETGRENT: + result = "setgrent"; + break; + + case WINBINDD_ENDGRENT: + result = "endgrent"; + break; + + case WINBINDD_GETGRENT: + result = "getgrent"; + break; + + case WINBINDD_PAM_AUTH: + result = "pam_auth"; + break; + + default: + result = "invalid command"; + break; + } + + return result; +}; + + +/* parse a string of the form DOMAIN/user into a domain and a user */ +void parse_domain_user(char *domuser, fstring domain, fstring user) +{ + char *p; + p = strchr(domuser,'/'); + if (!p) p = strchr(domuser,'\\'); + if (!p) { + fstrcpy(domain,""); + fstrcpy(user, domuser); + return; + } + + fstrcpy(user, p+1); + fstrcpy(domain, domuser); + domain[PTR_DIFF(p, domuser)] = 0; +} + +/* find the sequence number for a domain */ +uint32 domain_sequence_number(char *domain_name) +{ + struct winbindd_domain *domain; + SAM_UNK_CTR ctr; + + domain = find_domain_from_name(domain_name); + if (!domain) return DOM_SEQUENCE_NONE; + + if (!samr_query_dom_info(&domain->sam_dom_handle, 2, &ctr)) { + DEBUG(2,("domain sequence query failed\n")); + return DOM_SEQUENCE_NONE; + } + + DEBUG(4,("got domain sequence number for %s of %u\n", + domain_name, (unsigned)ctr.info.inf2.seq_num)); + + return ctr.info.inf2.seq_num; +} -- cgit