xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_info.c (revision 55bf511df53aad0fdb7eb3fa349f0308cc05234c)
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_set_machine_pwd
116  *
117  * Returns 0 upon success.  Otherwise, returns 1.
118  */
119 int
120 smb_set_machine_pwd(char *pwd)
121 {
122 	int rc;
123 
124 	smb_config_wrlock();
125 	rc = smb_config_set(SMB_CI_MACHINE_PASSWD, pwd);
126 	smb_config_unlock();
127 	return (rc);
128 }
129 
130 /*
131  * smb_getdomaininfo
132  *
133  * Returns a pointer to the cached domain data. The caller can specify
134  * whether or not he is prepared to wait if the cache is not yet valid
135  * and for how long. The specified timeout is in seconds.
136  */
137 smb_ntdomain_t *
138 smb_getdomaininfo(uint32_t timeout)
139 {
140 	timestruc_t to;
141 	int err;
142 
143 	if (timeout != 0) {
144 		(void) mutex_lock(&smbpdc_mtx);
145 		while (smbpdc_cache.ipaddr == 0) {
146 			to.tv_sec = timeout;
147 			to.tv_nsec = 0;
148 			err = cond_reltimedwait(&smbpdc_cv, &smbpdc_mtx, &to);
149 			if (err == ETIME)
150 				break;
151 		}
152 		(void) mutex_unlock(&smbpdc_mtx);
153 	}
154 
155 	if (smbpdc_cache.ipaddr != 0)
156 		return (&smbpdc_cache);
157 	else
158 		return (0);
159 }
160 
161 void
162 smb_logdomaininfo(smb_ntdomain_t *di)
163 {
164 	char ipstr[16];
165 
166 	(void) inet_ntop(AF_INET, (const void *)&di->ipaddr, ipstr,
167 	    sizeof (ipstr));
168 	syslog(LOG_DEBUG, "smbd: %s (%s:%s)", di->domain, di->server, ipstr);
169 }
170 
171 /*
172  * smb_setdomaininfo
173  *
174  * Set the information for the specified domain. If the information is
175  * non-null, the notification event is raised to wakeup any threads
176  * blocking on the cache.
177  */
178 void
179 smb_setdomaininfo(char *domain, char *server, uint32_t ipaddr)
180 {
181 	char *p;
182 
183 	bzero(&smbpdc_cache, sizeof (smb_ntdomain_t));
184 
185 	if (domain && server && ipaddr) {
186 		(void) strlcpy(smbpdc_cache.domain, domain, SMB_PI_MAX_DOMAIN);
187 		(void) strlcpy(smbpdc_cache.server, server, SMB_PI_MAX_DOMAIN);
188 
189 		/*
190 		 * Remove DNS domain name extension
191 		 * to avoid confusing NetBIOS.
192 		 */
193 		if ((p = strchr(smbpdc_cache.domain, '.')) != 0)
194 			*p = '\0';
195 
196 		if ((p = strchr(smbpdc_cache.server, '.')) != 0)
197 			*p = '\0';
198 
199 		(void) mutex_lock(&smbpdc_mtx);
200 		smbpdc_cache.ipaddr = ipaddr;
201 		(void) cond_broadcast(&smbpdc_cv);
202 		(void) mutex_unlock(&smbpdc_mtx);
203 	}
204 }
205 
206 void
207 smb_load_kconfig(smb_kmod_cfg_t *kcfg)
208 {
209 	smb_config_rdlock();
210 	bzero(kcfg, sizeof (smb_kmod_cfg_t));
211 
212 	kcfg->skc_maxbufsize = smb_config_getnum(SMB_CI_MAX_BUFSIZE);
213 	kcfg->skc_maxworkers = smb_config_getnum(SMB_CI_MAX_WORKERS);
214 	kcfg->skc_keepalive = smb_config_getnum(SMB_CI_KEEPALIVE);
215 	if ((kcfg->skc_keepalive != 0) &&
216 	    (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN))
217 		kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN;
218 	kcfg->skc_restrict_anon = smb_config_getyorn(SMB_CI_RESTRICT_ANON);
219 
220 	kcfg->skc_signing_enable = smb_config_getyorn(SMB_CI_SIGNING_ENABLE);
221 	kcfg->skc_signing_required = smb_config_getyorn(SMB_CI_SIGNING_REQD);
222 	kcfg->skc_signing_check = smb_config_getyorn(SMB_CI_SIGNING_CHECK);
223 
224 	kcfg->skc_oplock_enable = smb_config_getyorn(SMB_CI_OPLOCK_ENABLE);
225 	kcfg->skc_oplock_timeout = smb_config_getnum(SMB_CI_OPLOCK_TIMEOUT);
226 
227 	kcfg->skc_flush_required = smb_config_getyorn(SMB_CI_FLUSH_REQUIRED);
228 	kcfg->skc_sync_enable = smb_config_getyorn(SMB_CI_SYNC_ENABLE);
229 	kcfg->skc_dirsymlink_enable =
230 	    !smb_config_getyorn(SMB_CI_DIRSYMLINK_DISABLE);
231 	kcfg->skc_announce_quota = smb_config_getyorn(SMB_CI_ANNONCE_QUOTA);
232 	kcfg->skc_announce_quota = smb_config_getyorn(SMB_CI_ANNONCE_QUOTA);
233 
234 	kcfg->skc_secmode = smb_config_get_secmode();
235 	kcfg->skc_lmlevel = smb_config_getnum(SMB_CI_LM_LEVEL);
236 	kcfg->skc_maxconnections = smb_config_getnum(SMB_CI_MAX_CONNECTIONS);
237 
238 	(void) strlcpy(kcfg->skc_resource_domain,
239 	    smb_config_getstr(SMB_CI_DOMAIN_NAME),
240 	    sizeof (kcfg->skc_resource_domain));
241 
242 	(void) smb_gethostname(kcfg->skc_hostname,
243 	    sizeof (kcfg->skc_hostname), 1);
244 
245 	(void) strlcpy(kcfg->skc_system_comment,
246 	    smb_config_getstr(SMB_CI_SYS_CMNT),
247 	    sizeof (kcfg->skc_system_comment));
248 
249 	smb_config_unlock();
250 }
251 
252 /*
253  * Get the current system NetBIOS name.  The hostname is truncated at
254  * the first `.` or 15 bytes, whichever occurs first, and converted
255  * to uppercase (by smb_gethostname).  Text that appears after the
256  * first '.' is considered to be part of the NetBIOS scope.
257  *
258  * Returns 0 on success, otherwise -1 to indicate an error.
259  */
260 int
261 smb_getnetbiosname(char *buf, size_t buflen)
262 {
263 	if (smb_gethostname(buf, buflen, 1) != 0)
264 		return (-1);
265 
266 	if (buflen >= NETBIOS_NAME_SZ)
267 		buf[NETBIOS_NAME_SZ - 1] = '\0';
268 
269 	return (0);
270 }
271 
272 /*
273  * Get the current system node name.  The returned name is guaranteed
274  * to be null-terminated (gethostname may not null terminate the name).
275  * If the hostname has been fully-qualified for some reason, the domain
276  * part will be removed.  If the caller would like the name in upper
277  * case, it is folded to uppercase.
278  *
279  * If gethostname fails, the returned buffer will contain an empty
280  * string.
281  */
282 int
283 smb_gethostname(char *buf, size_t buflen, int upcase)
284 {
285 	char *p;
286 
287 	if (buf == NULL || buflen == 0)
288 		return (-1);
289 
290 	if (gethostname(buf, buflen) != 0) {
291 		*buf = '\0';
292 		return (-1);
293 	}
294 
295 	buf[buflen - 1] = '\0';
296 
297 	if ((p = strchr(buf, '.')) != NULL)
298 		*p = '\0';
299 
300 	if (upcase)
301 		(void) utf8_strupr(buf);
302 
303 	return (0);
304 }
305 
306 /*
307  * The ADS domain is often the same as the DNS domain but they can be
308  * different - one might be a sub-domain of the other.
309  *
310  * If an ADS domain name has been configured, return it.  Otherwise,
311  * return the DNS domain name.
312  *
313  * If getdomainname fails, the returned buffer will contain an empty
314  * string.
315  */
316 int
317 smb_getdomainname(char *buf, size_t buflen)
318 {
319 	char *domain;
320 
321 	if (buf == NULL || buflen == 0)
322 		return (-1);
323 
324 	smb_config_rdlock();
325 
326 	domain = smb_config_getstr(SMB_CI_ADS_DOMAIN);
327 	if ((domain != NULL) && (*domain != '\0')) {
328 		(void) strlcpy(buf, domain, buflen);
329 		smb_config_unlock();
330 		return (0);
331 	}
332 
333 	smb_config_unlock();
334 
335 	if (getdomainname(buf, buflen) != 0) {
336 		*buf = '\0';
337 		return (-1);
338 	}
339 
340 	return (0);
341 }
342 
343 /*
344  * Obtain the fully-qualified name for this machine.  If the
345  * hostname is fully-qualified, accept it.  Otherwise, try to
346  * find an appropriate domain name to append to the hostname.
347  */
348 int
349 smb_getfqhostname(char *buf, size_t buflen)
350 {
351 	char hostname[MAXHOSTNAMELEN];
352 	char domain[MAXHOSTNAMELEN];
353 
354 	hostname[0] = '\0';
355 	domain[0] = '\0';
356 
357 	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0)
358 		return (-1);
359 
360 	if (smb_getdomainname(domain, MAXHOSTNAMELEN) != 0)
361 		return (-1);
362 
363 	if (hostname[0] == '\0')
364 		return (-1);
365 
366 	if (domain[0] == '\0') {
367 		(void) strlcpy(buf, hostname, buflen);
368 		return (0);
369 	}
370 
371 	(void) snprintf(buf, buflen, "%s.%s", hostname, domain);
372 	return (0);
373 }
374 
375 /*
376  * Temporary fbt for dtrace until user space sdt enabled.
377  */
378 void
379 smb_tracef(const char *fmt, ...)
380 {
381 	va_list ap;
382 	char buf[128];
383 
384 	va_start(ap, fmt);
385 	(void) vsnprintf(buf, 128, fmt, ap);
386 	va_end(ap);
387 
388 	smb_trace(buf);
389 }
390 
391 /*
392  * Temporary fbt for dtrace until user space sdt enabled.
393  */
394 void
395 smb_trace(const char *s)
396 {
397 	syslog(LOG_DEBUG, "%s", s);
398 }
399