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