xref: /titanic_50/usr/src/lib/smbsrv/libsmb/common/smb_domain.c (revision b9bc7f7832704fda46b4d6b04f3f7be1227dc644)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This file defines the NT domain environment values and the domain
30  * database interface. The database is a single linked list of
31  * structures containing domain type, name and SID information.
32  */
33 
34 #include <strings.h>
35 #include <unistd.h>
36 #include <netdb.h>
37 #include <syslog.h>
38 #include <synch.h>
39 
40 #include <smbsrv/smbinfo.h>
41 #include <smbsrv/string.h>
42 #include <smbsrv/ntsid.h>
43 #include <smbsrv/alloc.h>
44 
45 #include <smbsrv/libsmb.h>
46 
47 
48 static void nt_domain_unlist(nt_domain_t *);
49 
50 /*
51  * Valid domain type identifiers as text. This table must be kept
52  * in step with the nt_domain_type_t enum in ntdomain.h.
53  */
54 static char *nt_domain_type_name[NT_DOMAIN_NUM_TYPES] = {
55 	"null",
56 	"builtin",
57 	"local",
58 	"primary",
59 	"account",
60 	"trusted",
61 	"untrusted"
62 };
63 
64 
65 static rwlock_t		nt_domain_lock;
66 static nt_domain_t	*nt_domain_list;
67 
68 /*
69  * nt_domain_init
70  *
71  * NT domain database one time initialization. This function should
72  * be called during module installation.
73  *
74  * Returns 0 on successful domain initialization. Less than zero otherwise.
75  */
76 int
77 nt_domain_init(char *resource_domain, uint32_t secmode)
78 {
79 	nt_domain_t *domain;
80 	nt_sid_t *sid;
81 	char *sidstr;
82 	char *lsidstr;
83 	char hostname[MAXHOSTNAMELEN];
84 
85 	if (rwlock_init(&nt_domain_lock, USYNC_THREAD, NULL))
86 		return (SMB_DOMAIN_NODOMAIN_SID);
87 
88 	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) {
89 		(void) rwlock_destroy(&nt_domain_lock);
90 		return (SMB_DOMAIN_NOMACHINE_SID);
91 	}
92 
93 	lsidstr = smb_config_get_localsid();
94 
95 	if (lsidstr) {
96 		sid = nt_sid_strtosid(lsidstr);
97 
98 		if (sid) {
99 			domain = nt_domain_new(NT_DOMAIN_LOCAL, hostname, sid);
100 			(void) nt_domain_add(domain);
101 			free(sid);
102 		}
103 		free(lsidstr);
104 	} else {
105 		(void) rwlock_destroy(&nt_domain_lock);
106 		return (SMB_DOMAIN_NOMACHINE_SID);
107 	}
108 
109 	if (secmode == SMB_SECMODE_DOMAIN) {
110 		sid = nt_sid_strtosid(NT_BUILTIN_DOMAIN_SIDSTR);
111 		domain = nt_domain_new(NT_DOMAIN_BUILTIN, "BUILTIN", sid);
112 		(void) nt_domain_add(domain);
113 		free(sid);
114 
115 		smb_config_rdlock();
116 		sidstr = smb_config_get(SMB_CI_DOMAIN_SID);
117 		if (sidstr) {
118 			sid = nt_sid_strtosid(sidstr);
119 			smb_config_unlock();
120 			domain = nt_domain_new(NT_DOMAIN_PRIMARY,
121 			    resource_domain, sid);
122 			(void) nt_domain_add(domain);
123 			free(sid);
124 		} else {
125 			smb_config_unlock();
126 			(void) rwlock_destroy(&nt_domain_lock);
127 			return (SMB_DOMAIN_NODOMAIN_SID);
128 		}
129 
130 	}
131 	return (0);
132 }
133 
134 /*
135  * nt_domain_new
136  *
137  * Allocate and initialize a new domain structure. On success, a pointer to
138  * the new domain structure is returned. Otherwise a null pointer is returned.
139  */
140 nt_domain_t *
141 nt_domain_new(nt_domain_type_t type, char *name, nt_sid_t *sid)
142 {
143 	nt_domain_t *new_domain;
144 
145 	if ((name == NULL) || (sid == NULL))
146 		return (NULL);
147 
148 	if (type == NT_DOMAIN_NULL || type >= NT_DOMAIN_NUM_TYPES)
149 		return (NULL);
150 
151 	if ((new_domain = malloc(sizeof (nt_domain_t))) == NULL)
152 		return (NULL);
153 
154 	bzero(new_domain, sizeof (nt_domain_t));
155 	new_domain->type = type;
156 	new_domain->name = strdup(name);
157 	new_domain->sid = nt_sid_dup(sid);
158 
159 	return (new_domain);
160 }
161 
162 /*
163  * nt_domain_delete
164  *
165  * Free the memory used by the specified domain structure.
166  */
167 void
168 nt_domain_delete(nt_domain_t *domain)
169 {
170 	if (domain) {
171 		free(domain->name);
172 		free(domain->sid);
173 		free(domain);
174 	}
175 }
176 
177 
178 /*
179  * nt_domain_add
180  *
181  * Add a domain structure to the global list. There is no checking
182  * for duplicates. If it's the primary domain, we save the SID in the
183  * environment. Returns a pointer to the new domain entry on success.
184  * Otherwise a null pointer is returned.
185  */
186 nt_domain_t *
187 nt_domain_add(nt_domain_t *new_domain)
188 {
189 	char *sidstr;
190 
191 	if (new_domain == NULL)
192 		return (NULL);
193 
194 	(void) rw_wrlock(&nt_domain_lock);
195 
196 	new_domain->next = nt_domain_list;
197 	nt_domain_list = new_domain;
198 
199 	if (new_domain->type == NT_DOMAIN_PRIMARY) {
200 		sidstr = nt_sid_format(new_domain->sid);
201 		smb_config_wrlock();
202 		(void) smb_config_set(SMB_CI_DOMAIN_SID, sidstr);
203 		smb_config_unlock();
204 		free(sidstr);
205 	}
206 	(void) rw_unlock(&nt_domain_lock);
207 
208 	return (new_domain);
209 }
210 
211 
212 /*
213  * nt_domain_remove
214  *
215  * Remove a domain from the global list. The memory
216  * used by the structure is not freed.
217  */
218 void
219 nt_domain_remove(nt_domain_t *domain)
220 {
221 	(void) rw_wrlock(&nt_domain_lock);
222 	nt_domain_unlist(domain);
223 	(void) rw_unlock(&nt_domain_lock);
224 }
225 
226 
227 /*
228  * nt_domain_flush
229  *
230  * Flush all domains of the specified type from the list. This is
231  * useful for things like updating the list of trusted domains.
232  */
233 void
234 nt_domain_flush(nt_domain_type_t domain_type)
235 {
236 	nt_domain_t *domain = nt_domain_list;
237 
238 	(void) rw_wrlock(&nt_domain_lock);
239 	while (domain) {
240 		if (domain->type == domain_type) {
241 			nt_domain_unlist(domain);
242 			nt_domain_delete(domain);
243 			domain = nt_domain_list;
244 			continue;
245 		}
246 		domain = domain->next;
247 	}
248 	(void) rw_unlock(&nt_domain_lock);
249 }
250 
251 /*
252  * nt_domain_xlat_type
253  *
254  * Translate a domain type into a text string.
255  */
256 char *
257 nt_domain_xlat_type(nt_domain_type_t domain_type)
258 {
259 	if (domain_type < NT_DOMAIN_NUM_TYPES)
260 		return (nt_domain_type_name[domain_type]);
261 	else
262 		return ("unknown");
263 }
264 
265 
266 /*
267  * nt_domain_xlat_type_name
268  *
269  * Translate a domain type test string into a domain type.
270  */
271 nt_domain_type_t
272 nt_domain_xlat_type_name(char *type_name)
273 {
274 	int i;
275 
276 	for (i = 0; i < NT_DOMAIN_NUM_TYPES; ++i)
277 		if (utf8_strcasecmp(nt_domain_type_name[i], type_name) == 0)
278 			return (i);
279 
280 	return (NT_DOMAIN_NUM_TYPES);
281 }
282 
283 
284 /*
285  * nt_domain_lookup_name
286  *
287  * Lookup a domain by its domain name. If the domain is in the list,
288  * a pointer to it is returned. Otherwise a null pointer is returned.
289  */
290 nt_domain_t *
291 nt_domain_lookup_name(char *domain_name)
292 {
293 	nt_domain_t *domain = nt_domain_list;
294 
295 	(void) rw_rdlock(&nt_domain_lock);
296 	while (domain) {
297 		if (utf8_strcasecmp(domain->name, domain_name) == 0)
298 			break;
299 
300 		domain = domain->next;
301 	}
302 	(void) rw_unlock(&nt_domain_lock);
303 
304 	return (domain);
305 }
306 
307 
308 /*
309  * nt_domain_lookup_sid
310  *
311  * Lookup a domain by its domain SID. If the domain is in the list,
312  * a pointer to it is returned. Otherwise a null pointer is returned.
313  */
314 nt_domain_t *
315 nt_domain_lookup_sid(nt_sid_t *domain_sid)
316 {
317 	nt_domain_t *domain = nt_domain_list;
318 
319 	(void) rw_rdlock(&nt_domain_lock);
320 	while (domain) {
321 		if (nt_sid_is_equal(domain->sid, domain_sid))
322 			break;
323 
324 		domain = domain->next;
325 	}
326 	(void) rw_unlock(&nt_domain_lock);
327 
328 	return (domain);
329 }
330 
331 
332 /*
333  * nt_domain_lookupbytype
334  *
335  * Lookup a domain by its type. The first matching entry in the list
336  * is returned. Otherwise a null pointer is returned.
337  */
338 nt_domain_t *
339 nt_domain_lookupbytype(nt_domain_type_t type)
340 {
341 	nt_domain_t *domain = nt_domain_list;
342 
343 	(void) rw_rdlock(&nt_domain_lock);
344 	while (domain) {
345 		if (domain->type == type)
346 			break;
347 
348 		domain = domain->next;
349 	}
350 	(void) rw_unlock(&nt_domain_lock);
351 
352 	return (domain);
353 }
354 
355 
356 /*
357  * nt_domain_local_sid
358  *
359  * Return a pointer to the local domain SID. Each system has a SID that
360  * represents the local domain, which is named after the local hostname.
361  * The local domain SID must exist.
362  */
363 nt_sid_t *
364 nt_domain_local_sid(void)
365 {
366 	nt_domain_t *domain = nt_domain_list;
367 
368 	(void) rw_rdlock(&nt_domain_lock);
369 	while (domain) {
370 		if (domain->type == NT_DOMAIN_LOCAL)
371 			break;
372 
373 		domain = domain->next;
374 	}
375 	(void) rw_unlock(&nt_domain_lock);
376 
377 	return (domain->sid);
378 }
379 
380 
381 static void
382 nt_domain_unlist(nt_domain_t *domain)
383 {
384 	nt_domain_t **ppdomain = &nt_domain_list;
385 
386 	while (*ppdomain) {
387 		if (*ppdomain == domain) {
388 			*ppdomain = domain->next;
389 			domain->next = NULL;
390 			return;
391 		}
392 		ppdomain = &(*ppdomain)->next;
393 	}
394 }
395