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/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 = NULL;
81 	char sidstr[128];
82 	char *lsidstr;
83 	char hostname[MAXHOSTNAMELEN];
84 	int rc;
85 
86 	if (rwlock_init(&nt_domain_lock, USYNC_THREAD, NULL))
87 		return (SMB_DOMAIN_NODOMAIN_SID);
88 
89 	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) {
90 		(void) rwlock_destroy(&nt_domain_lock);
91 		return (SMB_DOMAIN_NOMACHINE_SID);
92 	}
93 
94 	lsidstr = smb_config_get_localsid();
95 
96 	if (lsidstr) {
97 		sid = nt_sid_strtosid(lsidstr);
98 
99 		if (sid) {
100 			domain = nt_domain_new(NT_DOMAIN_LOCAL, hostname, sid);
101 			(void) nt_domain_add(domain);
102 			free(sid);
103 		}
104 		free(lsidstr);
105 	} else {
106 		(void) rwlock_destroy(&nt_domain_lock);
107 		return (SMB_DOMAIN_NOMACHINE_SID);
108 	}
109 
110 	if (secmode == SMB_SECMODE_DOMAIN) {
111 		sid = nt_sid_strtosid(NT_BUILTIN_DOMAIN_SIDSTR);
112 		domain = nt_domain_new(NT_DOMAIN_BUILTIN, "BUILTIN", sid);
113 		(void) nt_domain_add(domain);
114 		free(sid);
115 
116 		sid = NULL;
117 		rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr,
118 		    sizeof (sidstr));
119 		if (rc == SMBD_SMF_OK)
120 			sid = nt_sid_strtosid(sidstr);
121 		if (nt_sid_is_valid(sid)) {
122 			domain = nt_domain_new(NT_DOMAIN_PRIMARY,
123 			    resource_domain, sid);
124 			(void) nt_domain_add(domain);
125 			free(sid);
126 		} else {
127 			free(sid);
128 			(void) rwlock_destroy(&nt_domain_lock);
129 			return (SMB_DOMAIN_NODOMAIN_SID);
130 		}
131 
132 	}
133 	return (0);
134 }
135 
136 /*
137  * nt_domain_new
138  *
139  * Allocate and initialize a new domain structure. On success, a pointer to
140  * the new domain structure is returned. Otherwise a null pointer is returned.
141  */
142 nt_domain_t *
143 nt_domain_new(nt_domain_type_t type, char *name, nt_sid_t *sid)
144 {
145 	nt_domain_t *new_domain;
146 
147 	if ((name == NULL) || (sid == NULL))
148 		return (NULL);
149 
150 	if (type == NT_DOMAIN_NULL || type >= NT_DOMAIN_NUM_TYPES)
151 		return (NULL);
152 
153 	if ((new_domain = malloc(sizeof (nt_domain_t))) == NULL)
154 		return (NULL);
155 
156 	bzero(new_domain, sizeof (nt_domain_t));
157 	new_domain->type = type;
158 	new_domain->name = strdup(name);
159 	new_domain->sid = nt_sid_dup(sid);
160 
161 	return (new_domain);
162 }
163 
164 /*
165  * nt_domain_delete
166  *
167  * Free the memory used by the specified domain structure.
168  */
169 void
170 nt_domain_delete(nt_domain_t *domain)
171 {
172 	if (domain) {
173 		free(domain->name);
174 		free(domain->sid);
175 		free(domain);
176 	}
177 }
178 
179 
180 /*
181  * nt_domain_add
182  *
183  * Add a domain structure to the global list. There is no checking
184  * for duplicates. If it's the primary domain, we save the SID in the
185  * environment. Returns a pointer to the new domain entry on success.
186  * Otherwise a null pointer is returned.
187  */
188 nt_domain_t *
189 nt_domain_add(nt_domain_t *new_domain)
190 {
191 	char *sidstr;
192 
193 	if (new_domain == NULL)
194 		return (NULL);
195 
196 	(void) rw_wrlock(&nt_domain_lock);
197 
198 	new_domain->next = nt_domain_list;
199 	nt_domain_list = new_domain;
200 
201 	if (new_domain->type == NT_DOMAIN_PRIMARY) {
202 		sidstr = nt_sid_format(new_domain->sid);
203 		(void) smb_config_setstr(SMB_CI_DOMAIN_SID, sidstr);
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