2 Unix SMB/Netbios implementation.
5 Winbind daemon for ntdom nss module
7 Copyright (C) Tim Potter 2000
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 BOOL domain_handles_open(struct winbindd_domain *domain)
28 return domain->sam_handle_open &&
29 domain->sam_dom_handle_open &&
30 rpc_hnd_ok(&domain->sam_handle) &&
31 rpc_hnd_ok(&domain->sam_dom_handle);
34 static BOOL resolve_dc_name(char *domain_name, fstring domain_controller)
37 extern pstring global_myname;
39 /* if its our primary domain and password server is not '*' then use the
40 password server parameter */
41 if (strcmp(domain_name,lp_workgroup()) == 0 && !lp_wildcard_dc()) {
42 fstrcpy(domain_controller, lp_passwordserver());
46 if (!resolve_name(domain_name, &ip, 0x1B)) return False;
48 return lookup_pdc_name(global_myname, domain_name, &ip,
52 static struct winbindd_domain *add_trusted_domain(char *domain_name)
54 struct winbindd_domain *domain;
56 DEBUG(1, ("adding trusted domain %s\n", domain_name));
58 /* Create new domain entry */
60 if ((domain = (struct winbindd_domain *)malloc(sizeof(*domain))) == NULL) {
69 fstrcpy(domain->name, domain_name);
72 /* Link to domain list */
74 DLIST_ADD(domain_list, domain);
79 /* Look up global info for the winbind daemon */
80 static BOOL get_trusted_domains(void)
84 char **domains = NULL;
85 DOM_SID **sids = NULL;
89 DEBUG(1, ("getting trusted domain list\n"));
91 /* Add our workgroup - keep handle to look up trusted domains */
92 if (!add_trusted_domain(lp_workgroup())) {
93 DEBUG(0, ("could not add record for domain %s\n",
98 /* Enumerate list of trusted domains */
99 result = lsa_enum_trust_dom(&server_state.lsa_handle, &enum_ctx,
100 &num_doms, &domains, &sids);
102 if (!result || !domains) return False;
104 /* Add each domain to the trusted domain list */
105 for(i = 0; i < num_doms; i++) {
106 if (!add_trusted_domain(domains[i])) {
107 DEBUG(0, ("could not add record for domain %s\n",
114 free_char_array(num_doms, domains);
115 free_sid_array(num_doms, sids);
121 /* Open sam and sam domain handles to a domain and cache the results */
122 static BOOL open_sam_handles(struct winbindd_domain *domain)
124 /* Get domain info */
125 if (!domain->got_domain_info) {
126 domain->got_domain_info = get_domain_info(domain);
127 if (!domain->got_domain_info) return False;
130 if ((domain->sam_handle_open && !rpc_hnd_ok(&domain->sam_handle)) ||
131 (domain->sam_dom_handle_open &&
132 !rpc_hnd_ok(&domain->sam_dom_handle))) {
134 domain->got_domain_info = get_domain_info(domain);
135 if (domain->sam_dom_handle_open) {
136 samr_close(&domain->sam_dom_handle);
137 domain->sam_dom_handle_open = False;
139 if (domain->sam_handle_open) {
140 samr_close(&domain->sam_handle);
141 domain->sam_handle_open = False;
145 /* Open sam handle if it isn't already open */
147 if (!domain->sam_handle_open) {
149 domain->sam_handle_open =
150 samr_connect(domain->controller,
151 SEC_RIGHTS_MAXIMUM_ALLOWED,
152 &domain->sam_handle);
154 if (!domain->sam_handle_open) return False;
157 /* Open sam domain handle if it isn't already open */
159 if (!domain->sam_dom_handle_open) {
161 domain->sam_dom_handle_open =
162 samr_open_domain(&domain->sam_handle,
163 SEC_RIGHTS_MAXIMUM_ALLOWED,
164 &domain->sid, &domain->sam_dom_handle);
166 if (!domain->sam_dom_handle_open) return False;
172 /* Close all LSA and SAM connections */
174 static void winbindd_kill_connections(void)
176 struct winbindd_cli_state *cli;
177 struct winbindd_domain *domain;
179 DEBUG(1,("killing winbindd connections\n"));
181 /* Close LSA connection */
183 server_state.pwdb_initialised = False;
184 server_state.lsa_handle_open = False;
185 lsa_close(&server_state.lsa_handle);
187 /* Close SAM connections */
189 domain = domain_list;
192 struct winbindd_domain *next;
194 /* Close SAM handles */
196 if (domain->sam_dom_handle_open) {
197 samr_close(&domain->sam_dom_handle);
198 domain->sam_dom_handle_open = False;
201 if (domain->sam_handle_open) {
202 samr_close(&domain->sam_handle);
203 domain->sam_handle_open = False;
206 /* Remove from list */
209 DLIST_REMOVE(domain_list, domain);
215 /* We also need to go through and trash any pointers to domains in
216 get{pw,gr}ent state records */
218 for (cli = client_list; cli; cli = cli->next) {
219 free_getent_state(cli->getpwent_state);
220 free_getent_state(cli->getgrent_state);
224 /* Try to establish connections to NT servers */
226 void establish_connections(void)
228 struct winbindd_domain *domain;
233 if (t - lastt < WINBINDD_ESTABLISH_LOOP) return;
236 /* maybe the connection died - if so then close up and restart */
237 if (server_state.pwdb_initialised &&
238 server_state.lsa_handle_open &&
239 !rpc_hnd_ok(&server_state.lsa_handle)) {
240 winbindd_kill_connections();
243 if (!server_state.pwdb_initialised) {
244 fstrcpy(server_state.controller, lp_passwordserver());
245 if (lp_wildcard_dc()) {
246 if (!resolve_dc_name(lp_workgroup(), server_state.controller)) {
251 server_state.pwdb_initialised = pwdb_initialise(False);
252 if (!server_state.pwdb_initialised) return;
255 /* Open lsa handle if it isn't already open */
256 if (!server_state.lsa_handle_open) {
257 server_state.lsa_handle_open =
258 lsa_open_policy(server_state.controller, &server_state.lsa_handle,
259 False, SEC_RIGHTS_MAXIMUM_ALLOWED);
260 if (!server_state.lsa_handle_open) return;
262 /* now we can talk to the server we can get some info */
263 get_trusted_domains();
266 for (domain=domain_list; domain; domain=domain->next) {
267 if (!domain_handles_open(domain)) {
268 open_sam_handles(domain);
274 /* Connect to a domain controller using get_any_dc_name() to discover
275 the domain name and sid */
276 BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
282 char **domains = NULL;
283 DOM_SID **sids = NULL;
285 if (domain == NULL) {
289 DEBUG(1, ("looking up sid for domain %s\n", domain_name));
291 /* Get controller name for domain */
292 if (!resolve_dc_name(domain_name, domain->controller)) {
296 if (strequal(domain->controller, server_state.controller)) {
297 /* Do a level 5 query info policy */
298 return lsa_query_info_pol(&server_state.lsa_handle, 0x05,
299 level5_dom, &domain->sid);
302 /* Use lsaenumdomains to get sid for this domain */
304 res = lsa_enum_trust_dom(&server_state.lsa_handle, &enum_ctx,
305 &num_doms, &domains, &sids);
307 /* Look for domain name */
309 if (res && domains && sids) {
313 for(i = 0; i < num_doms; i++) {
314 if (strequal(domain_name, domains[i])) {
315 sid_copy(&domain->sid, sids[i]);
326 free_char_array(num_doms, domains);
327 free_sid_array(num_doms, sids);
333 /* Lookup domain controller and sid for a domain */
335 BOOL get_domain_info(struct winbindd_domain *domain)
339 DEBUG(1, ("Getting domain info for domain %s\n", domain->name));
341 /* Lookup domain sid */
342 if (!lookup_domain_sid(domain->name, domain)) {
343 DEBUG(0, ("could not find sid for domain %s\n", domain->name));
349 domain->got_domain_info = 1;
351 sid_to_string(sid_str, &domain->sid);
352 DEBUG(1, ("found sid %s for domain %s\n", sid_str, domain->name));
357 /* Lookup a sid in a domain from a name */
359 BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
360 char *name, DOM_SID *sid,
361 enum SID_NAME_USE *type)
363 int num_sids = 0, num_names = 1;
364 DOM_SID *sids = NULL;
365 uint32 *types = NULL;
368 /* Don't bother with machine accounts */
370 if (name[strlen(name) - 1] == '$') {
376 res = lsa_lookup_names(&server_state.lsa_handle, num_names, (char **)&name,
377 &sids, &types, &num_sids);
379 /* Return rid and type if lookup successful */
385 if ((sid != NULL) && (sids != NULL)) {
386 sid_copy(sid, &sids[0]);
389 /* Return name type */
391 if ((type != NULL) && (types != NULL)) {
398 if (types != NULL) free(types);
399 if (sids != NULL) free(sids);
404 /* Lookup a name in a domain from a sid */
406 BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
407 DOM_SID *sid, char *name,
408 enum SID_NAME_USE *type)
410 int num_sids = 1, num_names = 0;
411 uint32 *types = NULL;
416 res = lsa_lookup_sids(&server_state.lsa_handle, num_sids, &sid, &names,
419 /* Return name and type if successful */
425 if ((names != NULL) && (name != NULL)) {
426 fstrcpy(name, names[0]);
429 /* Return name type */
431 if ((type != NULL) && (types != NULL)) {
439 free_char_array(num_names, names);
444 /* Lookup user information from a rid */
446 BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain,
447 uint32 user_rid, SAM_USERINFO_CTR *user_info)
449 if (!domain_handles_open(domain)) return False;
451 return get_samr_query_userinfo(&domain->sam_dom_handle, 0x15, user_rid, user_info);
454 /* Lookup group information from a rid */
456 BOOL winbindd_lookup_groupinfo(struct winbindd_domain *domain,
457 uint32 group_rid, GROUP_INFO_CTR *info)
459 if (!domain_handles_open(domain)) return False;
461 return get_samr_query_groupinfo(&domain->sam_dom_handle, 1, group_rid, info);
464 /* Lookup group membership given a rid */
466 BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
467 uint32 group_rid, uint32 *num_names,
468 uint32 **rid_mem, char ***names,
469 enum SID_NAME_USE **name_types)
471 if (!domain_handles_open(domain)) return False;
473 return sam_query_groupmem(&domain->sam_dom_handle, group_rid, num_names,
474 rid_mem, names, name_types);
477 /* Lookup alias membership given a rid */
479 int winbindd_lookup_aliasmem(struct winbindd_domain *domain,
480 uint32 alias_rid, uint32 *num_names,
481 DOM_SID ***sids, char ***names,
482 enum SID_NAME_USE **name_types)
484 /* Open sam handles */
485 if (!domain_handles_open(domain)) return False;
487 return sam_query_aliasmem(domain->controller,
488 &domain->sam_dom_handle, alias_rid, num_names,
489 sids, names, name_types);
492 /* Globals for domain list stuff */
494 struct winbindd_domain *domain_list = NULL;
496 /* Given a domain name, return the struct winbindd domain info for it */
498 struct winbindd_domain *find_domain_from_name(char *domain_name)
500 struct winbindd_domain *tmp;
502 /* Search through list */
503 for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
504 if (strcmp(domain_name, tmp->name) == 0) {
505 if (!tmp->got_domain_info) return NULL;
514 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
516 void free_getent_state(struct getent_state *state)
518 struct getent_state *temp;
520 /* Iterate over state list */
524 while(temp != NULL) {
525 struct getent_state *next;
527 /* Free sam entries then list entry */
529 safe_free(state->sam_entries);
530 DLIST_REMOVE(state, state);
538 /* Parse list of arguments to winbind uid or winbind gid parameters */
540 static BOOL parse_id_list(char *paramstr, BOOL is_user)
542 uid_t id_low, id_high = 0;
544 /* Give a nicer error message if no parameters specified */
546 if (strequal(paramstr, "")) {
547 DEBUG(0, ("winbid %s parameter missing\n", is_user ? "uid" : "gid"));
553 if (sscanf(paramstr, "%u-%u", &id_low, &id_high) != 2) {
554 DEBUG(0, ("winbid %s parameter invalid\n",
555 is_user ? "uid" : "gid"));
562 server_state.uid_low = id_low;
563 server_state.uid_high = id_high;
565 server_state.gid_low = id_low;
566 server_state.gid_high = id_high;
572 /* Initialise trusted domain info */
574 BOOL winbindd_param_init(void)
576 /* Parse winbind uid and winbind_gid parameters */
578 if (!(parse_id_list(lp_winbind_uid(), True) &&
579 parse_id_list(lp_winbind_gid(), False))) {
583 /* Check for reversed uid and gid ranges */
585 if (server_state.uid_low > server_state.uid_high) {
586 DEBUG(0, ("uid range invalid\n"));
590 if (server_state.gid_low > server_state.gid_high) {
591 DEBUG(0, ("gid range for invalid\n"));
598 /* Convert a enum winbindd_cmd to a string */
600 char *winbindd_cmd_to_string(enum winbindd_cmd cmd)
606 case WINBINDD_GETPWNAM_FROM_USER:
607 result = "getpwnam from user";
610 case WINBINDD_GETPWNAM_FROM_UID:
611 result = "getpwnam from uid";
614 case WINBINDD_GETGRNAM_FROM_GROUP:
615 result = "getgrnam from group";
618 case WINBINDD_GETGRNAM_FROM_GID:
619 result = "getgrnam from gid";
622 case WINBINDD_SETPWENT:
626 case WINBINDD_ENDPWENT:
630 case WINBINDD_GETPWENT:
634 case WINBINDD_SETGRENT:
638 case WINBINDD_ENDGRENT:
642 case WINBINDD_GETGRENT:
646 case WINBINDD_PAM_AUTH:
651 result = "invalid command";
659 /* parse a string of the form DOMAIN/user into a domain and a user */
660 void parse_domain_user(char *domuser, fstring domain, fstring user)
663 char *sep = lp_winbind_separator();
664 if (!sep) sep = "\\";
665 p = strchr(domuser,*sep);
666 if (!p) p = strchr(domuser,'\\');
669 fstrcpy(user, domuser);
674 fstrcpy(domain, domuser);
675 domain[PTR_DIFF(p, domuser)] = 0;
678 /* find the sequence number for a domain */
679 uint32 domain_sequence_number(char *domain_name)
681 struct winbindd_domain *domain;
684 domain = find_domain_from_name(domain_name);
685 if (!domain) return DOM_SEQUENCE_NONE;
687 if (!samr_query_dom_info(&domain->sam_dom_handle, 2, &ctr)) {
688 DEBUG(2,("domain sequence query failed\n"));
689 return DOM_SEQUENCE_NONE;
692 DEBUG(4,("got domain sequence number for %s of %u\n",
693 domain_name, (unsigned)ctr.info.inf2.seq_num));
695 return ctr.info.inf2.seq_num;