xref: /titanic_52/usr/src/lib/smbsrv/libsmb/common/smb_info.c (revision 5763ba1e357fad1d57b5875c499307b7ea6e2cd4)
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 #include <sys/types.h>
29 #include <stdarg.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <synch.h>
34 #include <syslog.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <errno.h>
38 #include <net/if.h>
39 #include <netdb.h>
40 #include <sys/sockio.h>
41 #include <smbsrv/smbinfo.h>
42 #include <smbsrv/netbios.h>
43 #include <smbsrv/libsmb.h>
44 
45 static smb_ntdomain_t smbpdc_cache;
46 static mutex_t smbpdc_mtx;
47 static cond_t smbpdc_cv;
48 
49 extern int getdomainname(char *, int);
50 
51 uint32_t
52 smb_get_security_mode()
53 {
54 	uint32_t mode;
55 
56 	smb_config_rdlock();
57 	mode = smb_config_get_secmode();
58 	smb_config_unlock();
59 
60 	return (mode);
61 }
62 
63 /*
64  * smb_purge_domain_info
65  *
66  * Clean out the environment in preparation for joining a domain.
67  * This ensures that we don't have any old information lying around.
68  */
69 void
70 smb_purge_domain_info(void)
71 {
72 	smb_config_wrlock();
73 	(void) smb_config_set(SMB_CI_DOMAIN_NAME, 0);
74 	(void) smb_config_set(SMB_CI_DOMAIN_SID, 0);
75 	(void) smb_config_set(SMB_CI_DOMAIN_MEMB, 0);
76 	smb_config_unlock();
77 }
78 
79 int
80 smb_is_domain_member(void)
81 {
82 	int is_memb;
83 
84 	smb_config_rdlock();
85 	is_memb = smb_config_getyorn(SMB_CI_DOMAIN_MEMB);
86 	smb_config_unlock();
87 
88 	return (is_memb);
89 }
90 
91 uint8_t
92 smb_get_fg_flag(void)
93 {
94 	uint8_t run_fg;
95 
96 	smb_config_rdlock();
97 	run_fg = smb_config_get_fg_flag();
98 	smb_config_unlock();
99 
100 	return (run_fg);
101 }
102 
103 void
104 smb_set_domain_member(int set)
105 {
106 	char *member;
107 
108 	smb_config_wrlock();
109 	member = (set) ? "true" : "false";
110 	(void) smb_config_set(SMB_CI_DOMAIN_MEMB, member);
111 	smb_config_unlock();
112 }
113 
114 /*
115  * smb_getdomaininfo
116  *
117  * Returns a pointer to the cached domain data. The caller can specify
118  * whether or not he is prepared to wait if the cache is not yet valid
119  * and for how long. The specified timeout is in seconds.
120  */
121 smb_ntdomain_t *
122 smb_getdomaininfo(uint32_t timeout)
123 {
124 	timestruc_t to;
125 	int err;
126 
127 	if (timeout != 0) {
128 		(void) mutex_lock(&smbpdc_mtx);
129 		while (smbpdc_cache.ipaddr == 0) {
130 			to.tv_sec = timeout;
131 			to.tv_nsec = 0;
132 			err = cond_reltimedwait(&smbpdc_cv, &smbpdc_mtx, &to);
133 			if (err == ETIME)
134 				break;
135 		}
136 		(void) mutex_unlock(&smbpdc_mtx);
137 	}
138 
139 	if (smbpdc_cache.ipaddr != 0)
140 		return (&smbpdc_cache);
141 	else
142 		return (0);
143 }
144 
145 void
146 smb_logdomaininfo(smb_ntdomain_t *di)
147 {
148 	char ipstr[16];
149 
150 	(void) inet_ntop(AF_INET, (const void *)&di->ipaddr, ipstr,
151 	    sizeof (ipstr));
152 	syslog(LOG_DEBUG, "smbd: %s (%s:%s)", di->domain, di->server, ipstr);
153 }
154 
155 /*
156  * smb_setdomaininfo
157  *
158  * Set the information for the specified domain. If the information is
159  * non-null, the notification event is raised to wakeup any threads
160  * blocking on the cache.
161  */
162 void
163 smb_setdomaininfo(char *domain, char *server, uint32_t ipaddr)
164 {
165 	char *p;
166 
167 	bzero(&smbpdc_cache, sizeof (smb_ntdomain_t));
168 
169 	if (domain && server && ipaddr) {
170 		(void) strlcpy(smbpdc_cache.domain, domain, SMB_PI_MAX_DOMAIN);
171 		(void) strlcpy(smbpdc_cache.server, server, SMB_PI_MAX_DOMAIN);
172 
173 		/*
174 		 * Remove DNS domain name extension
175 		 * to avoid confusing NetBIOS.
176 		 */
177 		if ((p = strchr(smbpdc_cache.domain, '.')) != 0)
178 			*p = '\0';
179 
180 		if ((p = strchr(smbpdc_cache.server, '.')) != 0)
181 			*p = '\0';
182 
183 		(void) mutex_lock(&smbpdc_mtx);
184 		smbpdc_cache.ipaddr = ipaddr;
185 		(void) cond_broadcast(&smbpdc_cv);
186 		(void) mutex_unlock(&smbpdc_mtx);
187 	}
188 }
189 
190 void
191 smb_load_kconfig(smb_kmod_cfg_t *kcfg)
192 {
193 	smb_config_rdlock();
194 	bzero(kcfg, sizeof (smb_kmod_cfg_t));
195 
196 	kcfg->skc_maxbufsize = smb_config_getnum(SMB_CI_MAX_BUFSIZE);
197 	kcfg->skc_maxworkers = smb_config_getnum(SMB_CI_MAX_WORKERS);
198 	kcfg->skc_keepalive = smb_config_getnum(SMB_CI_KEEPALIVE);
199 	if ((kcfg->skc_keepalive != 0) &&
200 	    (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN))
201 		kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN;
202 	kcfg->skc_restrict_anon = smb_config_getyorn(SMB_CI_RESTRICT_ANON);
203 
204 	kcfg->skc_signing_enable = smb_config_getyorn(SMB_CI_SIGNING_ENABLE);
205 	kcfg->skc_signing_required = smb_config_getyorn(SMB_CI_SIGNING_REQD);
206 	kcfg->skc_signing_check = smb_config_getyorn(SMB_CI_SIGNING_CHECK);
207 
208 	kcfg->skc_oplock_enable = smb_config_getyorn(SMB_CI_OPLOCK_ENABLE);
209 	kcfg->skc_oplock_timeout = smb_config_getnum(SMB_CI_OPLOCK_TIMEOUT);
210 
211 	kcfg->skc_flush_required = smb_config_getyorn(SMB_CI_FLUSH_REQUIRED);
212 	kcfg->skc_sync_enable = smb_config_getyorn(SMB_CI_SYNC_ENABLE);
213 	kcfg->skc_dirsymlink_enable =
214 	    !smb_config_getyorn(SMB_CI_DIRSYMLINK_DISABLE);
215 	kcfg->skc_announce_quota = smb_config_getyorn(SMB_CI_ANNONCE_QUOTA);
216 	kcfg->skc_announce_quota = smb_config_getyorn(SMB_CI_ANNONCE_QUOTA);
217 
218 	kcfg->skc_secmode = smb_config_get_secmode();
219 	kcfg->skc_lmlevel = smb_config_getnum(SMB_CI_LM_LEVEL);
220 	kcfg->skc_maxconnections = smb_config_getnum(SMB_CI_MAX_CONNECTIONS);
221 
222 	(void) strlcpy(kcfg->skc_resource_domain,
223 	    smb_config_getstr(SMB_CI_DOMAIN_NAME),
224 	    sizeof (kcfg->skc_resource_domain));
225 
226 	(void) smb_gethostname(kcfg->skc_hostname,
227 	    sizeof (kcfg->skc_hostname), 1);
228 
229 	(void) strlcpy(kcfg->skc_system_comment,
230 	    smb_config_getstr(SMB_CI_SYS_CMNT),
231 	    sizeof (kcfg->skc_system_comment));
232 
233 	smb_config_unlock();
234 }
235 
236 /*
237  * Get the current system NetBIOS name.  The hostname is truncated at
238  * the first `.` or 15 bytes, whichever occurs first, and converted
239  * to uppercase (by smb_gethostname).  Text that appears after the
240  * first '.' is considered to be part of the NetBIOS scope.
241  *
242  * Returns 0 on success, otherwise -1 to indicate an error.
243  */
244 int
245 smb_getnetbiosname(char *buf, size_t buflen)
246 {
247 	if (smb_gethostname(buf, buflen, 1) != 0)
248 		return (-1);
249 
250 	if (buflen >= NETBIOS_NAME_SZ)
251 		buf[NETBIOS_NAME_SZ - 1] = '\0';
252 
253 	return (0);
254 }
255 
256 /*
257  * Get the current system node name.  The returned name is guaranteed
258  * to be null-terminated (gethostname may not null terminate the name).
259  * If the hostname has been fully-qualified for some reason, the domain
260  * part will be removed.  If the caller would like the name in upper
261  * case, it is folded to uppercase.
262  *
263  * If gethostname fails, the returned buffer will contain an empty
264  * string.
265  */
266 int
267 smb_gethostname(char *buf, size_t buflen, int upcase)
268 {
269 	char *p;
270 
271 	if (buf == NULL || buflen == 0)
272 		return (-1);
273 
274 	if (gethostname(buf, buflen) != 0) {
275 		*buf = '\0';
276 		return (-1);
277 	}
278 
279 	buf[buflen - 1] = '\0';
280 
281 	if ((p = strchr(buf, '.')) != NULL)
282 		*p = '\0';
283 
284 	if (upcase)
285 		(void) utf8_strupr(buf);
286 
287 	return (0);
288 }
289 
290 /*
291  * The ADS domain is often the same as the DNS domain but they can be
292  * different - one might be a sub-domain of the other.
293  *
294  * If an ADS domain name has been configured, return it.  Otherwise,
295  * return the DNS domain name.
296  *
297  * If getdomainname fails, the returned buffer will contain an empty
298  * string.
299  */
300 int
301 smb_getdomainname(char *buf, size_t buflen)
302 {
303 	char *domain;
304 
305 	if (buf == NULL || buflen == 0)
306 		return (-1);
307 
308 	smb_config_rdlock();
309 
310 	domain = smb_config_getstr(SMB_CI_ADS_DOMAIN);
311 	if ((domain != NULL) && (*domain != '\0')) {
312 		(void) strlcpy(buf, domain, buflen);
313 		smb_config_unlock();
314 		return (0);
315 	}
316 
317 	smb_config_unlock();
318 
319 	if (getdomainname(buf, buflen) != 0) {
320 		*buf = '\0';
321 		return (-1);
322 	}
323 
324 	return (0);
325 }
326 
327 /*
328  * Obtain the fully-qualified name for this machine.  If the
329  * hostname is fully-qualified, accept it.  Otherwise, try to
330  * find an appropriate domain name to append to the hostname.
331  */
332 int
333 smb_getfqhostname(char *buf, size_t buflen)
334 {
335 	char hostname[MAXHOSTNAMELEN];
336 	char domain[MAXHOSTNAMELEN];
337 
338 	hostname[0] = '\0';
339 	domain[0] = '\0';
340 
341 	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0)
342 		return (-1);
343 
344 	if (smb_getdomainname(domain, MAXHOSTNAMELEN) != 0)
345 		return (-1);
346 
347 	if (hostname[0] == '\0')
348 		return (-1);
349 
350 	if (domain[0] == '\0') {
351 		(void) strlcpy(buf, hostname, buflen);
352 		return (0);
353 	}
354 
355 	(void) snprintf(buf, buflen, "%s.%s", hostname, domain);
356 	return (0);
357 }
358 
359 /*
360  * Temporary fbt for dtrace until user space sdt enabled.
361  */
362 void
363 smb_tracef(const char *fmt, ...)
364 {
365 	va_list ap;
366 	char buf[128];
367 
368 	va_start(ap, fmt);
369 	(void) vsnprintf(buf, 128, fmt, ap);
370 	va_end(ap);
371 
372 	smb_trace(buf);
373 }
374 
375 /*
376  * Temporary fbt for dtrace until user space sdt enabled.
377  */
378 void
379 smb_trace(const char *s)
380 {
381 	syslog(LOG_DEBUG, "%s", s);
382 }
383