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
->sequence_number
= DOM_SEQUENCE_NONE
;
122 domain
->last_seq_check
= 0;
124 sid_copy(&domain
->sid
, sid
);
127 /* see if this is a native mode win2k domain, but only for our own domain */
129 if ( strequal( lp_workgroup(), domain_name
) ) {
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" ));
135 /* Link to domain list */
136 DLIST_ADD(_domain_list
, domain
);
138 DEBUG(1,("Added domain %s %s %s\n",
139 domain
->name
, domain
->alt_name
,
140 sid
?sid_string_static(&domain
->sid
):""));
147 rescan our domains looking for new trusted domains
149 void rescan_trusted_domains(BOOL force
)
151 struct winbindd_domain
*domain
;
153 static time_t last_scan
;
154 time_t t
= time(NULL
);
156 /* trusted domains might be disabled */
157 if (!lp_allow_trusted_domains()) {
161 /* Only rescan every few minutes but force if necessary */
163 if (((unsigned)(t
- last_scan
) < WINBINDD_RESCAN_FREQ
) && !force
)
168 DEBUG(1, ("scanning trusted domain list\n"));
170 if (!(mem_ctx
= talloc_init("init_domain_list")))
173 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
181 result
= domain
->methods
->trusted_domains(domain
, mem_ctx
, &num_domains
,
182 &names
, &alt_names
, &dom_sids
);
183 if (!NT_STATUS_IS_OK(result
)) {
187 /* Add each domain to the trusted domain list. Each domain inherits
188 the access methods of its parent */
189 for(i
= 0; i
< num_domains
; i
++) {
190 DEBUG(10,("Found domain %s\n", names
[i
]));
191 add_trusted_domain(names
[i
], alt_names
?alt_names
[i
]:NULL
,
192 domain
->methods
, &dom_sids
[i
]);
194 /* store trusted domain in the cache */
195 trustdom_cache_store(mem_ctx
, names
[i
], alt_names
? alt_names
[i
] : NULL
,
196 &dom_sids
[i
], t
+ WINBINDD_RESCAN_FREQ
);
200 talloc_destroy(mem_ctx
);
203 /* Look up global info for the winbind daemon */
204 BOOL
init_domain_list(void)
206 extern struct winbindd_methods cache_methods
;
207 struct winbindd_domain
*domain
;
209 /* Free existing list */
212 /* Add ourselves as the first entry */
213 domain
= add_trusted_domain(lp_workgroup(), NULL
, &cache_methods
, NULL
);
214 if (!secrets_fetch_domain_sid(domain
->name
, &domain
->sid
)) {
215 DEBUG(1, ("Could not fetch sid for our domain %s\n",
220 /* get any alternate name for the primary domain */
221 cache_methods
.alternate_name(domain
);
223 /* do an initial scan for trusted domains */
224 rescan_trusted_domains(True
);
229 /* Given a domain name, return the struct winbindd domain info for it
230 if it is actually working. */
232 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
234 struct winbindd_domain
*domain
;
236 /* Search through list */
238 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
239 if (strequal(domain_name
, domain
->name
) ||
240 (domain
->alt_name
[0] && strequal(domain_name
, domain
->alt_name
)))
249 /* Given a domain sid, return the struct winbindd domain info for it */
251 struct winbindd_domain
*find_domain_from_sid(DOM_SID
*sid
)
253 struct winbindd_domain
*domain
;
255 /* Search through list */
257 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
258 if (sid_compare_domain(sid
, &domain
->sid
) == 0)
267 /* Lookup a sid in a domain from a name */
269 BOOL
winbindd_lookup_sid_by_name(struct winbindd_domain
*domain
,
270 const char *name
, DOM_SID
*sid
,
271 enum SID_NAME_USE
*type
)
275 /* Don't bother with machine accounts */
277 if (name
[strlen(name
) - 1] == '$')
280 mem_ctx
= talloc_init("lookup_sid_by_name for %s\n", name
);
285 result
= domain
->methods
->name_to_sid(domain
, mem_ctx
, name
, sid
, type
);
287 talloc_destroy(mem_ctx
);
289 /* Return rid and type if lookup successful */
290 if (!NT_STATUS_IS_OK(result
)) {
291 *type
= SID_NAME_UNKNOWN
;
294 return NT_STATUS_IS_OK(result
);
298 * @brief Lookup a name in a domain from a sid.
300 * @param sid Security ID you want to look up.
302 * @param name On success, set to the name corresponding to @p sid.
304 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
306 * @param type On success, contains the type of name: alias, group or
309 * @retval True if the name exists, in which case @p name and @p type
310 * are set, otherwise False.
312 BOOL
winbindd_lookup_name_by_sid(DOM_SID
*sid
,
315 enum SID_NAME_USE
*type
)
321 struct winbindd_domain
*domain
;
323 domain
= find_domain_from_sid(sid
);
326 DEBUG(1,("Can't find domain from sid\n"));
332 if (!(mem_ctx
= talloc_init("winbindd_lookup_name_by_sid")))
335 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
, &names
, type
);
337 /* Return name and type if successful */
339 if ((rv
= NT_STATUS_IS_OK(result
))) {
340 fstrcpy(dom_name
, domain
->name
);
341 fstrcpy(name
, names
);
343 *type
= SID_NAME_UNKNOWN
;
344 fstrcpy(name
, name_deadbeef
);
347 talloc_destroy(mem_ctx
);
353 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
355 void free_getent_state(struct getent_state
*state
)
357 struct getent_state
*temp
;
359 /* Iterate over state list */
363 while(temp
!= NULL
) {
364 struct getent_state
*next
;
366 /* Free sam entries then list entry */
368 SAFE_FREE(state
->sam_entries
);
369 DLIST_REMOVE(state
, state
);
377 /* Parse winbindd related parameters */
379 BOOL
winbindd_param_init(void)
381 /* Parse winbind uid and winbind_gid parameters */
383 if (!lp_winbind_uid(&server_state
.uid_low
, &server_state
.uid_high
)) {
384 DEBUG(0, ("winbind uid range missing or invalid\n"));
388 if (!lp_winbind_gid(&server_state
.gid_low
, &server_state
.gid_high
)) {
389 DEBUG(0, ("winbind gid range missing or invalid\n"));
396 /* Check if a domain is present in a comma-separated list of domains */
398 BOOL
check_domain_env(char *domain_env
, char *domain
)
401 const char *tmp
= domain_env
;
403 while(next_token(&tmp
, name
, ",", sizeof(fstring
))) {
404 if (strequal(name
, domain
))
411 /* Parse a string of the form DOMAIN/user into a domain and a user */
413 BOOL
parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
415 char *p
= strchr(domuser
,*lp_winbind_separator());
417 if (!(p
|| lp_winbind_use_default_domain()))
420 if(!p
&& lp_winbind_use_default_domain()) {
421 fstrcpy(user
, domuser
);
422 fstrcpy(domain
, lp_workgroup());
425 fstrcpy(domain
, domuser
);
426 domain
[PTR_DIFF(p
, domuser
)] = 0;
433 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
434 'winbind separator' options.
436 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
440 void fill_domain_username(fstring name
, const char *domain
, const char *user
)
442 if(lp_winbind_use_default_domain() &&
443 !strcmp(lp_workgroup(), domain
)) {
444 strlcpy(name
, user
, sizeof(fstring
));
446 slprintf(name
, sizeof(fstring
) - 1, "%s%s%s",
447 domain
, lp_winbind_separator(),
453 * Winbindd socket accessor functions
456 /* Open the winbindd socket */
458 static int _winbindd_socket
= -1;
460 int open_winbindd_socket(void)
462 if (_winbindd_socket
== -1) {
463 _winbindd_socket
= create_pipe_sock(
464 WINBINDD_SOCKET_DIR
, WINBINDD_SOCKET_NAME
, 0755);
465 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
469 return _winbindd_socket
;
472 /* Close the winbindd socket */
474 void close_winbindd_socket(void)
476 if (_winbindd_socket
!= -1) {
477 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
479 close(_winbindd_socket
);
480 _winbindd_socket
= -1;
485 * Client list accessor functions
488 static struct winbindd_cli_state
*_client_list
;
489 static int _num_clients
;
491 /* Return list of all connected clients */
493 struct winbindd_cli_state
*winbindd_client_list(void)
498 /* Add a connection to the list */
500 void winbindd_add_client(struct winbindd_cli_state
*cli
)
502 DLIST_ADD(_client_list
, cli
);
506 /* Remove a client from the list */
508 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
510 DLIST_REMOVE(_client_list
, cli
);
514 /* Close all open clients */
516 void winbindd_kill_all_clients(void)
518 struct winbindd_cli_state
*cl
= winbindd_client_list();
520 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
523 struct winbindd_cli_state
*next
;
526 winbindd_remove_client(cl
);
531 /* Return number of open clients */
533 int winbindd_num_clients(void)
538 /* Help with RID -> SID conversion */
540 DOM_SID
*rid_to_talloced_sid(struct winbindd_domain
*domain
,
545 sid
= talloc(mem_ctx
, sizeof(*sid
));
547 smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n");
549 sid_copy(sid
, &domain
->sid
);
550 sid_append_rid(sid
, rid
);