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
);
76 /* Add a trusted domain to our list of domains */
77 static struct winbindd_domain
*add_trusted_domain(const char *domain_name
, const char *alt_name
,
78 struct winbindd_methods
*methods
,
81 struct winbindd_domain
*domain
;
83 /* We can't call domain_list() as this function is called from
84 init_domain_list() and we'll get stuck in a loop. */
85 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
86 if (strcasecmp(domain_name
, domain
->name
) == 0 ||
87 strcasecmp(domain_name
, domain
->alt_name
) == 0) {
90 if (alt_name
&& *alt_name
) {
91 if (strcasecmp(alt_name
, domain
->name
) == 0 ||
92 strcasecmp(alt_name
, domain
->alt_name
) == 0) {
98 /* Create new domain entry */
100 if ((domain
= (struct winbindd_domain
*)
101 malloc(sizeof(*domain
))) == NULL
)
106 ZERO_STRUCTP(domain
);
108 /* prioritise the short name */
109 if (strchr_m(domain_name
, '.') && alt_name
&& *alt_name
) {
110 fstrcpy(domain
->name
, alt_name
);
111 fstrcpy(domain
->alt_name
, domain_name
);
113 fstrcpy(domain
->name
, domain_name
);
115 fstrcpy(domain
->alt_name
, alt_name
);
119 domain
->methods
= methods
;
120 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
121 domain
->last_seq_check
= 0;
123 sid_copy(&domain
->sid
, sid
);
126 /* Link to domain list */
127 DLIST_ADD(_domain_list
, domain
);
129 DEBUG(1,("Added domain %s %s %s\n",
130 domain
->name
, domain
->alt_name
,
131 sid
?sid_string_static(&domain
->sid
):""));
138 rescan our domains looking for new trusted domains
140 void rescan_trusted_domains(void)
142 struct winbindd_domain
*domain
;
144 static time_t last_scan
;
145 time_t t
= time(NULL
);
147 /* ony rescan every few minutes */
148 if ((unsigned)(t
- last_scan
) < WINBINDD_RESCAN_FREQ
) {
151 last_scan
= time(NULL
);
153 DEBUG(1, ("scanning trusted domain list\n"));
155 if (!(mem_ctx
= talloc_init_named("init_domain_list")))
158 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
166 result
= domain
->methods
->trusted_domains(domain
, mem_ctx
, &num_domains
,
167 &names
, &alt_names
, &dom_sids
);
168 if (!NT_STATUS_IS_OK(result
)) {
172 /* Add each domain to the trusted domain list. Each domain inherits
173 the access methods of its parent */
174 for(i
= 0; i
< num_domains
; i
++) {
175 DEBUG(10,("Found domain %s\n", names
[i
]));
176 add_trusted_domain(names
[i
],
177 alt_names
?alt_names
[i
]:NULL
,
178 domain
->methods
, &dom_sids
[i
]);
182 talloc_destroy(mem_ctx
);
185 /* Look up global info for the winbind daemon */
186 BOOL
init_domain_list(void)
189 extern struct winbindd_methods cache_methods
;
190 struct winbindd_domain
*domain
;
192 /* Free existing list */
195 /* Add ourselves as the first entry */
196 domain
= add_trusted_domain(lp_workgroup(), NULL
, &cache_methods
, NULL
);
198 /* Now we *must* get the domain sid for our primary domain. Go into
199 a holding pattern until that is available */
201 result
= cache_methods
.domain_sid(domain
, &domain
->sid
);
202 while (!NT_STATUS_IS_OK(result
)) {
204 DEBUG(1,("Retrying startup domain sid fetch for %s\n",
206 result
= cache_methods
.domain_sid(domain
, &domain
->sid
);
209 /* get any alternate name for the primary domain */
210 cache_methods
.alternate_name(domain
);
212 /* do an initial scan for trusted domains */
213 rescan_trusted_domains();
218 /* Given a domain name, return the struct winbindd domain info for it
219 if it is actually working. */
221 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
223 struct winbindd_domain
*domain
;
225 /* Search through list */
227 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
228 if (strequal(domain_name
, domain
->name
) ||
229 (domain
->alt_name
[0] && strequal(domain_name
, domain
->alt_name
)))
238 /* Given a domain sid, return the struct winbindd domain info for it */
240 struct winbindd_domain
*find_domain_from_sid(DOM_SID
*sid
)
242 struct winbindd_domain
*domain
;
244 /* Search through list */
246 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
247 if (sid_compare_domain(sid
, &domain
->sid
) == 0)
256 /* Lookup a sid in a domain from a name */
258 BOOL
winbindd_lookup_sid_by_name(struct winbindd_domain
*domain
,
259 const char *name
, DOM_SID
*sid
,
260 enum SID_NAME_USE
*type
)
264 /* Don't bother with machine accounts */
266 if (name
[strlen(name
) - 1] == '$')
270 result
= domain
->methods
->name_to_sid(domain
, name
, sid
, type
);
272 /* Return rid and type if lookup successful */
273 if (!NT_STATUS_IS_OK(result
)) {
274 *type
= SID_NAME_UNKNOWN
;
277 return NT_STATUS_IS_OK(result
);
281 * @brief Lookup a name in a domain from a sid.
283 * @param sid Security ID you want to look up.
285 * @param name On success, set to the name corresponding to @p sid.
287 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
289 * @param type On success, contains the type of name: alias, group or
292 * @retval True if the name exists, in which case @p name and @p type
293 * are set, otherwise False.
295 BOOL
winbindd_lookup_name_by_sid(DOM_SID
*sid
,
298 enum SID_NAME_USE
*type
)
304 struct winbindd_domain
*domain
;
306 domain
= find_domain_from_sid(sid
);
309 DEBUG(1,("Can't find domain from sid\n"));
315 if (!(mem_ctx
= talloc_init_named("winbindd_lookup_name_by_sid")))
318 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
, &names
, type
);
320 /* Return name and type if successful */
322 if ((rv
= NT_STATUS_IS_OK(result
))) {
323 fstrcpy(dom_name
, domain
->name
);
324 fstrcpy(name
, names
);
326 *type
= SID_NAME_UNKNOWN
;
327 fstrcpy(name
, name_deadbeef
);
330 talloc_destroy(mem_ctx
);
336 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
338 void free_getent_state(struct getent_state
*state
)
340 struct getent_state
*temp
;
342 /* Iterate over state list */
346 while(temp
!= NULL
) {
347 struct getent_state
*next
;
349 /* Free sam entries then list entry */
351 SAFE_FREE(state
->sam_entries
);
352 DLIST_REMOVE(state
, state
);
360 /* Initialise trusted domain info */
362 BOOL
winbindd_param_init(void)
364 /* Parse winbind uid and winbind_gid parameters */
366 if (!lp_winbind_uid(&server_state
.uid_low
, &server_state
.uid_high
)) {
367 DEBUG(0, ("winbind uid range missing or invalid\n"));
371 if (!lp_winbind_gid(&server_state
.gid_low
, &server_state
.gid_high
)) {
372 DEBUG(0, ("winbind gid range missing or invalid\n"));
379 /* Check if a domain is present in a comma-separated list of domains */
381 BOOL
check_domain_env(char *domain_env
, char *domain
)
384 char *tmp
= domain_env
;
386 while(next_token(&tmp
, name
, ",", sizeof(fstring
))) {
387 if (strequal(name
, domain
))
394 /* Parse a string of the form DOMAIN/user into a domain and a user */
395 extern fstring global_myworkgroup
;
397 BOOL
parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
399 char *p
= strchr(domuser
,*lp_winbind_separator());
401 if (!(p
|| lp_winbind_use_default_domain()))
404 if(!p
&& lp_winbind_use_default_domain()) {
405 fstrcpy(user
, domuser
);
406 fstrcpy(domain
, global_myworkgroup
);
409 fstrcpy(domain
, domuser
);
410 domain
[PTR_DIFF(p
, domuser
)] = 0;
417 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
418 'winbind separator' options.
420 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
424 void fill_domain_username(fstring name
, const char *domain
, const char *user
)
426 if(lp_winbind_use_default_domain() &&
427 !strcmp(global_myworkgroup
, domain
)) {
428 strlcpy(name
, user
, sizeof(fstring
));
430 slprintf(name
, sizeof(fstring
) - 1, "%s%s%s",
431 domain
, lp_winbind_separator(),