xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_domain.c (revision 6537f381d2d9e7b4e2f7b29c3e7a3f13be036f2e)
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 2008 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/smb_sid.h>
43 
44 #include <smbsrv/libsmb.h>
45 
46 
47 static void nt_domain_unlist(nt_domain_t *);
48 
49 /*
50  * Valid domain type identifiers as text. This table must be kept
51  * in step with the nt_domain_type_t enum in ntdomain.h.
52  */
53 static char *nt_domain_type_name[NT_DOMAIN_NUM_TYPES] = {
54 	"null",
55 	"builtin",
56 	"local",
57 	"primary",
58 	"account",
59 	"trusted",
60 	"untrusted"
61 };
62 
63 
64 static rwlock_t		nt_domain_lock;
65 static nt_domain_t	*nt_domain_list;
66 
67 /*
68  * nt_domain_init
69  *
70  * NT domain database one time initialization. This function should
71  * be called during module installation.
72  *
73  * Returns 0 on successful domain initialization. Less than zero otherwise.
74  */
75 int
76 nt_domain_init(char *resource_domain, uint32_t secmode)
77 {
78 	nt_domain_t *domain;
79 	smb_sid_t *sid = NULL;
80 	char sidstr[128];
81 	char *lsidstr;
82 	char hostname[MAXHOSTNAMELEN];
83 	int rc;
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 = smb_sid_fromstr(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 ((sid = smb_sid_fromstr(NT_BUILTIN_DOMAIN_SIDSTR)) != NULL) {
110 		domain = nt_domain_new(NT_DOMAIN_BUILTIN, "BUILTIN", sid);
111 		(void) nt_domain_add(domain);
112 		free(sid);
113 	}
114 
115 	if (secmode == SMB_SECMODE_DOMAIN) {
116 		rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr,
117 		    sizeof (sidstr));
118 		sid = (rc == SMBD_SMF_OK) ? smb_sid_fromstr(sidstr) : NULL;
119 		if (smb_sid_isvalid(sid)) {
120 			domain = nt_domain_new(NT_DOMAIN_PRIMARY,
121 			    resource_domain, sid);
122 			(void) nt_domain_add(domain);
123 			free(sid);
124 		} else {
125 			free(sid);
126 			(void) rwlock_destroy(&nt_domain_lock);
127 			return (SMB_DOMAIN_NODOMAIN_SID);
128 		}
129 
130 	}
131 
132 	return (0);
133 }
134 
135 /*
136  * nt_domain_new
137  *
138  * Allocate and initialize a new domain structure. On success, a pointer to
139  * the new domain structure is returned. Otherwise a null pointer is returned.
140  */
141 nt_domain_t *
142 nt_domain_new(nt_domain_type_t type, char *name, smb_sid_t *sid)
143 {
144 	nt_domain_t *new_domain;
145 
146 	if ((name == NULL) || (sid == NULL))
147 		return (NULL);
148 
149 	if (type == NT_DOMAIN_NULL || type >= NT_DOMAIN_NUM_TYPES)
150 		return (NULL);
151 
152 	if ((new_domain = malloc(sizeof (nt_domain_t))) == NULL)
153 		return (NULL);
154 
155 	bzero(new_domain, sizeof (nt_domain_t));
156 	new_domain->type = type;
157 	new_domain->name = strdup(name);
158 	new_domain->sid = smb_sid_dup(sid);
159 
160 	return (new_domain);
161 }
162 
163 /*
164  * nt_domain_delete
165  *
166  * Free the memory used by the specified domain structure.
167  */
168 void
169 nt_domain_delete(nt_domain_t *domain)
170 {
171 	if (domain) {
172 		free(domain->name);
173 		free(domain->sid);
174 		free(domain);
175 	}
176 }
177 
178 
179 /*
180  * nt_domain_add
181  *
182  * Add a domain structure to the global list. There is no checking
183  * for duplicates. If it's the primary domain, we save the SID in the
184  * environment. Returns a pointer to the new domain entry on success.
185  * Otherwise a null pointer is returned.
186  */
187 nt_domain_t *
188 nt_domain_add(nt_domain_t *new_domain)
189 {
190 	char sidstr[SMB_SID_STRSZ];
191 
192 	if (new_domain == NULL)
193 		return (NULL);
194 
195 	(void) rw_wrlock(&nt_domain_lock);
196 
197 	new_domain->next = nt_domain_list;
198 	nt_domain_list = new_domain;
199 
200 	if (new_domain->type == NT_DOMAIN_PRIMARY) {
201 		smb_sid_tostr(new_domain->sid, sidstr);
202 		(void) smb_config_setstr(SMB_CI_DOMAIN_SID, sidstr);
203 	}
204 	(void) rw_unlock(&nt_domain_lock);
205 
206 	return (new_domain);
207 }
208 
209 
210 /*
211  * nt_domain_remove
212  *
213  * Remove a domain from the global list. The memory
214  * used by the structure is not freed.
215  */
216 void
217 nt_domain_remove(nt_domain_t *domain)
218 {
219 	(void) rw_wrlock(&nt_domain_lock);
220 	nt_domain_unlist(domain);
221 	(void) rw_unlock(&nt_domain_lock);
222 }
223 
224 
225 /*
226  * nt_domain_flush
227  *
228  * Flush all domains of the specified type from the list. This is
229  * useful for things like updating the list of trusted domains.
230  */
231 void
232 nt_domain_flush(nt_domain_type_t domain_type)
233 {
234 	nt_domain_t *domain = nt_domain_list;
235 
236 	(void) rw_wrlock(&nt_domain_lock);
237 	while (domain) {
238 		if (domain->type == domain_type) {
239 			nt_domain_unlist(domain);
240 			nt_domain_delete(domain);
241 			domain = nt_domain_list;
242 			continue;
243 		}
244 		domain = domain->next;
245 	}
246 	(void) rw_unlock(&nt_domain_lock);
247 }
248 
249 /*
250  * nt_domain_xlat_type
251  *
252  * Translate a domain type into a text string.
253  */
254 char *
255 nt_domain_xlat_type(nt_domain_type_t domain_type)
256 {
257 	if (domain_type < NT_DOMAIN_NUM_TYPES)
258 		return (nt_domain_type_name[domain_type]);
259 	else
260 		return ("unknown");
261 }
262 
263 
264 /*
265  * nt_domain_xlat_type_name
266  *
267  * Translate a domain type test string into a domain type.
268  */
269 nt_domain_type_t
270 nt_domain_xlat_type_name(char *type_name)
271 {
272 	int i;
273 
274 	for (i = 0; i < NT_DOMAIN_NUM_TYPES; ++i)
275 		if (utf8_strcasecmp(nt_domain_type_name[i], type_name) == 0)
276 			return (i);
277 
278 	return (NT_DOMAIN_NUM_TYPES);
279 }
280 
281 
282 /*
283  * nt_domain_lookup_name
284  *
285  * Lookup a domain by its domain name. If the domain is in the list,
286  * a pointer to it is returned. Otherwise a null pointer is returned.
287  */
288 nt_domain_t *
289 nt_domain_lookup_name(char *domain_name)
290 {
291 	nt_domain_t *domain = nt_domain_list;
292 
293 	(void) rw_rdlock(&nt_domain_lock);
294 	while (domain) {
295 		if (utf8_strcasecmp(domain->name, domain_name) == 0)
296 			break;
297 
298 		domain = domain->next;
299 	}
300 	(void) rw_unlock(&nt_domain_lock);
301 
302 	return (domain);
303 }
304 
305 
306 /*
307  * nt_domain_lookup_sid
308  *
309  * Lookup a domain by its domain SID. If the domain is in the list,
310  * a pointer to it is returned. Otherwise a null pointer is returned.
311  */
312 nt_domain_t *
313 nt_domain_lookup_sid(smb_sid_t *domain_sid)
314 {
315 	nt_domain_t *domain = nt_domain_list;
316 
317 	(void) rw_rdlock(&nt_domain_lock);
318 	while (domain) {
319 		if (smb_sid_cmp(domain->sid, domain_sid))
320 			break;
321 
322 		domain = domain->next;
323 	}
324 	(void) rw_unlock(&nt_domain_lock);
325 
326 	return (domain);
327 }
328 
329 
330 /*
331  * nt_domain_lookupbytype
332  *
333  * Lookup a domain by its type. The first matching entry in the list
334  * is returned. Otherwise a null pointer is returned.
335  */
336 nt_domain_t *
337 nt_domain_lookupbytype(nt_domain_type_t type)
338 {
339 	nt_domain_t *domain = nt_domain_list;
340 
341 	(void) rw_rdlock(&nt_domain_lock);
342 	while (domain) {
343 		if (domain->type == type)
344 			break;
345 
346 		domain = domain->next;
347 	}
348 	(void) rw_unlock(&nt_domain_lock);
349 
350 	return (domain);
351 }
352 
353 
354 /*
355  * nt_domain_local_sid
356  *
357  * Return a pointer to the local domain SID. Each system has a SID that
358  * represents the local domain, which is named after the local hostname.
359  * The local domain SID must exist.
360  */
361 smb_sid_t *
362 nt_domain_local_sid(void)
363 {
364 	nt_domain_t *domain = nt_domain_list;
365 
366 	(void) rw_rdlock(&nt_domain_lock);
367 	while (domain) {
368 		if (domain->type == NT_DOMAIN_LOCAL)
369 			break;
370 
371 		domain = domain->next;
372 	}
373 	(void) rw_unlock(&nt_domain_lock);
374 
375 	return (domain->sid);
376 }
377 
378 
379 static void
380 nt_domain_unlist(nt_domain_t *domain)
381 {
382 	nt_domain_t **ppdomain = &nt_domain_list;
383 
384 	while (*ppdomain) {
385 		if (*ppdomain == domain) {
386 			*ppdomain = domain->next;
387 			domain->next = NULL;
388 			return;
389 		}
390 		ppdomain = &(*ppdomain)->next;
391 	}
392 }
393