2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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.
27 #define DBGC_CLASS DBGC_WINBIND
30 * @file winbindd_util.c
32 * Winbind daemon for NT domain authentication nss module.
37 * Used to clobber name fields that have an undefined value.
39 * Correct code should never look at a field that has this value.
42 static const fstring name_deadbeef
= "<deadbeef>";
44 /* The list of trusted domains. Note that the list can be deleted and
45 recreated using the init_domain_list() function so pointers to
46 individual winbindd_domain structures cannot be made. Keep a copy of
47 the domain name instead. */
49 static struct winbindd_domain
*_domain_list
;
51 struct winbindd_domain
*domain_list(void)
61 /* Free all entries in the trusted domain list */
63 void free_domain_list(void)
65 struct winbindd_domain
*domain
= _domain_list
;
68 struct winbindd_domain
*next
= domain
->next
;
70 DLIST_REMOVE(_domain_list
, domain
);
77 /* Add a trusted domain to our list of domains */
78 static struct winbindd_domain
*add_trusted_domain(const char *domain_name
, const char *alt_name
,
79 struct winbindd_methods
*methods
,
82 struct winbindd_domain
*domain
;
84 /* We can't call domain_list() as this function is called from
85 init_domain_list() and we'll get stuck in a loop. */
86 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
87 if (strcasecmp(domain_name
, domain
->name
) == 0 ||
88 strcasecmp(domain_name
, domain
->alt_name
) == 0) {
91 if (alt_name
&& *alt_name
) {
92 if (strcasecmp(alt_name
, domain
->name
) == 0 ||
93 strcasecmp(alt_name
, domain
->alt_name
) == 0) {
99 /* Create new domain entry */
101 if ((domain
= (struct winbindd_domain
*)
102 malloc(sizeof(*domain
))) == NULL
)
107 ZERO_STRUCTP(domain
);
109 /* prioritise the short name */
110 if (strchr_m(domain_name
, '.') && alt_name
&& *alt_name
) {
111 fstrcpy(domain
->name
, alt_name
);
112 fstrcpy(domain
->alt_name
, domain_name
);
114 fstrcpy(domain
->name
, domain_name
);
116 fstrcpy(domain
->alt_name
, alt_name
);
120 domain
->methods
= methods
;
121 domain
->backend
= NULL
;
122 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
123 domain
->last_seq_check
= 0;
125 sid_copy(&domain
->sid
, sid
);
128 /* see if this is a native mode win2k domain */
130 domain
->native_mode
= cm_check_for_native_mode_win2k( domain_name
);
131 DEBUG(3,("add_trusted_domain: %s is a %s mode domain\n", domain_name
,
132 domain
->native_mode
? "native" : "mixed (or NT4)" ));
134 /* Link to domain list */
135 DLIST_ADD(_domain_list
, domain
);
137 DEBUG(1,("Added domain %s %s %s\n",
138 domain
->name
, domain
->alt_name
,
139 sid
?sid_string_static(&domain
->sid
):""));
146 rescan our domains looking for new trusted domains
148 void rescan_trusted_domains(BOOL force
)
150 struct winbindd_domain
*domain
;
152 static time_t last_scan
;
153 time_t t
= time(NULL
);
155 /* trusted domains might be disabled */
156 if (!lp_allow_trusted_domains()) {
160 /* Only rescan every few minutes but force if necessary */
162 if (((unsigned)(t
- last_scan
) < WINBINDD_RESCAN_FREQ
) && !force
)
167 DEBUG(1, ("scanning trusted domain list\n"));
169 if (!(mem_ctx
= talloc_init("init_domain_list")))
172 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
180 result
= domain
->methods
->trusted_domains(domain
, mem_ctx
, &num_domains
,
181 &names
, &alt_names
, &dom_sids
);
182 if (!NT_STATUS_IS_OK(result
)) {
186 /* Add each domain to the trusted domain list. Each domain inherits
187 the access methods of its parent */
188 for(i
= 0; i
< num_domains
; i
++) {
189 DEBUG(10,("Found domain %s\n", names
[i
]));
190 add_trusted_domain(names
[i
], alt_names
?alt_names
[i
]:NULL
,
191 domain
->methods
, &dom_sids
[i
]);
193 /* store trusted domain in the cache */
194 trustdom_cache_store(names
[i
], alt_names
? alt_names
[i
] : NULL
,
195 &dom_sids
[i
], t
+ WINBINDD_RESCAN_FREQ
);
199 talloc_destroy(mem_ctx
);
202 /* Look up global info for the winbind daemon */
203 BOOL
init_domain_list(void)
205 extern struct winbindd_methods cache_methods
;
206 struct winbindd_domain
*domain
;
208 /* Free existing list */
211 /* Add ourselves as the first entry */
212 domain
= add_trusted_domain(lp_workgroup(), NULL
, &cache_methods
, NULL
);
213 if (!secrets_fetch_domain_sid(domain
->name
, &domain
->sid
)) {
214 DEBUG(1, ("Could not fetch sid for our domain %s\n",
219 /* get any alternate name for the primary domain */
220 cache_methods
.alternate_name(domain
);
222 /* do an initial scan for trusted domains */
223 rescan_trusted_domains(True
);
228 /* Given a domain name, return the struct winbindd domain info for it
229 if it is actually working. */
231 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
233 struct winbindd_domain
*domain
;
235 /* Search through list */
237 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
238 if (strequal(domain_name
, domain
->name
) ||
239 (domain
->alt_name
[0] && strequal(domain_name
, domain
->alt_name
)))
248 /* Given a domain sid, return the struct winbindd domain info for it */
250 struct winbindd_domain
*find_domain_from_sid(DOM_SID
*sid
)
252 struct winbindd_domain
*domain
;
254 /* Search through list */
256 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
257 if (sid_compare_domain(sid
, &domain
->sid
) == 0)
266 /* Lookup a sid in a domain from a name */
268 BOOL
winbindd_lookup_sid_by_name(struct winbindd_domain
*domain
,
269 const char *name
, DOM_SID
*sid
,
270 enum SID_NAME_USE
*type
)
274 /* Don't bother with machine accounts */
276 if (name
[strlen(name
) - 1] == '$')
279 mem_ctx
= talloc_init("lookup_sid_by_name for %s\n", name
);
284 result
= domain
->methods
->name_to_sid(domain
, mem_ctx
, name
, sid
, type
);
286 talloc_destroy(mem_ctx
);
288 /* Return rid and type if lookup successful */
289 if (!NT_STATUS_IS_OK(result
)) {
290 *type
= SID_NAME_UNKNOWN
;
293 return NT_STATUS_IS_OK(result
);
297 * @brief Lookup a name in a domain from a sid.
299 * @param sid Security ID you want to look up.
301 * @param name On success, set to the name corresponding to @p sid.
303 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
305 * @param type On success, contains the type of name: alias, group or
308 * @retval True if the name exists, in which case @p name and @p type
309 * are set, otherwise False.
311 BOOL
winbindd_lookup_name_by_sid(DOM_SID
*sid
,
314 enum SID_NAME_USE
*type
)
320 struct winbindd_domain
*domain
;
322 domain
= find_domain_from_sid(sid
);
325 DEBUG(1,("Can't find domain from sid\n"));
331 if (!(mem_ctx
= talloc_init("winbindd_lookup_name_by_sid")))
334 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
, &names
, type
);
336 /* Return name and type if successful */
338 if ((rv
= NT_STATUS_IS_OK(result
))) {
339 fstrcpy(dom_name
, domain
->name
);
340 fstrcpy(name
, names
);
342 *type
= SID_NAME_UNKNOWN
;
343 fstrcpy(name
, name_deadbeef
);
346 talloc_destroy(mem_ctx
);
352 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
354 void free_getent_state(struct getent_state
*state
)
356 struct getent_state
*temp
;
358 /* Iterate over state list */
362 while(temp
!= NULL
) {
363 struct getent_state
*next
;
365 /* Free sam entries then list entry */
367 SAFE_FREE(state
->sam_entries
);
368 DLIST_REMOVE(state
, state
);
376 /* Parse winbindd related parameters */
378 BOOL
winbindd_param_init(void)
380 /* Parse winbind uid and winbind_gid parameters */
382 if (!lp_idmap_uid(&server_state
.uid_low
, &server_state
.uid_high
)) {
383 DEBUG(0, ("idmap uid range missing or invalid\n"));
387 if (!lp_idmap_gid(&server_state
.gid_low
, &server_state
.gid_high
)) {
388 DEBUG(0, ("idmap gid range missing or invalid\n"));
395 /* Check if a domain is present in a comma-separated list of domains */
397 BOOL
check_domain_env(char *domain_env
, char *domain
)
400 const char *tmp
= domain_env
;
402 while(next_token(&tmp
, name
, ",", sizeof(fstring
))) {
403 if (strequal(name
, domain
))
410 /* Parse a string of the form DOMAIN/user into a domain and a user */
412 BOOL
parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
414 char *p
= strchr(domuser
,*lp_winbind_separator());
416 if (!(p
|| lp_winbind_use_default_domain()))
419 if(!p
&& lp_winbind_use_default_domain()) {
420 fstrcpy(user
, domuser
);
421 fstrcpy(domain
, lp_workgroup());
424 fstrcpy(domain
, domuser
);
425 domain
[PTR_DIFF(p
, domuser
)] = 0;
432 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
433 'winbind separator' options.
435 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
439 void fill_domain_username(fstring name
, const char *domain
, const char *user
)
441 if(lp_winbind_use_default_domain() &&
442 !strcmp(lp_workgroup(), domain
)) {
443 strlcpy(name
, user
, sizeof(fstring
));
445 slprintf(name
, sizeof(fstring
) - 1, "%s%s%s",
446 domain
, lp_winbind_separator(),
452 * Winbindd socket accessor functions
455 char *get_winbind_priv_pipe_dir(void)
457 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR
);
460 /* Open the winbindd socket */
462 static int _winbindd_socket
= -1;
463 static int _winbindd_priv_socket
= -1;
465 int open_winbindd_socket(void)
467 if (_winbindd_socket
== -1) {
468 _winbindd_socket
= create_pipe_sock(
469 WINBINDD_SOCKET_DIR
, WINBINDD_SOCKET_NAME
, 0755);
470 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
474 return _winbindd_socket
;
477 int open_winbindd_priv_socket(void)
479 if (_winbindd_priv_socket
== -1) {
480 _winbindd_priv_socket
= create_pipe_sock(
481 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME
, 0750);
482 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
483 _winbindd_priv_socket
));
486 return _winbindd_priv_socket
;
489 /* Close the winbindd socket */
491 void close_winbindd_socket(void)
493 if (_winbindd_socket
!= -1) {
494 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
496 close(_winbindd_socket
);
497 _winbindd_socket
= -1;
499 if (_winbindd_priv_socket
!= -1) {
500 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
501 _winbindd_priv_socket
));
502 close(_winbindd_priv_socket
);
503 _winbindd_priv_socket
= -1;
508 * Client list accessor functions
511 static struct winbindd_cli_state
*_client_list
;
512 static int _num_clients
;
514 /* Return list of all connected clients */
516 struct winbindd_cli_state
*winbindd_client_list(void)
521 /* Add a connection to the list */
523 void winbindd_add_client(struct winbindd_cli_state
*cli
)
525 DLIST_ADD(_client_list
, cli
);
529 /* Remove a client from the list */
531 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
533 DLIST_REMOVE(_client_list
, cli
);
537 /* Close all open clients */
539 void winbindd_kill_all_clients(void)
541 struct winbindd_cli_state
*cl
= winbindd_client_list();
543 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
546 struct winbindd_cli_state
*next
;
549 winbindd_remove_client(cl
);
554 /* Return number of open clients */
556 int winbindd_num_clients(void)
561 /* Help with RID -> SID conversion */
563 DOM_SID
*rid_to_talloced_sid(struct winbindd_domain
*domain
,
568 sid
= talloc(mem_ctx
, sizeof(*sid
));
570 smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n");
572 sid_copy(sid
, &domain
->sid
);
573 sid_append_rid(sid
, rid
);